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.
Dependencies: EthernetInterface NTPClient iothub_amqp_transport iothub_client mbed-rtos mbed
Fork of iothub_client_sample_amqp 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 #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 }
Generated on Tue Jul 12 2022 12:43:19 by
