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 httpapiex.c Source File

httpapiex.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/httpapiex.h"
00011 #include "azure_c_shared_utility/xlogging.h"
00012 #include "azure_c_shared_utility/strings.h"
00013 #include "azure_c_shared_utility/crt_abstractions.h"
00014 #include "azure_c_shared_utility/vector.h"
00015 
00016 typedef struct HTTPAPIEX_SAVED_OPTION_TAG
00017 {
00018     const char* optionName;
00019     const void* value;
00020 }HTTPAPIEX_SAVED_OPTION;
00021 
00022 typedef struct HTTPAPIEX_HANDLE_DATA_TAG
00023 {
00024     STRING_HANDLE hostName;
00025     int k;
00026     HTTP_HANDLE httpHandle;
00027     VECTOR_HANDLE savedOptions;
00028 }HTTPAPIEX_HANDLE_DATA;
00029 
00030 DEFINE_ENUM_STRINGS(HTTPAPIEX_RESULT, HTTPAPIEX_RESULT_VALUES);
00031 
00032 #define LOG_HTTAPIEX_ERROR() LogError("error code = %s", ENUM_TO_STRING(HTTPAPIEX_RESULT, result))
00033 
00034 HTTPAPIEX_HANDLE HTTPAPIEX_Create(const char* hostName)
00035 {
00036     HTTPAPIEX_HANDLE result;
00037     /*Codes_SRS_HTTPAPIEX_02_001: [If parameter hostName is NULL then HTTPAPIEX_Create shall return NULL.]*/
00038     if (hostName == NULL)
00039     {
00040         LogError("invalid (NULL) parameter");
00041         result = NULL;
00042     }
00043     else
00044     {
00045         /*Codes_SRS_HTTPAPIEX_02_005: [If creating the handle fails for any reason, then HTTAPIEX_Create shall return NULL.] */
00046         HTTPAPIEX_HANDLE_DATA* handleData = (HTTPAPIEX_HANDLE_DATA*)malloc(sizeof(HTTPAPIEX_HANDLE_DATA));
00047         if (handleData == NULL)
00048         {
00049             LogError("malloc failed.");
00050             result = NULL;
00051         }
00052         else
00053         {
00054             /*Codes_SRS_HTTPAPIEX_02_002: [Parameter hostName shall be saved.]*/
00055             handleData->hostName = STRING_construct(hostName);
00056             if (handleData->hostName == NULL)
00057             {
00058                 free(handleData);
00059                 LogError("unable to STRING_construct");
00060                 result = NULL;
00061             }
00062             else
00063             {
00064                 /*Codes_SRS_HTTPAPIEX_02_004: [Otherwise, HTTPAPIEX_Create shall return a HTTAPIEX_HANDLE suitable for further calls to the module.] */
00065                 handleData->savedOptions = VECTOR_create(sizeof(HTTPAPIEX_SAVED_OPTION));
00066                 if (handleData->savedOptions == NULL)
00067                 {
00068                     STRING_delete(handleData->hostName);
00069                     free(handleData);
00070                     result = NULL;
00071                 }
00072                 else
00073                 {
00074                     handleData->k = -1;
00075                     handleData->httpHandle = NULL;
00076                     result = handleData;
00077                 }
00078             }
00079         }
00080     }
00081     return result;
00082 }
00083 
00084 /*this function builds the default request http headers if none are specified*/
00085 /*returns 0 if no error*/
00086 /*any other code is error*/
00087 static int buildRequestHttpHeadersHandle(HTTPAPIEX_HANDLE_DATA *handleData, BUFFER_HANDLE requestContent, HTTP_HEADERS_HANDLE originalRequestHttpHeadersHandle, bool* isOriginalRequestHttpHeadersHandle, HTTP_HEADERS_HANDLE* toBeUsedRequestHttpHeadersHandle)
00088 {
00089     int result;
00090 
00091 
00092     if (originalRequestHttpHeadersHandle != NULL)
00093     {
00094         *toBeUsedRequestHttpHeadersHandle = originalRequestHttpHeadersHandle;
00095         *isOriginalRequestHttpHeadersHandle = true;
00096 
00097     }
00098     else
00099     {
00100         /*Codes_SRS_HTTPAPIEX_02_009: [If parameter requestHttpHeadersHandle is NULL then HTTPAPIEX_ExecuteRequest shall allocate a temporary internal instance of HTTPHEADERS, shall add to that instance the following headers
00101         Host:{hostname} - as it was indicated by the call to HTTPAPIEX_Create API call
00102         Content-Length:the size of the requestContent parameter, and use this instance to all the subsequent calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.]
00103         */
00104         *isOriginalRequestHttpHeadersHandle = false;
00105         *toBeUsedRequestHttpHeadersHandle = HTTPHeaders_Alloc();
00106     }
00107 
00108     if (*toBeUsedRequestHttpHeadersHandle == NULL)
00109     {
00110         result = __LINE__;
00111         LogError("unable to HTTPHeaders_Alloc");
00112     }
00113     else
00114     {
00115         char temp[22] = { 0 };
00116         (void)size_tToString(temp, 22, BUFFER_length(requestContent)); /*cannot fail, MAX_uint64 has 19 digits*/
00117         /*Codes_SRS_HTTPAPIEX_02_011: [If parameter requestHttpHeadersHandle is not NULL then HTTPAPIEX_ExecuteRequest shall create or update the following headers of the request:
00118         Host:{hostname}
00119         Content-Length:the size of the requestContent parameter, and shall use the so constructed HTTPHEADERS object to all calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.]
00120         */
00121         /*Codes_SRS_HTTPAPIEX_02_009: [If parameter requestHttpHeadersHandle is NULL then HTTPAPIEX_ExecuteRequest shall allocate a temporary internal instance of HTTPHEADERS, shall add to that instance the following headers
00122         Host:{hostname} - as it was indicated by the call to HTTPAPIEX_Create API call
00123         Content-Length:the size of the requestContent parameter, and use this instance to all the subsequent calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.]
00124         */
00125         if (!(
00126             (HTTPHeaders_ReplaceHeaderNameValuePair(*toBeUsedRequestHttpHeadersHandle, "Host", STRING_c_str(handleData->hostName)) == HTTP_HEADERS_OK) &&
00127             (HTTPHeaders_ReplaceHeaderNameValuePair(*toBeUsedRequestHttpHeadersHandle, "Content-Length", temp) == HTTP_HEADERS_OK)
00128             ))
00129         {
00130             if (! *isOriginalRequestHttpHeadersHandle)
00131             { 
00132                 HTTPHeaders_Free(*toBeUsedRequestHttpHeadersHandle);
00133             }
00134             *toBeUsedRequestHttpHeadersHandle = NULL;
00135             result = __LINE__;
00136         }
00137         else
00138         {
00139             result = 0;
00140         }
00141     }
00142     return result;
00143 }
00144 
00145 static int buildResponseHttpHeadersHandle(HTTP_HEADERS_HANDLE originalResponsetHttpHeadersHandle, bool* isOriginalResponseHttpHeadersHandle, HTTP_HEADERS_HANDLE* toBeUsedResponsetHttpHeadersHandle)
00146 {
00147     int result;
00148     if (originalResponsetHttpHeadersHandle == NULL)
00149     {
00150         if ((*toBeUsedResponsetHttpHeadersHandle = HTTPHeaders_Alloc()) == NULL)
00151         {
00152             result = __LINE__;
00153         }
00154         else
00155         {
00156             *isOriginalResponseHttpHeadersHandle = false;
00157             result = 0;
00158         }
00159     }
00160     else
00161     {
00162         *isOriginalResponseHttpHeadersHandle = true;
00163         *toBeUsedResponsetHttpHeadersHandle = originalResponsetHttpHeadersHandle;
00164         result = 0;
00165     }
00166     return result;
00167 }
00168 
00169 
00170 static int buildBufferIfNotExist(BUFFER_HANDLE originalRequestContent, bool* isOriginalRequestContent, BUFFER_HANDLE* toBeUsedRequestContent)
00171 {
00172     int result;
00173     if (originalRequestContent == NULL)
00174     {
00175         *toBeUsedRequestContent = BUFFER_new();
00176         if (*toBeUsedRequestContent == NULL)
00177         {
00178             result = __LINE__;
00179         }
00180         else
00181         {
00182             *isOriginalRequestContent = false;
00183             result = 0;
00184         }
00185     }
00186     else
00187     {
00188         *isOriginalRequestContent = true;
00189         *toBeUsedRequestContent = originalRequestContent;
00190         result = 0;
00191     }
00192     return result;
00193 }
00194 
00195 static unsigned int dummyStatusCode;
00196 
00197 static int buildAllRequests(HTTPAPIEX_HANDLE_DATA* handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
00198     HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode,
00199     HTTP_HEADERS_HANDLE responseHttpHeadersHandle, BUFFER_HANDLE responseContent,
00200 
00201     const char** toBeUsedRelativePath, 
00202     HTTP_HEADERS_HANDLE *toBeUsedRequestHttpHeadersHandle, bool *isOriginalRequestHttpHeadersHandle,
00203     BUFFER_HANDLE *toBeUsedRequestContent, bool *isOriginalRequestContent,
00204     unsigned int** toBeUsedStatusCode,
00205     HTTP_HEADERS_HANDLE *toBeUsedResponseHttpHeadersHandle, bool *isOriginalResponseHttpHeadersHandle,
00206     BUFFER_HANDLE *toBeUsedResponseContent, bool *isOriginalResponseContent)
00207 {
00208     int result;
00209     (void)requestType;
00210     /*Codes_SRS_HTTPAPIEX_02_013: [If requestContent is NULL then HTTPAPIEX_ExecuteRequest shall behave as if a buffer of zero size would have been used, that is, it shall call HTTPAPI_ExecuteRequest with parameter content = NULL and contentLength = 0.]*/
00211     /*Codes_SRS_HTTPAPIEX_02_014: [If requestContent is not NULL then its content and its size shall be used for parameters content and contentLength of HTTPAPI_ExecuteRequest.] */
00212     if (buildBufferIfNotExist(requestContent, isOriginalRequestContent, toBeUsedRequestContent) != 0)
00213     {
00214         result = __LINE__;
00215         LogError("unable to build the request content");
00216     }
00217     else
00218     {
00219         if (buildRequestHttpHeadersHandle(handle, *toBeUsedRequestContent, requestHttpHeadersHandle, isOriginalRequestHttpHeadersHandle, toBeUsedRequestHttpHeadersHandle) != 0)
00220         {
00221             /*Codes_SRS_HTTPAPIEX_02_010: [If any of the operations in SRS_HTTAPIEX_02_009 fails, then HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_ERROR.] */
00222             result = __LINE__;
00223             if (*isOriginalRequestContent == false) 
00224             {
00225                 BUFFER_delete(*toBeUsedRequestContent);
00226             }
00227             LogError("unable to build the request http headers handle");
00228         }
00229         else
00230         {
00231             /*Codes_SRS_HTTPAPIEX_02_008: [If parameter relativePath is NULL then HTTPAPIEX_INVALID_ARG shall not assume a relative path - that is, it will assume an empty path ("").] */
00232             if (relativePath == NULL)
00233             {
00234                 *toBeUsedRelativePath = "";
00235             }
00236             else
00237             {
00238                 *toBeUsedRelativePath = relativePath;
00239             }
00240 
00241             /*Codes_SRS_HTTPAPIEX_02_015: [If statusCode is NULL then HTTPAPIEX_ExecuteRequest shall not write in statusCode the HTTP status code, and it will use a temporary internal int for parameter statusCode to the calls of HTTPAPI_ExecuteRequest.] */
00242             if (statusCode == NULL)
00243             {
00244                 /*Codes_SRS_HTTPAPIEX_02_016: [If statusCode is not NULL then If statusCode is NULL then HTTPAPIEX_ExecuteRequest shall use it for parameter statusCode to the calls of HTTPAPI_ExecuteRequest.] */
00245                 *toBeUsedStatusCode = &dummyStatusCode;
00246             }
00247             else
00248             {
00249                 *toBeUsedStatusCode = statusCode;
00250             }
00251 
00252             /*Codes_SRS_HTTPAPIEX_02_017: [If responseHeaders handle is NULL then HTTPAPIEX_ExecuteRequest shall create a temporary internal instance of HTTPHEADERS object and use that for responseHeaders parameter of HTTPAPI_ExecuteRequest call.] */
00253             /*Codes_SRS_HTTPAPIEX_02_019: [If responseHeaders is not NULL, then then HTTPAPIEX_ExecuteRequest shall use that object as parameter responseHeaders of HTTPAPI_ExecuteRequest call.] */
00254             if (buildResponseHttpHeadersHandle(responseHttpHeadersHandle, isOriginalResponseHttpHeadersHandle, toBeUsedResponseHttpHeadersHandle) != 0)
00255             {
00256                 /*Codes_SRS_HTTPAPIEX_02_018: [If creating the temporary http headers in SRS_HTTPAPIEX_02_017 fails then HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_ERROR.] */
00257                 result = __LINE__;
00258                 if (*isOriginalRequestContent == false)
00259                 {
00260                     BUFFER_delete(*toBeUsedRequestContent);
00261                 }
00262                 if (*isOriginalRequestHttpHeadersHandle == false)
00263                 {
00264                     HTTPHeaders_Free(*toBeUsedRequestHttpHeadersHandle);
00265                 }
00266                 LogError("unable to build response content");
00267             }
00268             else
00269             {
00270                 /*Codes_SRS_HTTPAPIEX_02_020: [If responseContent is NULL then HTTPAPIEX_ExecuteRequest shall create a temporary internal BUFFER object and use that as parameter responseContent of HTTPAPI_ExecuteRequest call.] */
00271                 /*Codes_SRS_HTTPAPIEX_02_022: [If responseContent is not NULL then HTTPAPIEX_ExecuteRequest use that as parameter responseContent of HTTPAPI_ExecuteRequest call.] */
00272                 if (buildBufferIfNotExist(responseContent, isOriginalResponseContent, toBeUsedResponseContent) != 0)
00273                 {
00274                     /*Codes_SRS_HTTPAPIEX_02_021: [If creating the BUFFER_HANDLE in SRS_HTTPAPIEX_02_020 fails, then HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_ERROR.] */
00275                     result = __LINE__;
00276                     if (*isOriginalRequestContent == false)
00277                     {
00278                         BUFFER_delete(*toBeUsedRequestContent);
00279                     }
00280                     if (*isOriginalRequestHttpHeadersHandle == false)
00281                     {
00282                         HTTPHeaders_Free(*toBeUsedRequestHttpHeadersHandle);
00283                     }
00284                     if (*isOriginalResponseHttpHeadersHandle == false)
00285                     {
00286                         HTTPHeaders_Free(*toBeUsedResponseHttpHeadersHandle);
00287                     }
00288                     LogError("unable to build response content");
00289                 }
00290                 else
00291                 {
00292                     result = 0;
00293                 }
00294             }
00295         }
00296     }
00297     return result;
00298 }
00299 
00300 HTTPAPIEX_RESULT HTTPAPIEX_ExecuteRequest(HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
00301     HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode,
00302     HTTP_HEADERS_HANDLE responseHttpHeadersHandle, BUFFER_HANDLE responseContent)
00303 {
00304     HTTPAPIEX_RESULT result;
00305     /*Codes_SRS_HTTPAPIEX_02_006: [If parameter handle is NULL then HTTPAPIEX_ExecuteRequest shall fail and return HTTPAPIEX_INVALID_ARG.]*/
00306     if (handle == NULL)
00307     {
00308         result = HTTPAPIEX_INVALID_ARG;
00309         LOG_HTTAPIEX_ERROR();
00310     }
00311     else
00312     {
00313         /*Codes_SRS_HTTPAPIEX_02_007: [If parameter requestType does not indicate a valid request, HTTPAPIEX_ExecuteRequest shall fail and return HTTPAPIEX_INVALID_ARG.] */
00314         if (requestType >= COUNT_ARG(HTTPAPI_REQUEST_TYPE_VALUES))
00315         {
00316             result = HTTPAPIEX_INVALID_ARG;
00317             LOG_HTTAPIEX_ERROR();
00318         }
00319         else
00320         {
00321             HTTPAPIEX_HANDLE_DATA *handleData = (HTTPAPIEX_HANDLE_DATA *)handle;
00322 
00323             /*call to buildAll*/
00324             const char* toBeUsedRelativePath;
00325             HTTP_HEADERS_HANDLE toBeUsedRequestHttpHeadersHandle; bool isOriginalRequestHttpHeadersHandle;
00326             BUFFER_HANDLE toBeUsedRequestContent; bool isOriginalRequestContent;
00327             unsigned int* toBeUsedStatusCode;
00328             HTTP_HEADERS_HANDLE toBeUsedResponseHttpHeadersHandle; bool isOriginalResponseHttpHeadersHandle;
00329             BUFFER_HANDLE toBeUsedResponseContent;  bool isOriginalResponseContent;
00330 
00331             if (buildAllRequests(handleData, requestType, relativePath, requestHttpHeadersHandle, requestContent, statusCode, responseHttpHeadersHandle, responseContent,
00332                 &toBeUsedRelativePath,
00333                 &toBeUsedRequestHttpHeadersHandle, &isOriginalRequestHttpHeadersHandle,
00334                 &toBeUsedRequestContent, &isOriginalRequestContent,
00335                 &toBeUsedStatusCode,
00336                 &toBeUsedResponseHttpHeadersHandle, &isOriginalResponseHttpHeadersHandle,
00337                 &toBeUsedResponseContent, &isOriginalResponseContent) != 0)
00338             {
00339                 result = HTTPAPIEX_ERROR;
00340                 LOG_HTTAPIEX_ERROR();
00341             }
00342             else
00343             {
00344 
00345                 /*Codes_SRS_HTTPAPIEX_02_023: [HTTPAPIEX_ExecuteRequest shall try to execute the HTTP call by ensuring the following API call sequence is respected:]*/
00346                 /*Codes_SRS_HTTPAPIEX_02_024: [If any point in the sequence fails, HTTPAPIEX_ExecuteRequest shall attempt to recover by going back to the previous step and retrying that step.]*/
00347                 /*Codes_SRS_HTTPAPIEX_02_025: [If the first step fails, then the sequence fails.]*/
00348                 /*Codes_SRS_HTTPAPIEX_02_026: [A step shall be retried at most once.]*/
00349                 /*Codes_SRS_HTTPAPIEX_02_027: [If a step has been retried then all subsequent steps shall be retried too.]*/
00350                 bool st[3] = { false, false, false }; /*the three levels of possible failure in resilient send: HTTAPI_Init, HTTPAPI_CreateConnection, HTTPAPI_ExecuteRequest*/
00351                 if (handleData->k == -1)
00352                 {
00353                     handleData->k = 0;
00354                 }
00355 
00356                 do
00357                 {
00358                     bool goOn;
00359 
00360                     if (handleData->k > 2)
00361                     {
00362                         /* error */
00363                         break;
00364                     }
00365 
00366                     if (st[handleData->k] == true) /*already been tried*/
00367                     {
00368                         goOn = false;
00369                     }
00370                     else
00371                     {
00372                         switch (handleData->k)
00373                         {
00374                         case 0:
00375                         {
00376                             if (HTTPAPI_Init() != HTTPAPI_OK)
00377                             {
00378                                 goOn = false;
00379                             }
00380                             else
00381                             {
00382                                 goOn = true;
00383                             }
00384                             break;
00385                         }
00386                         case 1:
00387                         {
00388                             if ((handleData->httpHandle = HTTPAPI_CreateConnection(STRING_c_str(handleData->hostName))) == NULL)
00389                             {
00390                                 goOn = false;
00391                             }
00392                             else
00393                             {
00394                                 size_t i;
00395                                 size_t vectorSize = VECTOR_size(handleData->savedOptions);
00396                                 for (i = 0; i < vectorSize; i++)
00397                                 {
00398                                     /*Codes_SRS_HTTPAPIEX_02_035: [HTTPAPIEX_ExecuteRequest shall pass all the saved options (see HTTPAPIEX_SetOption) to the newly create HTTPAPI_HANDLE in step 2 by calling HTTPAPI_SetOption.]*/
00399                                     /*Codes_SRS_HTTPAPIEX_02_036: [If setting the option fails, then the failure shall be ignored.] */
00400                                     HTTPAPIEX_SAVED_OPTION* option = VECTOR_element(handleData->savedOptions, i);
00401                                     if (HTTPAPI_SetOption(handleData->httpHandle, option->optionName, option->value) != HTTPAPI_OK)
00402                                     {
00403                                         LogError("HTTPAPI_SetOption failed when called for option %s", option->optionName);
00404                                     }
00405                                 }
00406                                 goOn = true;
00407                             }
00408                             break;
00409                         }
00410                         case 2:
00411                         {
00412                             size_t length = BUFFER_length(toBeUsedRequestContent);
00413                             unsigned char* buffer = BUFFER_u_char(toBeUsedRequestContent);
00414                             if (HTTPAPI_ExecuteRequest(handleData->httpHandle, requestType, toBeUsedRelativePath, toBeUsedRequestHttpHeadersHandle, buffer, length, toBeUsedStatusCode, toBeUsedResponseHttpHeadersHandle, toBeUsedResponseContent) != HTTPAPI_OK)
00415                             {
00416                                 goOn = false;
00417                             }
00418                             else
00419                             {
00420                                 goOn = true;
00421                             }
00422                             break;
00423                         }
00424                         default:
00425                         {
00426                             /*serious error*/
00427                             goOn = false;
00428                             break;
00429                         }
00430                         }
00431                     }
00432 
00433                     if (goOn)
00434                     {
00435                         if (handleData->k == 2)
00436                         {
00437                             /*Codes_SRS_HTTPAPIEX_02_028: [HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_OK when a call to HTTPAPI_ExecuteRequest has been completed successfully.]*/
00438                             result = HTTPAPIEX_OK;
00439                             goto out;
00440                         }
00441                         else
00442                         {
00443                             st[handleData->k] = true;
00444                             handleData->k++;
00445                             st[handleData->k] = false;
00446                         }
00447                     }
00448                     else
00449                     {
00450                         st[handleData->k] = false;
00451                         handleData->k--;
00452                         switch (handleData->k)
00453                         {
00454                         case 0:
00455                         {
00456                             HTTPAPI_Deinit();
00457                             break;
00458                         }
00459                         case 1:
00460                         {
00461                             HTTPAPI_CloseConnection(handleData->httpHandle);
00462                             handleData->httpHandle = NULL;
00463                             break;
00464                         }
00465                         case 2:
00466                         {
00467                             break;
00468                         }
00469                         default:
00470                         {
00471                             break;
00472                         }
00473                         }
00474                     }
00475                 } while (handleData->k >= 0);
00476                 /*Codes_SRS_HTTPAPIEX_02_029: [Otherwise, HTTAPIEX_ExecuteRequest shall return HTTPAPIEX_RECOVERYFAILED.] */
00477                 result = HTTPAPIEX_RECOVERYFAILED;
00478                 LogError("unable to recover sending to a working state");
00479             out:;
00480                 /*in all cases, unbuild the temporaries*/
00481                 if (isOriginalRequestContent == false)
00482                 {
00483                     BUFFER_delete(toBeUsedRequestContent);
00484                 }
00485                 if (isOriginalRequestHttpHeadersHandle == false)
00486                 {
00487                     HTTPHeaders_Free(toBeUsedRequestHttpHeadersHandle);
00488                 }
00489                 if (isOriginalResponseContent == false)
00490                 {
00491                     BUFFER_delete(toBeUsedResponseContent);
00492                 }
00493                 if (isOriginalResponseHttpHeadersHandle == false)
00494                 {
00495                     HTTPHeaders_Free(toBeUsedResponseHttpHeadersHandle);
00496                 }
00497             }
00498         }
00499     }
00500     return result;
00501 }
00502 
00503 
00504 void HTTPAPIEX_Destroy(HTTPAPIEX_HANDLE handle)
00505 {
00506     if (handle != NULL)
00507     {
00508         /*Codes_SRS_HTTPAPIEX_02_042: [HTTPAPIEX_Destroy shall free all the resources used by HTTAPIEX_HANDLE.]*/
00509         size_t i;
00510         size_t vectorSize;
00511         HTTPAPIEX_HANDLE_DATA* handleData = (HTTPAPIEX_HANDLE_DATA*)handle;
00512         
00513         if (handleData->k == 2)
00514         {
00515             HTTPAPI_CloseConnection(handleData->httpHandle);
00516             HTTPAPI_Deinit();
00517         }
00518         STRING_delete(handleData->hostName);
00519 
00520         vectorSize = VECTOR_size(handleData->savedOptions);
00521         for (i = 0; i < vectorSize; i++)
00522         {
00523             HTTPAPIEX_SAVED_OPTION*savedOption = VECTOR_element(handleData->savedOptions, i);
00524             free((void*)savedOption->optionName);
00525             free((void*)savedOption->value);
00526         }
00527         VECTOR_destroy(handleData->savedOptions);
00528 
00529         free(handle);
00530     }
00531     else
00532     {
00533         /*Codes_SRS_HTTPAPIEX_02_043: [If parameter handle is NULL then HTTPAPIEX_Destroy shall take no action.] */
00534     }
00535 }
00536 
00537 static bool sameName(const void* element, const void* value)
00538 {
00539     return (strcmp(((HTTPAPIEX_SAVED_OPTION*)element)->optionName, value) == 0) ? true : false;
00540 }
00541 
00542 /*return 0 on success, any other value is error*/
00543 /*obs: value is already cloned at the time of calling this function */
00544 static int createOrUpdateOption(HTTPAPIEX_HANDLE_DATA* handleData, const char* optionName, const void* value)
00545 {
00546     /*this function is called after the option value has been saved (cloned)*/
00547     int result;
00548     
00549     /*decide bwtween update or create*/
00550     HTTPAPIEX_SAVED_OPTION* whereIsIt = VECTOR_find_if(handleData->savedOptions, sameName, optionName);
00551     if (whereIsIt != NULL)
00552     {
00553         free((void*)(whereIsIt->value));
00554         whereIsIt->value = value;
00555         result = 0;
00556     }
00557     else
00558     {
00559         HTTPAPIEX_SAVED_OPTION newOption;
00560         if (mallocAndStrcpy_s((char**)&(newOption.optionName), optionName) != 0)
00561         {
00562             free((void*)value);
00563             result = __LINE__;
00564         }
00565         else
00566         {
00567             newOption.value = value;
00568             if (VECTOR_push_back(handleData->savedOptions, &newOption, 1) != 0)
00569             {
00570                 LogError("unable to VECTOR_push_back");
00571                 free((void*)newOption.optionName);
00572                 free((void*)value);
00573                 result = __LINE__;
00574             }
00575             else
00576             {
00577                 result = 0;
00578             }
00579         }
00580     }
00581     
00582     return result;
00583 }
00584 
00585 HTTPAPIEX_RESULT HTTPAPIEX_SetOption(HTTPAPIEX_HANDLE handle, const char* optionName, const void* value)
00586 {
00587     HTTPAPIEX_RESULT result;
00588     /*Codes_SRS_HTTPAPIEX_02_032: [If parameter handle is NULL then HTTPAPIEX_SetOption shall return HTTPAPIEX_INVALID_ARG.] */
00589     /*Codes_SRS_HTTPAPIEX_02_033: [If parameter optionName is NULL then HTTPAPIEX_SetOption shall return HTTPAPIEX_INVALID_ARG.] */
00590     /*Codes_SRS_HTTPAPIEX_02_034: [If parameter value is NULL then HTTPAPIEX_SetOption shall return HTTPAPIEX_INVALID_ARG.] */
00591     if (
00592         (handle == NULL) ||
00593         (optionName == NULL) ||
00594         (value == NULL)
00595         )
00596     {
00597         result = HTTPAPIEX_INVALID_ARG;
00598         LOG_HTTAPIEX_ERROR();
00599     }
00600     else
00601     {
00602         const void* savedOption;
00603         HTTPAPI_RESULT saveOptionResult;
00604 
00605         /*Codes_SRS_HTTPAPIEX_02_037: [HTTPAPIEX_SetOption shall attempt to save the value of the option by calling HTTPAPI_CloneOption passing optionName and value, irrespective of the existence of a HTTPAPI_HANDLE] */
00606         saveOptionResult = HTTPAPI_CloneOption(optionName, value, &savedOption);
00607 
00608         if(saveOptionResult == HTTPAPI_INVALID_ARG)
00609         {
00610             /*Codes_SRS_HTTPAPIEX_02_038: [If HTTPAPI_CloneOption returns HTTPAPI_INVALID_ARG then HTTPAPIEX shall return HTTPAPIEX_INVALID_ARG.] */
00611             result = HTTPAPIEX_INVALID_ARG;
00612             LOG_HTTAPIEX_ERROR();
00613         }
00614         else if (saveOptionResult != HTTPAPI_OK)
00615         {
00616             /*Codes_SRS_HTTPAPIEX_02_040: [For all other return values of HTTPAPI_SetOption, HTTPIAPIEX_SetOption shall return HTTPAPIEX_ERROR.] */
00617             result = HTTPAPIEX_ERROR;
00618             LOG_HTTAPIEX_ERROR();
00619         }
00620         else
00621         {
00622             HTTPAPIEX_HANDLE_DATA* handleData = (HTTPAPIEX_HANDLE_DATA*)handle;
00623             /*Codes_SRS_HTTPAPIEX_02_039: [If HTTPAPI_CloneOption returns HTTPAPI_OK then HTTPAPIEX_SetOption shall create or update the pair optionName/value.]*/
00624             if (createOrUpdateOption(handleData, optionName, savedOption) != 0)
00625             {
00626                 /*Codes_SRS_HTTPAPIEX_02_041: [If creating or updating the pair optionName/value fails then shall return HTTPAPIEX_ERROR.] */
00627                 result = HTTPAPIEX_ERROR;
00628                 LOG_HTTAPIEX_ERROR();
00629                 
00630             }
00631             else
00632             {
00633                 /*Codes_SRS_HTTPAPIEX_02_031: [If HTTPAPI_HANDLE exists then HTTPAPIEX_SetOption shall call HTTPAPI_SetOption passing the same optionName and value and shall return a value conforming to the below table:] */
00634                 if (handleData->httpHandle != NULL)
00635                 {
00636                     HTTPAPI_RESULT HTTPAPI_result = HTTPAPI_SetOption(handleData->httpHandle, optionName, value);
00637                     if (HTTPAPI_result == HTTPAPI_OK)
00638                     {
00639                         result = HTTPAPIEX_OK;
00640                     }
00641                     else if (HTTPAPI_result == HTTPAPI_INVALID_ARG)
00642                     {
00643                         result = HTTPAPIEX_INVALID_ARG;
00644                         LOG_HTTAPIEX_ERROR();
00645                     }
00646                     else
00647                     {
00648                         result = HTTPAPIEX_ERROR;
00649                         LOG_HTTAPIEX_ERROR();
00650                     }
00651                 }
00652                 else
00653                 {
00654                     result = HTTPAPIEX_OK;
00655                 }
00656             }
00657         }
00658     }
00659     return result;
00660 }