Mark Radbourne / Mbed 2 deprecated iothub_client_sample_amqp

Dependencies:   EthernetInterface NTPClient iothub_amqp_transport iothub_client mbed-rtos mbed

Fork of iothub_client_sample_amqp by Azure IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers httpheaders.c Source File

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 }