Skip to content

Commit

Permalink
Merge pull request #4 from AniruddhaKanhere/OptionalBodyParsing
Browse files Browse the repository at this point in the history
Optional body parsing
  • Loading branch information
cryi authored Jan 19, 2024
2 parents ae95ec7 + c6b8308 commit a4489b8
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 1 deletion.
24 changes: 24 additions & 0 deletions source/core_http_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,14 @@ static int httpParserOnHeadersCompleteCallback( llhttp_t * pHttpParser )

LogDebug( ( "Response parsing: Found the end of the headers." ) );

/* If there is HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG opt-in we should stop
* parsing here. */
if( pResponse->respOptionFlags & HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG )
{
shouldContinueParse = LLHTTP_PAUSE_PARSING;
pResponse->pBody = ( const uint8_t * ) pParsingContext->pBufferCur;
}

return shouldContinueParse;
}

Expand Down Expand Up @@ -1102,6 +1110,11 @@ static HTTPStatus_t processLlhttpError( const llhttp_t * pHttpParser )
returnStatus = HTTPSecurityAlertInvalidContentLength;
break;

case HPE_PAUSED:
LogInfo( ( "User intervention: Parsing stopped by user." ) );
returnStatus = HTTPParserPaused;
break;

/* All other error cases cannot be triggered and indicate an error in the
* third-party parsing library if found. */
default:
Expand Down Expand Up @@ -2086,6 +2099,13 @@ HTTPStatus_t HTTPClient_ReceiveAndParseHttpResponse( const TransportInterface_t
( totalReceived < pResponse->bufferLen ) ) ? 1U : 0U;
}

if( ( returnStatus == HTTPParserPaused ) && ( pResponse->respOptionFlags & HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG ) )
{
returnStatus = HTTPSuccess;
/* There may be dangling data if we parse with do not parse body flag. To let libraries built on top of corehttp we expose it through body. */
pResponse->bodyLen = totalReceived - ( size_t )( ( ( uintptr_t ) pResponse->pBody ) - ( ( uintptr_t ) pResponse->pBuffer ) );
}

if( returnStatus == HTTPSuccess )
{
/* If there are errors in receiving from the network or during parsing,
Expand Down Expand Up @@ -2607,6 +2627,10 @@ const char * HTTPClient_strerror( HTTPStatus_t status )
str = "HTTPSecurityAlertInvalidContentLength";
break;

case HTTPParserPaused:
str = "HTTPParserPaused";
break;

case HTTPParserInternalError:
str = "HTTPParserInternalError";
break;
Expand Down
39 changes: 38 additions & 1 deletion source/include/core_http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,26 @@
*/
#define HTTP_RESPONSE_CONNECTION_KEEP_ALIVE_FLAG 0x2U

/**
* @defgroup http_response_option_flags HTTPResponse_t Flags
* @brief Flags for #HTTPResponse_t.respOptionFlags.
* These flags control configurations of response parsing.
*
* Flags should be bitwise-ORed with each other to change the behavior of
* #HTTPClient_ReceiveAndParseHttpResponse and #HTTPClient_Send.
*/

/**
* @ingroup http_response_option_flags
* @brief Set this flag to indicate that the response body should not be parsed.
*
* Setting this will cause parser to stop after parsing the headers. Portion of raw body
* may be available in #HTTPResponse_t.pBody and #HTTPResponse_t.bodyLen.
*
* This flag is valid only for #HTTPResponse_t respOptionFlags parameter.
*/
#define HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG 0x1U

/**
* @ingroup http_constants
* @brief Flag that represents End of File byte in the range specification of
Expand All @@ -165,7 +185,7 @@
* - When the requested range is for the last N bytes of the file.
* In both cases, this value should be used for the "rangeEnd" parameter.
*/
#define HTTP_RANGE_REQUEST_END_OF_FILE -1
#define HTTP_RANGE_REQUEST_END_OF_FILE -1

/**
* @ingroup http_enum_types
Expand Down Expand Up @@ -291,6 +311,16 @@ typedef enum HTTPStatus
*/
HTTPSecurityAlertInvalidContentLength,

/**
* @brief Represents the state of the HTTP parser when it is paused.
*
* This state indicates that the parser has encountered a pause condition and is waiting for further input.
*
* @see HTTPClient_Send
* @see HTTPClient_ReceiveAndParseHttpResponse
*/
HTTPParserPaused,

/**
* @brief An error occurred in the third-party parsing library.
*
Expand Down Expand Up @@ -535,6 +565,13 @@ typedef struct HTTPResponse
*/
uint8_t areHeadersComplete;

/**
* @brief Flags to activate other response configurations.
*
* Please see @ref http_response_option_flags for more information.
*/
uint32_t respOptionFlags;

/**
* @brief Flags of useful headers found in the response.
*
Expand Down
5 changes: 5 additions & 0 deletions source/include/core_http_client_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@
*/
#define LLHTTP_STOP_PARSING HPE_USER

/**
* @brief Return value for llhttp registered callback to signal pause
*/
#define LLHTTP_PAUSE_PARSING HPE_PAUSED

/**
* @brief Return value for llhttp_t.on_headers_complete to signal
* that the HTTP response has no body and to halt further execution.
Expand Down
17 changes: 17 additions & 0 deletions test/cbmc/stubs/HTTPClient_Send_llhttp_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,22 @@ llhttp_errno_t llhttp_execute( llhttp_t * parser,
pParsingContext->lastHeaderValueLen = 0U;
}

/* The body pointer is set by the httpParserOnBodyCallback. But since we are
* removing that from CBMC proof execution, the body has to be set here. */
size_t bodyOffset;

if( pParsingContext->pResponse->bufferLen == 0 )
{
bodyOffset = 0;
}
else
{
/* Body offset can be anything as long as it doesn't exceed the buffer length
* and the length of the current data packet. */
__CPROVER_assume( bodyOffset < pParsingContext->pResponse->bufferLen );
__CPROVER_assume( bodyOffset < len );
}
pParsingContext->pResponse->pBody = pParsingContext->pBufferCur + bodyOffset;

return parser->error;
}

0 comments on commit a4489b8

Please sign in to comment.