static HTTPStatus_t receiveAndParseHttpResponse()

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;
}