diff --git a/docs/doxygen/include/size_table.md b/docs/doxygen/include/size_table.md index fed45453..2170e484 100644 --- a/docs/doxygen/include/size_table.md +++ b/docs/doxygen/include/size_table.md @@ -10,7 +10,7 @@ core_http_client.c
3.2K
-
2.5K
+
2.6K
api.c (llhttp) @@ -30,6 +30,6 @@ Total estimates
24.0K
-
20.7K
+
20.8K
diff --git a/source/core_http_client.c b/source/core_http_client.c index f5693eac..995143ff 100644 --- a/source/core_http_client.c +++ b/source/core_http_client.c @@ -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 @@ -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. @@ -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, @@ -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 ) ); @@ -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; @@ -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; @@ -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; @@ -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; } @@ -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; @@ -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 ) @@ -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; diff --git a/source/include/core_http_client.h b/source/include/core_http_client.h index 96f2d1bd..8dc2a098 100644 --- a/source/include/core_http_client.h +++ b/source/include/core_http_client.h @@ -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. * @@ -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 @@ -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 diff --git a/test/cbmc/proofs/HTTPClient_Send/Makefile b/test/cbmc/proofs/HTTPClient_Send/Makefile index 931729ad..064330a3 100644 --- a/test/cbmc/proofs/HTTPClient_Send/Makefile +++ b/test/cbmc/proofs/HTTPClient_Send/Makefile @@ -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.