in src/httpapiex.c [364:578]
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 (!validRequestType(requestType))
{
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 (useGlobalInitialization > 0)
{
/*Codes_SRS_HTTPAPIEX_21_048: [If HTTPAPIEX_Init was called, HTTPAPI_ExecuteRequest shall not call HTTPAPI_Init.] */
goOn = true;
}
else 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 = (HTTPAPIEX_SAVED_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", option->optionName);
}
}
goOn = true;
}
break;
}
case 2:
{
size_t length = BUFFER_length(toBeUsedRequestContent);
unsigned char* buffer = BUFFER_u_char(toBeUsedRequestContent);
if (HTTPAPI_ExecuteRequest(handleData->httpHandle, requestType, toBeUsedRelativePath, toBeUsedRequestHttpHeadersHandle, buffer, length, 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:
{
/*Codes_SRS_HTTPAPIEX_21_049: [If HTTPAPIEX_Init was called, HTTPAPI_ExecuteRequest shall not call HTTPAPI_Deinit.] */
if (useGlobalInitialization == 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");
out:;
/*in all cases, unbuild the temporaries*/
if (isOriginalRequestContent == false)
{
BUFFER_delete(toBeUsedRequestContent);
toBeUsedRequestContent = NULL;
}
if (isOriginalRequestHttpHeadersHandle == false)
{
HTTPHeaders_Free(toBeUsedRequestHttpHeadersHandle);
toBeUsedRequestHttpHeadersHandle = NULL;
}
if (isOriginalResponseContent == false)
{
BUFFER_delete(toBeUsedResponseContent);
toBeUsedResponseContent = NULL;
}
if (isOriginalResponseHttpHeadersHandle == false)
{
HTTPHeaders_Free(toBeUsedResponseHttpHeadersHandle);
toBeUsedResponseHttpHeadersHandle = NULL;
}
}
}
}
return result;
}