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.
Fork of azure_c_shared_utility by
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 Tue Jul 12 2022 19:14:38 by
1.7.2
