Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional body parsing #4

Merged
merged 3 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
Loading