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