Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of azure_c_shared_utility by
httpheaders.c
00001 // Copyright (c) Microsoft. All rights reserved. 00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 00003 00004 #include <stdlib.h> 00005 #include "azure_c_shared_utility/gballoc.h" 00006 #include "azure_c_shared_utility/map.h" 00007 #include "azure_c_shared_utility/httpheaders.h" 00008 #include <string.h> 00009 #include "azure_c_shared_utility/crt_abstractions.h" 00010 #include "azure_c_shared_utility/xlogging.h" 00011 00012 DEFINE_ENUM_STRINGS(HTTP_HEADERS_RESULT, HTTP_HEADERS_RESULT_VALUES); 00013 00014 typedef struct HTTP_HEADERS_HANDLE_DATA_TAG 00015 { 00016 MAP_HANDLE headers; 00017 } HTTP_HEADERS_HANDLE_DATA; 00018 00019 HTTP_HEADERS_HANDLE HTTPHeaders_Alloc(void) 00020 { 00021 /*Codes_SRS_HTTP_HEADERS_99_002:[ This API shall produce a HTTP_HANDLE that can later be used in subsequent calls to the module.]*/ 00022 HTTP_HEADERS_HANDLE_DATA* result; 00023 result = (HTTP_HEADERS_HANDLE_DATA*)malloc(sizeof(HTTP_HEADERS_HANDLE_DATA)); 00024 00025 if (result == NULL) 00026 { 00027 LogError("malloc failed"); 00028 } 00029 else 00030 { 00031 /*Codes_SRS_HTTP_HEADERS_99_004:[ After a successful init, HTTPHeaders_GetHeaderCount shall report 0 existing headers.]*/ 00032 result->headers = Map_Create(NULL); 00033 if (result->headers == NULL) 00034 { 00035 LogError("Map_Create failed"); 00036 free(result); 00037 result = NULL; 00038 } 00039 else 00040 { 00041 /*all is fine*/ 00042 } 00043 } 00044 00045 /*Codes_SRS_HTTP_HEADERS_99_003:[ The function shall return NULL when the function cannot execute properly]*/ 00046 return (HTTP_HEADERS_HANDLE)result; 00047 } 00048 00049 /*Codes_SRS_HTTP_HEADERS_99_005:[ Calling this API shall de-allocate the data structures allocated by previous API calls to the same handle.]*/ 00050 void HTTPHeaders_Free(HTTP_HEADERS_HANDLE handle) 00051 { 00052 /*Codes_SRS_HTTP_HEADERS_02_001: [If httpHeadersHandle is NULL then HTTPHeaders_Free shall perform no action.] */ 00053 if (handle == NULL) 00054 { 00055 /*do nothing*/ 00056 } 00057 else 00058 { 00059 /*Codes_SRS_HTTP_HEADERS_99_005:[ Calling this API shall de-allocate the data structures allocated by previous API calls to the same handle.]*/ 00060 HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle; 00061 00062 Map_Destroy(handleData->headers); 00063 free(handleData); 00064 } 00065 } 00066 00067 /*Codes_SRS_HTTP_HEADERS_99_012:[ Calling this API shall record a header from name and value parameters.]*/ 00068 static HTTP_HEADERS_RESULT headers_ReplaceHeaderNameValuePair(HTTP_HEADERS_HANDLE handle, const char* name, const char* value, bool replace) 00069 { 00070 HTTP_HEADERS_RESULT result; 00071 /*Codes_SRS_HTTP_HEADERS_99_014:[ The function shall return when the handle is not valid or when name parameter is NULL or when value parameter is NULL.]*/ 00072 if ( 00073 (handle == NULL) || 00074 (name == NULL) || 00075 (value == NULL) 00076 ) 00077 { 00078 result = HTTP_HEADERS_INVALID_ARG; 00079 LogError("invalid arg (NULL) , result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00080 } 00081 else 00082 { 00083 /*Codes_SRS_HTTP_HEADERS_99_036:[ If name contains the characters outside character codes 33 to 126 then the return value shall be HTTP_HEADERS_INVALID_ARG]*/ 00084 /*Codes_SRS_HTTP_HEADERS_99_031:[ If name contains the character ":" then the return value shall be HTTP_HEADERS_INVALID_ARG.]*/ 00085 size_t i; 00086 size_t nameLen = strlen(name); 00087 for (i = 0; i < nameLen; i++) 00088 { 00089 if ((name[i] < 33) || (126 < name[i]) || (name[i] == ':')) 00090 { 00091 break; 00092 } 00093 } 00094 00095 if (i < nameLen) 00096 { 00097 result = HTTP_HEADERS_INVALID_ARG; 00098 LogError("(result = %s)", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00099 } 00100 else 00101 { 00102 HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle; 00103 const char* existingValue = Map_GetValueFromKey(handleData->headers, name); 00104 /*eat up the whitespaces from value, as per RFC 2616, chapter 4.2 "The field value MAY be preceded by any amount of LWS, though a single SP is preferred."*/ 00105 /*Codes_SRS_HTTP_HEADERS_02_002: [The LWS from the beginning of the value shall not be stored.] */ 00106 while ((value[0] == ' ') || (value[0] == '\t') || (value[0] == '\r') || (value[0] == '\n')) 00107 { 00108 value++; 00109 } 00110 00111 if (!replace && (existingValue != NULL)) 00112 { 00113 size_t existingValueLen = strlen(existingValue); 00114 size_t valueLen = strlen(value); 00115 char* newValue = (char*)malloc(sizeof(char) * (existingValueLen + /*COMMA_AND_SPACE_LENGTH*/ 2 + valueLen + /*EOL*/ 1)); 00116 if (newValue == NULL) 00117 { 00118 /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ 00119 result = HTTP_HEADERS_ALLOC_FAILED; 00120 LogError("failed to malloc , result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00121 } 00122 else 00123 { 00124 char* runNewValue; 00125 /*Codes_SRS_HTTP_HEADERS_99_017:[ If the name already exists in the collection of headers, the function shall concatenate the new value after the existing value, separated by a comma and a space as in: old-value+", "+new-value.]*/ 00126 (void)memcpy(newValue, existingValue, existingValueLen); 00127 runNewValue = newValue + existingValueLen; 00128 (*runNewValue++) = ','; 00129 (*runNewValue++) = ' '; 00130 (void)memcpy(runNewValue, value, valueLen + /*EOL*/ 1); 00131 00132 /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/ 00133 if (Map_AddOrUpdate(handleData->headers, name, newValue) != MAP_OK) 00134 { 00135 /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ 00136 result = HTTP_HEADERS_ERROR; 00137 LogError("failed to Map_AddOrUpdate, result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00138 } 00139 else 00140 { 00141 /*Codes_SRS_HTTP_HEADERS_99_013:[ The function shall return HTTP_HEADERS_OK when execution is successful.]*/ 00142 result = HTTP_HEADERS_OK; 00143 } 00144 free(newValue); 00145 } 00146 } 00147 else 00148 { 00149 /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/ 00150 if (Map_AddOrUpdate(handleData->headers, name, value) != MAP_OK) 00151 { 00152 /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ 00153 result = HTTP_HEADERS_ALLOC_FAILED; 00154 LogError("failed to Map_AddOrUpdate, result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00155 } 00156 else 00157 { 00158 result = HTTP_HEADERS_OK; 00159 } 00160 } 00161 } 00162 } 00163 00164 return result; 00165 } 00166 00167 HTTP_HEADERS_RESULT HTTPHeaders_AddHeaderNameValuePair(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name, const char* value) 00168 { 00169 return headers_ReplaceHeaderNameValuePair(httpHeadersHandle, name, value, false); 00170 } 00171 00172 /* Codes_SRS_HTTP_HEADERS_06_001: [This API will perform exactly as HTTPHeaders_AddHeaderNameValuePair except that if the header name already exists the already existing value will be replaced as opposed to concatenated to.] */ 00173 HTTP_HEADERS_RESULT HTTPHeaders_ReplaceHeaderNameValuePair(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name, const char* value) 00174 { 00175 return headers_ReplaceHeaderNameValuePair(httpHeadersHandle, name, value, true); 00176 } 00177 00178 00179 const char* HTTPHeaders_FindHeaderValue(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name) 00180 { 00181 const char* result; 00182 /*Codes_SRS_HTTP_HEADERS_99_022:[ The return value shall be NULL if name parameter is NULL or if httpHeadersHandle is NULL]*/ 00183 if ( 00184 (httpHeadersHandle == NULL) || 00185 (name == NULL) 00186 ) 00187 { 00188 result = NULL; 00189 } 00190 else 00191 { 00192 /*Codes_SRS_HTTP_HEADERS_99_018:[ Calling this API shall retrieve the value for a previously stored name.]*/ 00193 /*Codes_SRS_HTTP_HEADERS_99_020:[ The return value shall be different than NULL when the name matches the name of a previously stored name:value pair.] */ 00194 /*Codes_SRS_HTTP_HEADERS_99_021:[ In this case the return value shall point to a string that shall strcmp equal to the original stored string.]*/ 00195 HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)httpHeadersHandle; 00196 result = Map_GetValueFromKey(handleData->headers, name); 00197 } 00198 return result; 00199 00200 } 00201 00202 HTTP_HEADERS_RESULT HTTPHeaders_GetHeaderCount(HTTP_HEADERS_HANDLE handle, size_t* headerCount) 00203 { 00204 HTTP_HEADERS_RESULT result; 00205 /*Codes_SRS_HTTP_HEADERS_99_024:[ The function shall return HTTP_HEADERS_INVALID_ARG when an invalid handle is passed.]*/ 00206 /*Codes_SRS_HTTP_HEADERS_99_025:[ The function shall return HTTP_HEADERS_INVALID_ARG when headersCount is NULL.]*/ 00207 if ((handle == NULL) || 00208 (headerCount == NULL)) 00209 { 00210 result = HTTP_HEADERS_INVALID_ARG; 00211 LogError("(result = %s)", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00212 } 00213 else 00214 { 00215 HTTP_HEADERS_HANDLE_DATA *handleData = (HTTP_HEADERS_HANDLE_DATA *)handle; 00216 const char*const* keys; 00217 const char*const* values; 00218 /*Codes_SRS_HTTP_HEADERS_99_023:[ Calling this API shall provide the number of stored headers.]*/ 00219 if (Map_GetInternals(handleData->headers, &keys, &values, headerCount) != MAP_OK) 00220 { 00221 /*Codes_SRS_HTTP_HEADERS_99_037:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs.]*/ 00222 result = HTTP_HEADERS_ERROR; 00223 LogError("Map_GetInternals failed, result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00224 } 00225 else 00226 { 00227 /*Codes_SRS_HTTP_HEADERS_99_026:[ The function shall write in *headersCount the number of currently stored headers and shall return HTTP_HEADERS_OK]*/ 00228 result = HTTP_HEADERS_OK; 00229 } 00230 } 00231 00232 return result; 00233 } 00234 00235 /*produces a string in *destination that is equal to name: value*/ 00236 HTTP_HEADERS_RESULT HTTPHeaders_GetHeader(HTTP_HEADERS_HANDLE handle, size_t index, char** destination) 00237 { 00238 HTTP_HEADERS_RESULT result = HTTP_HEADERS_OK; 00239 00240 /*Codes_SRS_HTTP_HEADERS_99_028:[ The function shall return NULL if the handle is invalid.]*/ 00241 /*Codes_SRS_HTTP_HEADERS_99_032:[ The function shall return HTTP_HEADERS_INVALID_ARG if the destination is NULL]*/ 00242 if ( 00243 (handle == NULL) || 00244 (destination == NULL) 00245 ) 00246 { 00247 result = HTTP_HEADERS_INVALID_ARG; 00248 LogError("invalid arg (NULL), result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00249 } 00250 /*Codes_SRS_HTTP_HEADERS_99_029:[ The function shall return HTTP_HEADERS_INVALID_ARG if index is not valid (for example, out of range) for the currently stored headers.]*/ 00251 else 00252 { 00253 HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle; 00254 const char*const* keys; 00255 const char*const* values; 00256 size_t headerCount; 00257 if (Map_GetInternals(handleData->headers, &keys, &values, &headerCount) != MAP_OK) 00258 { 00259 /*Codes_SRS_HTTP_HEADERS_99_034:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs]*/ 00260 result = HTTP_HEADERS_ERROR; 00261 LogError("Map_GetInternals failed, result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00262 } 00263 else 00264 { 00265 /*Codes_SRS_HTTP_HEADERS_99_029:[ The function shall return HTTP_HEADERS_INVALID_ARG if index is not valid (for example, out of range) for the currently stored headers.]*/ 00266 if (index >= headerCount) 00267 { 00268 result = HTTP_HEADERS_INVALID_ARG; 00269 LogError("index out of bounds, result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00270 } 00271 else 00272 { 00273 size_t keyLen = strlen(keys[index]); 00274 size_t valueLen = strlen(values[index]); 00275 *destination = (char*)malloc(sizeof(char) * (keyLen + /*COLON_AND_SPACE_LENGTH*/ 2 + valueLen + /*EOL*/ 1)); 00276 if (*destination == NULL) 00277 { 00278 /*Codes_SRS_HTTP_HEADERS_99_034:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs]*/ 00279 result = HTTP_HEADERS_ERROR; 00280 LogError("unable to malloc, result= %s", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); 00281 } 00282 else 00283 { 00284 /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/ 00285 /*Codes_SRS_HTTP_HEADERS_99_027:[ Calling this API shall produce the string value+": "+pair) for the index header in the *destination parameter.]*/ 00286 char* runDestination = (*destination); 00287 (void)memcpy(runDestination, keys[index], keyLen); 00288 runDestination += keyLen; 00289 (*runDestination++) = ':'; 00290 (*runDestination++) = ' '; 00291 (void)memcpy(runDestination, values[index], valueLen + /*EOL*/ 1); 00292 /*Codes_SRS_HTTP_HEADERS_99_035:[ The function shall return HTTP_HEADERS_OK when the function executed without error.]*/ 00293 result = HTTP_HEADERS_OK; 00294 } 00295 } 00296 } 00297 } 00298 00299 return result; 00300 } 00301 00302 HTTP_HEADERS_HANDLE HTTPHeaders_Clone(HTTP_HEADERS_HANDLE handle) 00303 { 00304 HTTP_HEADERS_HANDLE_DATA* result; 00305 /*Codes_SRS_HTTP_HEADERS_02_003: [If handle is NULL then HTTPHeaders_Clone shall return NULL.] */ 00306 if (handle == NULL) 00307 { 00308 result = NULL; 00309 } 00310 else 00311 { 00312 /*Codes_SRS_HTTP_HEADERS_02_004: [Otherwise HTTPHeaders_Clone shall clone the content of handle to a new handle.] */ 00313 result = (HTTP_HEADERS_HANDLE_DATA*)malloc(sizeof(HTTP_HEADERS_HANDLE_DATA)); 00314 if (result == NULL) 00315 { 00316 /*Codes_SRS_HTTP_HEADERS_02_005: [If cloning fails for any reason, then HTTPHeaders_Clone shall return NULL.] */ 00317 } 00318 else 00319 { 00320 HTTP_HEADERS_HANDLE_DATA* handleData = handle; 00321 result->headers = Map_Clone(handleData->headers); 00322 if (result->headers == NULL) 00323 { 00324 /*Codes_SRS_HTTP_HEADERS_02_005: [If cloning fails for any reason, then HTTPHeaders_Clone shall return NULL.] */ 00325 free(result); 00326 result = NULL; 00327 } 00328 else 00329 { 00330 /*all is fine*/ 00331 } 00332 } 00333 } 00334 return result; 00335 }
Generated on Tue Jul 12 2022 19:14:38 by
