in source/core_http_client.c [1997:2107]
static HTTPStatus_t receiveAndParseHttpResponse( const TransportInterface_t * pTransport,
HTTPResponse_t * pResponse,
const HTTPRequestHeaders_t * pRequestHeaders )
{
HTTPStatus_t returnStatus = HTTPSuccess;
size_t totalReceived = 0U;
int32_t currentReceived = 0;
HTTPParsingContext_t parsingContext = { 0 };
uint8_t shouldRecv = 1U, shouldParse = 1U, timeoutReached = 0U;
uint32_t lastRecvTimeMs = 0U, timeSinceLastRecvMs = 0U;
uint32_t retryTimeoutMs = HTTP_RECV_RETRY_TIMEOUT_MS;
assert( pTransport != NULL );
assert( pTransport->recv != NULL );
assert( pResponse != NULL );
assert( pRequestHeaders != NULL );
/* Initialize the parsing context for parsing the response received from the
* network. */
initializeParsingContextForFirstResponse( &parsingContext, pRequestHeaders );
/* If the timestamp function was undefined by the application, then do not
* retry the transport receive. */
if( pResponse->getTime == getZeroTimestampMs )
{
retryTimeoutMs = 0U;
}
/* Initialize the last send time to allow retries, if 0 bytes are sent on
* the first try. */
lastRecvTimeMs = pResponse->getTime();
while( shouldRecv == 1U )
{
/* Receive the HTTP response data into the pResponse->pBuffer. */
currentReceived = pTransport->recv( pTransport->pNetworkContext,
pResponse->pBuffer + totalReceived,
pResponse->bufferLen - totalReceived );
/* Transport receive errors are negative. */
if( currentReceived < 0 )
{
LogError( ( "Failed to receive HTTP data: Transport recv() "
"returned error: TransportStatus=%ld",
( long int ) currentReceived ) );
returnStatus = HTTPNetworkError;
/* Do not invoke the parser on network errors. */
shouldParse = 0U;
}
else if( currentReceived > 0 )
{
/* Reset the time of the last data received when data is received. */
lastRecvTimeMs = pResponse->getTime();
/* Parsing is done on data as soon as it is received from the network.
* Because we cannot know how large the HTTP response will be in
* total, parsing will tell us if the end of the message is reached.*/
shouldParse = 1U;
totalReceived += currentReceived;
}
else
{
timeSinceLastRecvMs = pResponse->getTime() - lastRecvTimeMs;
/* Do not invoke the response parsing for intermediate zero data. */
shouldParse = 0U;
/* Check if the allowed elapsed time between non-zero data has been
* reached. */
if( timeSinceLastRecvMs >= retryTimeoutMs )
{
/* Invoke the parsing upon this final zero data to indicate
* to the parser that there is no more data available from the
* server. */
shouldParse = 1U;
timeoutReached = 1U;
}
}
if( shouldParse == 1U )
{
/* Data is received into the buffer is immediately parsed. Parsing
* is invoked even with a length of zero. A length of zero indicates
* to the parser that there is no more data from the server (EOF). */
returnStatus = parseHttpResponse( &parsingContext,
pResponse,
currentReceived );
}
/* Reading should continue if there are no errors in the transport receive
* or parsing, the retry on zero data timeout has not been reached, the
* parser indicated the response message is not finished, and there is
* room in the response buffer. */
shouldRecv = ( ( returnStatus == HTTPSuccess ) &&
( timeoutReached == 0U ) &&
( parsingContext.state != HTTP_PARSING_COMPLETE ) &&
( totalReceived < pResponse->bufferLen ) ) ? 1U : 0U;
}
if( returnStatus == HTTPSuccess )
{
/* If there are errors in receiving from the network or during parsing,
* the final status of the response message is derived from the state of
* the parsing and how much data is in the buffer. */
returnStatus = getFinalResponseStatus( parsingContext.state,
totalReceived,
pResponse->bufferLen );
}
return returnStatus;
}