Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more
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 }
Generated on Wed Jul 13 2022 23:38:02 by
1.7.2
