Azure IoT / azure_c_shared_utility

Dependents:   STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more

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