void HTTPAPIEX_Destroy(HTTPAPIEX_HANDLE handle) { if (handle != NULL) { /*Codes_SRS_HTTPAPIEX_02_042: [HTTPAPIEX_Destroy shall free all the resources used by HTTAPIEX_HANDLE.]*/ size_t i; size_t vectorSize; HTTPAPIEX_HANDLE_DATA* handleData = (HTTPAPIEX_HANDLE_DATA*)handle; if (handleData->k == 2) { HTTPAPI_CloseConnection(handleData->httpHandle); HTTPAPI_Deinit(); } STRING_delete(handleData->hostName); vectorSize = VECTOR_size(handleData->savedOptions); for (i = 0; i < vectorSize; i++) { HTTPAPIEX_SAVED_OPTION*savedOption = VECTOR_element(handleData->savedOptions, i); free((void*)savedOption->optionName); free((void*)savedOption->value); } VECTOR_destroy(handleData->savedOptions); free(handle); } else { /*Codes_SRS_HTTPAPIEX_02_043: [If parameter handle is NULL then HTTPAPIEX_Destroy shall take no action.] */ } }
HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName) { HTTP_HANDLE_DATA* result = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA)); if (result == NULL) { /* error */ } else { wchar_t hostNameTemp[1024]; if (MultiByteToWideChar(CP_ACP, 0, hostName, -1, hostNameTemp, sizeof(hostNameTemp) / sizeof(hostNameTemp[0])) == 0) { /* error */ } else { result->SessionHandle = InternetOpen( NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (result->SessionHandle != NULL) { result->ConnectionHandle = InternetConnectW( result->SessionHandle, hostNameTemp, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); } if ((result->SessionHandle == NULL) || (result->ConnectionHandle == NULL)) { HTTPAPI_CloseConnection(result); result = NULL; } } } return (HTTP_HANDLE)result; }
HTTPAPIEX_RESULT HTTPAPIEX_ExecuteRequest(HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode, HTTP_HEADERS_HANDLE responseHttpHeadersHandle, BUFFER_HANDLE responseContent) { HTTPAPIEX_RESULT result; /*Codes_SRS_HTTPAPIEX_02_006: [If parameter handle is NULL then HTTPAPIEX_ExecuteRequest shall fail and return HTTPAPIEX_INVALID_ARG.]*/ if (handle == NULL) { result = HTTPAPIEX_INVALID_ARG; LOG_HTTAPIEX_ERROR(); } else { /*Codes_SRS_HTTPAPIEX_02_007: [If parameter requestType does not indicate a valid request, HTTPAPIEX_ExecuteRequest shall fail and return HTTPAPIEX_INVALID_ARG.] */ if (requestType >= COUNT_ARG(HTTPAPI_REQUEST_TYPE_VALUES)) { result = HTTPAPIEX_INVALID_ARG; LOG_HTTAPIEX_ERROR(); } else { HTTPAPIEX_HANDLE_DATA *handleData = (HTTPAPIEX_HANDLE_DATA *)handle; /*call to buildAll*/ const char* toBeUsedRelativePath; HTTP_HEADERS_HANDLE toBeUsedRequestHttpHeadersHandle; bool isOriginalRequestHttpHeadersHandle; BUFFER_HANDLE toBeUsedRequestContent; bool isOriginalRequestContent; unsigned int* toBeUsedStatusCode; HTTP_HEADERS_HANDLE toBeUsedResponseHttpHeadersHandle; bool isOriginalResponseHttpHeadersHandle; BUFFER_HANDLE toBeUsedResponseContent; bool isOriginalResponseContent; if (buildAllRequests(handleData, requestType, relativePath, requestHttpHeadersHandle, requestContent, statusCode, responseHttpHeadersHandle, responseContent, &toBeUsedRelativePath, &toBeUsedRequestHttpHeadersHandle, &isOriginalRequestHttpHeadersHandle, &toBeUsedRequestContent, &isOriginalRequestContent, &toBeUsedStatusCode, &toBeUsedResponseHttpHeadersHandle, &isOriginalResponseHttpHeadersHandle, &toBeUsedResponseContent, &isOriginalResponseContent) != 0) { result = HTTPAPIEX_ERROR; LOG_HTTAPIEX_ERROR(); } else { /*Codes_SRS_HTTPAPIEX_02_023: [HTTPAPIEX_ExecuteRequest shall try to execute the HTTP call by ensuring the following API call sequence is respected:]*/ /*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.]*/ /*Codes_SRS_HTTPAPIEX_02_025: [If the first step fails, then the sequence fails.]*/ /*Codes_SRS_HTTPAPIEX_02_026: [A step shall be retried at most once.]*/ /*Codes_SRS_HTTPAPIEX_02_027: [If a step has been retried then all subsequent steps shall be retried too.]*/ bool st[3] = { false, false, false }; /*the three levels of possible failure in resilient send: HTTAPI_Init, HTTPAPI_CreateConnection, HTTPAPI_ExecuteRequest*/ if (handleData->k == -1) { handleData->k = 0; } do { bool goOn; if (handleData->k > 2) { /* error */ break; } if (st[handleData->k] == true) /*already been tried*/ { goOn = false; } else { switch (handleData->k) { case 0: { if (HTTPAPI_Init() != HTTPAPI_OK) { goOn = false; } else { goOn = true; } break; } case 1: { if ((handleData->httpHandle = HTTPAPI_CreateConnection(STRING_c_str(handleData->hostName))) == NULL) { goOn = false; } else { size_t i; size_t vectorSize = VECTOR_size(handleData->savedOptions); for (i = 0; i < vectorSize; i++) { /*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.]*/ /*Codes_SRS_HTTPAPIEX_02_036: [If setting the option fails, then the failure shall be ignored.] */ HTTPAPIEX_SAVED_OPTION* option = VECTOR_element(handleData->savedOptions, i); if (HTTPAPI_SetOption(handleData->httpHandle, option->optionName, option->value) != HTTPAPI_OK) { LogError("HTTPAPI_SetOption failed when called for option %s\r\n", option->optionName); } } goOn = true; } break; } case 2: { if (HTTPAPI_ExecuteRequest(handleData->httpHandle, requestType, toBeUsedRelativePath, toBeUsedRequestHttpHeadersHandle, BUFFER_u_char(toBeUsedRequestContent), BUFFER_length(toBeUsedRequestContent), toBeUsedStatusCode, toBeUsedResponseHttpHeadersHandle, toBeUsedResponseContent) != HTTPAPI_OK) { goOn = false; } else { goOn = true; } break; } default: { /*serious error*/ goOn = false; break; } } } if (goOn) { if (handleData->k == 2) { /*Codes_SRS_HTTPAPIEX_02_028: [HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_OK when a call to HTTPAPI_ExecuteRequest has been completed successfully.]*/ result = HTTPAPIEX_OK; goto out; } else { st[handleData->k] = true; handleData->k++; st[handleData->k] = false; } } else { st[handleData->k] = false; handleData->k--; switch (handleData->k) { case 0: { HTTPAPI_Deinit(); break; } case 1: { HTTPAPI_CloseConnection(handleData->httpHandle); handleData->httpHandle = NULL; break; } case 2: { break; } default: { break; } } } } while (handleData->k >= 0); /*Codes_SRS_HTTPAPIEX_02_029: [Otherwise, HTTAPIEX_ExecuteRequest shall return HTTPAPIEX_RECOVERYFAILED.] */ result = HTTPAPIEX_RECOVERYFAILED; LogError("unable to recover sending to a working state\r\n"); out:; /*in all cases, unbuild the temporaries*/ if (isOriginalRequestContent == false) { BUFFER_delete(toBeUsedRequestContent); } if (isOriginalRequestHttpHeadersHandle == false) { HTTPHeaders_Free(toBeUsedRequestHttpHeadersHandle); } if (isOriginalResponseContent == false) { BUFFER_delete(toBeUsedResponseContent); } if (isOriginalResponseHttpHeadersHandle == false) { HTTPHeaders_Free(toBeUsedResponseHttpHeadersHandle); } } } } return result; }