Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility 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 #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 }