Skip to content

Commit

Permalink
Expose Internal Functions for Enhanced Usability (FreeRTOS#167)
Browse files Browse the repository at this point in the history
This exposes the internal functions sendHttpHeaders, sendHttpData, and receiveAndParseHttpResponse. Exposing these functions aims to provide developers with more control over the HTTP communication process, enabling the support for chunked body reads and writes, streaming, and other advanced HTTP functionalities which are essential for building more sophisticated applications atop coreHTTP.
  • Loading branch information
cryi committed Nov 8, 2023
1 parent 15213f4 commit 668db4b
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 80 deletions.
4 changes: 2 additions & 2 deletions docs/doxygen/include/size_table.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<tr>
<td>core_http_client.c</td>
<td><center>3.2K</center></td>
<td><center>2.5K</center></td>
<td><center>2.6K</center></td>
</tr>
<tr>
<td>api.c (llhttp)</td>
Expand All @@ -30,6 +30,6 @@
<tr>
<td><b>Total estimates</b></td>
<td><b><center>24.0K</center></b></td>
<td><b><center>20.7K</center></b></td>
<td><b><center>20.8K</center></b></td>
</tr>
</table>
120 changes: 44 additions & 76 deletions source/core_http_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,43 +43,18 @@
*/
static uint32_t getZeroTimestampMs( void );

/**
* @brief Send HTTP bytes over the transport send interface.
*
* @param[in] pTransport Transport interface.
* @param[in] getTimestampMs Function to retrieve a timestamp in milliseconds.
* @param[in] pData HTTP request data to send.
* @param[in] dataLen HTTP request data length.
*
* @return #HTTPSuccess if successful. If there was a network error or less
* bytes than what were specified were sent, then #HTTPNetworkError is
* returned.
*/
static HTTPStatus_t sendHttpData( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
const uint8_t * pData,
size_t dataLen );

/**
* @brief Send the HTTP headers over the transport send interface.
*
* @param[in] pTransport Transport interface.
* @param[in] getTimestampMs Function to retrieve a timestamp in milliseconds.
* @param[in] pRequestHeaders Request headers to send, it includes the buffer
* and length.
* @param[in] reqBodyLen The length of the request body to be sent. This is
* used to generated a Content-Length header.
* @param[in] sendFlags Application provided flags to #HTTPClient_Send.
*
* @return #HTTPSuccess if successful. If there was a network error or less
* bytes than what were specified were sent, then #HTTPNetworkError is
* returned.
*/
static HTTPStatus_t sendHttpHeaders( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
HTTPRequestHeaders_t * pRequestHeaders,
size_t reqBodyLen,
uint32_t sendFlags );
HTTPStatus_t HTTPClient_SendHttpData( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
const uint8_t * pData,
size_t dataLen );


HTTPStatus_t HTTPClient_SendHttpHeaders( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
HTTPRequestHeaders_t * pRequestHeaders,
size_t reqBodyLen,
uint32_t sendFlags );

/**
* @brief Adds the Content-Length header field and value to the
Expand Down Expand Up @@ -187,20 +162,10 @@ static HTTPStatus_t getFinalResponseStatus( HTTPParsingState_t parsingState,
size_t totalReceived,
size_t responseBufferLen );

/**
* @brief Receive the HTTP response from the network and parse it.
*
* @param[in] pTransport Transport interface.
* @param[in] pResponse Response message to receive data from the network.
* @param[in] pRequestHeaders Request headers for the corresponding HTTP request.
*
* @return Returns #HTTPSuccess if successful. #HTTPNetworkError for a transport
* receive error. Please see #parseHttpResponse and #getFinalResponseStatus for
* other statuses returned.
*/
static HTTPStatus_t receiveAndParseHttpResponse( const TransportInterface_t * pTransport,
HTTPResponse_t * pResponse,
const HTTPRequestHeaders_t * pRequestHeaders );

HTTPStatus_t HTTPClient_ReceiveAndParseHttpResponse( const TransportInterface_t * pTransport,
HTTPResponse_t * pResponse,
const HTTPRequestHeaders_t * pRequestHeaders );

/**
* @brief Send the HTTP request over the network.
Expand All @@ -212,7 +177,7 @@ static HTTPStatus_t receiveAndParseHttpResponse( const TransportInterface_t * pT
* @param[in] reqBodyBufLen Length of the request body buffer.
* @param[in] sendFlags Application provided flags to #HTTPClient_Send.
*
* @return Returns #HTTPSuccess if successful. Please see #sendHttpHeaders and
* @return Returns #HTTPSuccess if successful. Please see #HTTPClient_SendHttpHeaders and
* #sendHttpBody for other statuses returned.
*/
static HTTPStatus_t sendHttpRequest( const TransportInterface_t * pTransport,
Expand Down Expand Up @@ -833,6 +798,9 @@ static int httpParserOnHeadersCompleteCallback( llhttp_t * pHttpParser )
assert( pResponse != NULL );
assert( pParsingContext->pBufferCur != NULL );

/* Flag indicating that the headers have been completely signed - useful for libraries built on top of corehttp. */
pResponse->areHeadersComplete = 1;

/* The current location to parse was updated in previous callbacks and MUST
* always be within the response buffer. */
assert( pParsingContext->pBufferCur >= ( const char * ) ( pResponse->pBuffer ) );
Expand Down Expand Up @@ -1796,10 +1764,10 @@ HTTPStatus_t HTTPClient_AddRangeHeader( HTTPRequestHeaders_t * pRequestHeaders,

/*-----------------------------------------------------------*/

static HTTPStatus_t sendHttpData( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
const uint8_t * pData,
size_t dataLen )
HTTPStatus_t HTTPClient_SendHttpData( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
const uint8_t * pData,
size_t dataLen )
{
HTTPStatus_t returnStatus = HTTPSuccess;
const uint8_t * pIndex = pData;
Expand Down Expand Up @@ -1908,11 +1876,11 @@ static HTTPStatus_t addContentLengthHeader( HTTPRequestHeaders_t * pRequestHeade

/*-----------------------------------------------------------*/

static HTTPStatus_t sendHttpHeaders( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
HTTPRequestHeaders_t * pRequestHeaders,
size_t reqBodyLen,
uint32_t sendFlags )
HTTPStatus_t HTTPClient_SendHttpHeaders( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
HTTPRequestHeaders_t * pRequestHeaders,
size_t reqBodyLen,
uint32_t sendFlags )
{
HTTPStatus_t returnStatus = HTTPSuccess;
uint8_t shouldSendContentLength = 0U;
Expand All @@ -1935,10 +1903,10 @@ static HTTPStatus_t sendHttpHeaders( const TransportInterface_t * pTransport,
{
LogDebug( ( "Sending HTTP request headers: HeaderBytes=%lu",
( unsigned long ) ( pRequestHeaders->headersLen ) ) );
returnStatus = sendHttpData( pTransport,
getTimestampMs,
pRequestHeaders->pBuffer,
pRequestHeaders->headersLen );
returnStatus = HTTPClient_SendHttpData( pTransport,
getTimestampMs,
pRequestHeaders->pBuffer,
pRequestHeaders->headersLen );
}

return returnStatus;
Expand All @@ -1960,7 +1928,7 @@ static HTTPStatus_t sendHttpBody( const TransportInterface_t * pTransport,
/* Send the request body. */
LogDebug( ( "Sending the HTTP request body: BodyBytes=%lu",
( unsigned long ) reqBodyBufLen ) );
returnStatus = sendHttpData( pTransport, getTimestampMs, pRequestBodyBuf, reqBodyBufLen );
returnStatus = HTTPClient_SendHttpData( pTransport, getTimestampMs, pRequestBodyBuf, reqBodyBufLen );

return returnStatus;
}
Expand Down Expand Up @@ -2014,9 +1982,9 @@ static HTTPStatus_t getFinalResponseStatus( HTTPParsingState_t parsingState,

/*-----------------------------------------------------------*/

static HTTPStatus_t receiveAndParseHttpResponse( const TransportInterface_t * pTransport,
HTTPResponse_t * pResponse,
const HTTPRequestHeaders_t * pRequestHeaders )
HTTPStatus_t HTTPClient_ReceiveAndParseHttpResponse( const TransportInterface_t * pTransport,
HTTPResponse_t * pResponse,
const HTTPRequestHeaders_t * pRequestHeaders )
{
HTTPStatus_t returnStatus = HTTPSuccess;
size_t totalReceived = 0U;
Expand Down Expand Up @@ -2149,11 +2117,11 @@ static HTTPStatus_t sendHttpRequest( const TransportInterface_t * pTransport,
assert( getTimestampMs != NULL );

/* Send the headers, which are at one location in memory. */
returnStatus = sendHttpHeaders( pTransport,
getTimestampMs,
pRequestHeaders,
reqBodyBufLen,
sendFlags );
returnStatus = HTTPClient_SendHttpHeaders( pTransport,
getTimestampMs,
pRequestHeaders,
reqBodyBufLen,
sendFlags );

/* Send the body, which is at another location in memory. */
if( returnStatus == HTTPSuccess )
Expand Down Expand Up @@ -2269,9 +2237,9 @@ HTTPStatus_t HTTPClient_Send( const TransportInterface_t * pTransport,

if( returnStatus == HTTPSuccess )
{
returnStatus = receiveAndParseHttpResponse( pTransport,
pResponse,
pRequestHeaders );
returnStatus = HTTPClient_ReceiveAndParseHttpResponse( pTransport,
pResponse,
pRequestHeaders );
}

return returnStatus;
Expand Down
91 changes: 91 additions & 0 deletions source/include/core_http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,13 @@ typedef struct HTTPResponse
*/
size_t headerCount;

/**
* @brief Indicates whether the HTTP response headers have been fully received.
*
* This variable is set to 1 after all headers have been received and processed by #HTTPClient_Send.
*/
uint8_t areHeadersComplete;

/**
* @brief Flags of useful headers found in the response.
*
Expand Down Expand Up @@ -730,6 +737,69 @@ HTTPStatus_t HTTPClient_AddRangeHeader( HTTPRequestHeaders_t * pRequestHeaders,
int32_t rangeEnd );
/* @[declare_httpclient_addrangeheader] */

/**
* @brief Send the request headers in @p pRequestHeaders over the transport.
*
* If #HTTP_SEND_DISABLE_CONTENT_LENGTH_FLAG is not set in parameter @p sendFlags,
* then the Content-Length to be sent to the server is automatically written to
* @p pRequestHeaders. The Content-Length will not be written when there is
* no request body. If there is not enough room in the buffer to write the
* Content-Length then #HTTPInsufficientMemory is returned. Please see
* #HTTP_MAX_CONTENT_LENGTH_HEADER_LENGTH for the maximum Content-Length header
* field and value that could be written to the buffer.
*
* The application should close the connection with the server if any of the
* following errors are returned:
* - #HTTPSecurityAlertExtraneousResponseData
* - #HTTPSecurityAlertInvalidChunkHeader
* - #HTTPSecurityAlertInvalidProtocolVersion
* - #HTTPSecurityAlertInvalidStatusCode
* - #HTTPSecurityAlertInvalidCharacter
* - #HTTPSecurityAlertInvalidContentLength
*
*
* @param[in] pTransport Transport interface, see #TransportInterface_t for
* more information.
* @param[in] getTimestampMs Function to retrieve a timestamp in milliseconds.
* @param[in] pRequestHeaders Request configuration containing the buffer of headers to
* send.
* @param[in] reqBodyLen The length of the request entity in bytes.
* @param[in] sendFlags Flags which modify the behavior of this function. Please see @ref
* http_send_flags for more information.
*
* @return #HTTPSuccess if successful. If there was a network error or less
* bytes than what were specified were sent, then #HTTPNetworkError is
* returned.
*
*/
/* @[declare_httpclient_sendhttpheaders] */
HTTPStatus_t HTTPClient_SendHttpHeaders( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
HTTPRequestHeaders_t * pRequestHeaders,
size_t reqBodyLen,
uint32_t sendFlags );
/* @[declare_httpclient_sendhttpheaders] */

/**
* @brief Send the request body in @p pRequestBodyBuf over the transport.
*
* @param[in] pTransport Transport interface, see #TransportInterface_t for
* more information.
* @param[in] getTimestampMs Function to retrieve a timestamp in milliseconds.
* @param[in] pData HTTP request data to send.
* @param[in] dataLen HTTP request data length.
*
* @return #HTTPSuccess if successful. If there was a network error or less
* bytes than what were specified were sent, then #HTTPNetworkError is
* returned.
*/
/* @[declare_httpclient_sendhttpdata] */
HTTPStatus_t HTTPClient_SendHttpData( const TransportInterface_t * pTransport,
HTTPClient_GetCurrentTimeFunc_t getTimestampMs,
const uint8_t * pData,
size_t dataLen );
/* @[declare_httpclient_sendhttpdata] */

/**
* @brief Send the request headers in #HTTPRequestHeaders_t.pBuffer and request
* body in @p pRequestBodyBuf over the transport. The response is received in
Expand Down Expand Up @@ -832,6 +902,27 @@ HTTPStatus_t HTTPClient_Send( const TransportInterface_t * pTransport,
uint32_t sendFlags );
/* @[declare_httpclient_send] */

/**
* @brief Receive the HTTP response from the network and parse it.
*
* @param[in] pTransport Transport interface, see #TransportInterface_t for more
* information.
* @param[in] pResponse The response message and some notable response parameters will be
* returned here on success.
* @param[in] pRequestHeaders Request configuration containing the buffer of headers to
* send.
*
* @return Returns #HTTPSuccess if successful. #HTTPNetworkError for a transport
* receive error. Please see #parseHttpResponse and #getFinalResponseStatus for
* other statuses returned.
*
*/
/* @[declare_httpclient_receiveandparsehttpresponse] */
HTTPStatus_t HTTPClient_ReceiveAndParseHttpResponse( const TransportInterface_t * pTransport,
HTTPResponse_t * pResponse,
const HTTPRequestHeaders_t * pRequestHeaders );
/* @[declare_httpclient_receiveandparsehttpresponse] */

/**
* @brief Read a header from a buffer containing a complete HTTP response.
* This will return the location of the response header value in the
Expand Down
4 changes: 2 additions & 2 deletions test/cbmc/proofs/HTTPClient_Send/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_http_client_c_httpHeaderStrncp
# than the total possible iterations in the int32_t to ASCII converation.
UNWINDSET += __CPROVER_file_local_core_http_client_c_convertInt32ToAscii.0:11
UNWINDSET += __CPROVER_file_local_core_http_client_c_convertInt32ToAscii.1:11
UNWINDSET += __CPROVER_file_local_core_http_client_c_receiveAndParseHttpResponse.0:10
UNWINDSET += __CPROVER_file_local_core_http_client_c_sendHttpData.0:10
UNWINDSET += HTTPClient_ReceiveAndParseHttpResponse.0:10
UNWINDSET += HTTPClient_SendHttpData.0:10

# strncmp is used to find if there exists "\r\n\r\n" at the end of the header
# buffer. Therefore, we need to unwind strncmp to the length of "\r\n\r\n" + 1.
Expand Down

0 comments on commit 668db4b

Please sign in to comment.