From fd2a415b1f956bd2ab2df766f267b09bab23c39e Mon Sep 17 00:00:00 2001
From: chinglee-iot <61685396+chinglee-iot@users.noreply.github.com>
Date: Tue, 7 May 2024 10:32:11 +0800
Subject: [PATCH 1/4] Update release.yml file (#179)
---
.github/workflows/release.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c1802545..f2c37d23 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.commit_id }}
- name: Configure git identity
@@ -53,7 +53,7 @@ jobs:
- name: Install ZIP tools
run: sudo apt-get install zip unzip
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.commit_id }}
path: coreHTTP
@@ -90,7 +90,7 @@ jobs:
ctest -E system --output-on-failure
cd ..
- name: Create artifact of ZIP
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: coreHTTP-${{ github.event.inputs.version_number }}.zip
path: zip-check/coreHTTP-${{ github.event.inputs.version_number }}.zip
@@ -123,7 +123,7 @@ jobs:
draft: false
prerelease: false
- name: Download ZIP artifact
- uses: actions/download-artifact@v2
+ uses: actions/download-artifact@v4
with:
name: coreHTTP-${{ github.event.inputs.version_number }}.zip
- name: Upload Release Asset
From 57e3570cb82c4085ecf6a13eb4775480afcb8c50 Mon Sep 17 00:00:00 2001
From: chinglee-iot <61685396+chinglee-iot@users.noreply.github.com>
Date: Tue, 7 May 2024 10:49:57 +0800
Subject: [PATCH 2/4] Update doxygen page (#178)
* Update doxygen function list
* Update doxygen version in Readme.md
---
README.md | 2 +-
docs/doxygen/pages.dox | 15 +++++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1dce2004..7749970f 100644
--- a/README.md
+++ b/README.md
@@ -129,7 +129,7 @@ repositories.
### Generating Documentation
-The Doxygen references were created using Doxygen version 1.9.2. To generate the
+The Doxygen references were created using Doxygen version 1.9.6. To generate the
Doxygen pages, please run the following command from the root of this
repository:
diff --git a/docs/doxygen/pages.dox b/docs/doxygen/pages.dox
index 48ac9c45..70e0f5b3 100644
--- a/docs/doxygen/pages.dox
+++ b/docs/doxygen/pages.dox
@@ -270,7 +270,10 @@ defined.
@subpage httpclient_initializerequestheaders_function
@subpage httpclient_addheader_function
@subpage httpclient_addrangeheader_function
+@subpage httpclient_sendhttpheaders_function
+@subpage httpclient_sendhttpdata_function
@subpage httpclient_send_function
+@subpage httpclient_receiveandparsehttpresponse_function
@subpage httpclient_readheader_function
@subpage httpclient_strerror_function
@@ -286,10 +289,22 @@ defined.
@snippet core_http_client.h declare_httpclient_addrangeheader
@copydoc HTTPClient_AddRangeHeader
+@page httpclient_sendhttpheaders_function HTTPClient_SendHttpHeaders
+@snippet core_http_client.h declare_httpclient_sendhttpheaders
+@copydoc HTTPClient_SendHttpHeaders
+
+@page httpclient_sendhttpdata_function HTTPClient_SendHttpData
+@snippet core_http_client.h declare_httpclient_sendhttpdata
+@copydoc HTTPClient_SendHttpData
+
@page httpclient_send_function HTTPClient_Send
@snippet core_http_client.h declare_httpclient_send
@copydoc HTTPClient_Send
+@page httpclient_receiveandparsehttpresponse_function HTTPClient_ReceiveAndParseHttpResponse
+@snippet core_http_client.h declare_httpclient_receiveandparsehttpresponse
+@copydoc HTTPClient_ReceiveAndParseHttpResponse
+
@page httpclient_readheader_function HTTPClient_ReadHeader
@snippet core_http_client.h declare_httpclient_readheader
@copydoc HTTPClient_ReadHeader
From dd62128662bb6b0651985c166934667a5117cf31 Mon Sep 17 00:00:00 2001
From: chinglee-iot <61685396+chinglee-iot@users.noreply.github.com>
Date: Tue, 7 May 2024 11:01:16 +0800
Subject: [PATCH 3/4] Add compiler warning check in the CI workflow (#177)
* Add compiler warning check in the CI workflow and fix compiler warning in the implementation
---------
Co-authored-by: ActoryOu
---
.github/.cSpellWords.txt | 5 +++++
.github/workflows/ci.yml | 5 +++++
source/core_http_client.c | 14 ++++++++------
test/CMakeLists.txt | 15 ++++++++++++---
4 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/.github/.cSpellWords.txt b/.github/.cSpellWords.txt
index 37112fdc..93840b88 100644
--- a/.github/.cSpellWords.txt
+++ b/.github/.cSpellWords.txt
@@ -49,4 +49,9 @@ utest
vect
Vect
VECT
+Wconversion
+Werror
+Weverything
+Wextra
+Wpedantic
Wunused
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1444471d..7efe576a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,10 +16,15 @@ jobs:
- name: Build
run: |
sudo apt-get install -y lcov
+
+ # Build the coverity analysis project as well to check compiler warning.
+ # Coverity analysis project builds coreHTTP source file only. llhttp source
+ # files are not built in this target.
cmake -S test -B build/ \
-G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=Debug \
-DUNITTEST=1 \
+ -DCOV_ANALYSIS=1 \
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -DNDEBUG'
make -C build/ all
diff --git a/source/core_http_client.c b/source/core_http_client.c
index 7a1ddc49..42578475 100644
--- a/source/core_http_client.c
+++ b/source/core_http_client.c
@@ -545,12 +545,12 @@ static int8_t caseInsensitiveStringCmp( const char * str1,
/* Subtract offset to go from lowercase to uppercase ASCII character */
if( ( firstChar >= 'a' ) && ( firstChar <= 'z' ) )
{
- firstChar = firstChar - offset;
+ firstChar = ( char ) ( firstChar - offset );
}
if( ( secondChar >= 'a' ) && ( secondChar <= 'z' ) )
{
- secondChar = secondChar - offset;
+ secondChar = ( char ) ( secondChar - offset );
}
if( ( firstChar ) != ( secondChar ) )
@@ -1249,6 +1249,7 @@ static uint8_t convertInt32ToAscii( int32_t value,
uint8_t numOfDigits = 0U;
uint8_t index = 0U;
uint8_t isNegative = 0U;
+ int32_t bufferIndex;
char temp = '\0';
assert( pBuffer != NULL );
@@ -1263,7 +1264,7 @@ static uint8_t convertInt32ToAscii( int32_t value,
*pBuffer = '-';
/* Convert the value to its absolute representation. */
- absoluteValue = value * -1;
+ absoluteValue = value * ( -1 );
}
/* Write the absolute integer value in reverse ASCII representation. */
@@ -1279,11 +1280,12 @@ static uint8_t convertInt32ToAscii( int32_t value,
for( index = 0U; index < ( numOfDigits / 2U ); index++ )
{
temp = pBuffer[ isNegative + index ];
- pBuffer[ isNegative + index ] = pBuffer[ isNegative + numOfDigits - index - 1U ];
- pBuffer[ isNegative + numOfDigits - index - 1U ] = temp;
+ bufferIndex = ( int32_t ) isNegative + ( int32_t ) numOfDigits - ( int32_t ) index - 1;
+ pBuffer[ isNegative + index ] = pBuffer[ bufferIndex ];
+ pBuffer[ bufferIndex ] = temp;
}
- return( isNegative + numOfDigits );
+ return ( uint8_t ) ( isNegative + numOfDigits );
}
/*-----------------------------------------------------------*/
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 66c4873a..d8e02404 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -44,7 +44,7 @@ if( COV_ANALYSIS )
# Target for Coverity analysis that builds the library.
add_library( coverity_analysis
- ${HTTP_SOURCES} )
+ ${CMAKE_CURRENT_LIST_DIR}/../source/core_http_client.c )
# Build HTTP library target without custom config dependency.
target_compile_definitions( coverity_analysis PUBLIC HTTP_DO_NOT_USE_CUSTOM_CONFIG=1 )
@@ -52,8 +52,17 @@ if( COV_ANALYSIS )
# HTTP public include path.
target_include_directories( coverity_analysis PUBLIC ${HTTP_INCLUDE_PUBLIC_DIRS} )
- # Build HTTP library target without logging
- target_compile_options(coverity_analysis PUBLIC -DNDEBUG )
+ target_compile_options( coverity_analysis PUBLIC
+ # Build HTTP library target without logging
+ -DNDEBUG
+
+ # GCC compiler option
+ -Wall
+ -Wextra
+ -Wpedantic
+ -Wconversion
+ -Werror
+ )
endif()
# ===================== Clone needed third-party libraries ======================
From 51d580bf30e28b7671773478687bbfdb8e69a8cd Mon Sep 17 00:00:00 2001
From: chinglee-iot <61685396+chinglee-iot@users.noreply.github.com>
Date: Tue, 7 May 2024 11:07:16 +0800
Subject: [PATCH 4/4] Add more unit tests for coverage (#175)
* Add unit test to cover httpParserOnStatusCompleteCallback, HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG and HTTP_REQUEST_NO_USER_AGENT_FLAG
* Enforce 100 percent coverage in CI
---
.github/workflows/ci.yml | 2 +
test/unit-test/core_http_send_utest.c | 153 +++++++++++++++++++++++---
test/unit-test/core_http_utest.c | 50 +++++++++
3 files changed, 191 insertions(+), 14 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7efe576a..e486e498 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -41,6 +41,8 @@ jobs:
uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main
with:
coverage-file: ./build/coverage.info
+ branch-coverage-min: 100
+ line-coverage-min: 100
complexity:
runs-on: ubuntu-latest
diff --git a/test/unit-test/core_http_send_utest.c b/test/unit-test/core_http_send_utest.c
index 28197e9c..db83af52 100644
--- a/test/unit-test/core_http_send_utest.c
+++ b/test/unit-test/core_http_send_utest.c
@@ -75,6 +75,7 @@
/* HTTP OK Status-Line. */
#define HTTP_STATUS_LINE_OK "HTTP/1.1 200 OK\r\n"
+#define HTTP_STATUS_LINE_NO_REASON_PHRASE "HTTP/1.1 200\r\n"
#define HTTP_STATUS_CODE_OK 200
/* Various header lines for test response templates. */
@@ -103,11 +104,26 @@
HTTP_TEST_VARY_HEADER_LINE \
HTTP_TEST_P3P_HEADER_LINE \
HTTP_TEST_XSERVER_HEADER_LINE HTTP_HEADER_LINE_SEPARATOR
-#define HTTP_TEST_RESPONSE_HEAD_LENGTH ( sizeof( HTTP_TEST_RESPONSE_HEAD ) - 1U )
-#define HTTP_TEST_RESPONSE_HEAD_HEADER_COUNT 7
-#define HTTP_TEST_RESPONSE_HEAD_CONTENT_LENGTH 43
-#define HTTP_TEST_RESPONSE_HEAD_PARTIAL_HEADER_FIELD_LENGTH ( sizeof( HTTP_STATUS_LINE_OK ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_FIELD ) - 2U )
-#define HTTP_TEST_RESPONSE_HEAD_PARTIAL_HEADER_VALUE_LENGTH ( sizeof( HTTP_STATUS_LINE_OK ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_VALUE ) - 2U )
+#define HTTP_TEST_RESPONSE_HEAD_LENGTH ( sizeof( HTTP_TEST_RESPONSE_HEAD ) - 1U )
+#define HTTP_TEST_RESPONSE_HEAD_HEADER_COUNT 7
+#define HTTP_TEST_RESPONSE_HEAD_CONTENT_LENGTH 43
+#define HTTP_TEST_RESPONSE_HEAD_PARTIAL_HEADER_FIELD_LENGTH ( sizeof( HTTP_STATUS_LINE_OK ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_FIELD ) - 2U )
+#define HTTP_TEST_RESPONSE_HEAD_PARTIAL_HEADER_VALUE_LENGTH ( sizeof( HTTP_STATUS_LINE_OK ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_VALUE ) - 2U )
+
+#define HTTP_TEST_RESPONSE_HEAD_2 \
+ HTTP_STATUS_LINE_NO_REASON_PHRASE \
+ HTTP_TEST_CONTENT_LENGTH_HEADER_LINE \
+ HTTP_TEST_CONNECTION_CLOSE_HEADER_LINE \
+ HTTP_TEST_DATE_HEADER_LINE \
+ HTTP_TEST_ETAG_HEADER_LINE \
+ HTTP_TEST_VARY_HEADER_LINE \
+ HTTP_TEST_P3P_HEADER_LINE \
+ HTTP_TEST_XSERVER_HEADER_LINE HTTP_HEADER_LINE_SEPARATOR
+#define HTTP_TEST_RESPONSE_HEAD_2_LENGTH ( sizeof( HTTP_TEST_RESPONSE_HEAD_2 ) - 1U )
+#define HTTP_TEST_RESPONSE_HEAD_2_HEADER_COUNT 7
+#define HTTP_TEST_RESPONSE_HEAD_2_CONTENT_LENGTH 43
+#define HTTP_TEST_RESPONSE_HEAD_2_PARTIAL_HEADER_FIELD_LENGTH ( sizeof( HTTP_STATUS_LINE_NO_REASON_PHRASE ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_FIELD ) - 2U )
+#define HTTP_TEST_RESPONSE_HEAD_2_PARTIAL_HEADER_VALUE_LENGTH ( sizeof( HTTP_STATUS_LINE_NO_REASON_PHRASE ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_VALUE ) - 2U )
/* Template HTTP PUT response. This has no body. */
#define HTTP_TEST_RESPONSE_PUT \
@@ -235,6 +251,9 @@ static HTTPRequestHeaders_t requestHeaders = { 0 };
/* Header parsing callback shared among the tests. */
static HTTPClient_ResponseHeaderParsingCallback_t headerParsingCallback = { 0 };
+/* Flag to indicate this callback is called. */
+static int statusCompleteCallbackFlag = 0;
+
/* A mocked timer query function that increments on every call. */
static uint32_t getTestTime( void )
{
@@ -432,6 +451,7 @@ static void helper_parse_status_line( const char ** pNext,
const llhttp_settings_t * pSettings )
{
const char * pReasonPhraseStart = NULL;
+ const char * pNextLineStart = NULL;
size_t reasonPhraseStartLen = 0;
/* For purposes of unit testing the response is well formed in the non-error
@@ -440,17 +460,36 @@ static void helper_parse_status_line( const char ** pNext,
* always string literals. strchr() should not be used in application code. */
*pNext = strchr( *pNext, SPACE_CHARACTER ); /* Get the space before the status-code. */
*pNext += SPACE_CHARACTER_LEN;
- *pNext = strchr( *pNext, SPACE_CHARACTER ); /* Get the space before the reason-phrase. */
- *pNext += SPACE_CHARACTER_LEN;
- pReasonPhraseStart = *pNext;
- *pNext = strstr( *pNext, HTTP_HEADER_LINE_SEPARATOR );
- reasonPhraseStartLen = ( size_t ) ( *pNext - pReasonPhraseStart );
+ /* pNext points to the status code now. */
+
+ pReasonPhraseStart = strchr( *pNext, SPACE_CHARACTER );
+ pReasonPhraseStart = &( pReasonPhraseStart[ SPACE_CHARACTER_LEN ] );
+
+ pNextLineStart = strstr( *pNext, HTTP_HEADER_LINE_SEPARATOR );
+ pNextLineStart = &( pNextLineStart[ HTTP_HEADER_LINE_SEPARATOR_LEN ] );
+
pParser->status_code = 200;
- pSettings->on_status( pParser,
- pReasonPhraseStart,
- reasonPhraseStartLen );
- *pNext += HTTP_HEADER_LINE_SEPARATOR_LEN;
+ /* Check if the reason phrase exist in the header and call the corresponding callback.
+ * Reason phrase "OK" exists in the response "HTTP/1.1 200 OK\r\n". The callback
+ * on_status is called.
+ * Reason phrase doesn't exist in the response "HTTP/1.1 200\r\n". The callback
+ * on_status_complete is called. */
+ if( pNextLineStart > pReasonPhraseStart )
+ {
+ reasonPhraseStartLen = ( size_t ) ( pNextLineStart - pReasonPhraseStart );
+ reasonPhraseStartLen = reasonPhraseStartLen - HTTP_HEADER_LINE_SEPARATOR_LEN;
+ pSettings->on_status( pParser,
+ pReasonPhraseStart,
+ reasonPhraseStartLen );
+ *pNext = pNextLineStart;
+ }
+ else
+ {
+ statusCompleteCallbackFlag = 1;
+ pSettings->on_status_complete( pParser );
+ *pNext = pNextLineStart;
+ }
}
/* Mock helper that parses all of the headers starting from pNext. */
@@ -805,6 +844,7 @@ void setUp( void )
response.pBuffer = httpBuffer;
response.bufferLen = sizeof( httpBuffer );
response.pHeaderParsingCallback = &headerParsingCallback;
+ statusCompleteCallbackFlag = 0;
/* Ignore third-party init functions that return void. */
llhttp_init_Ignore();
@@ -846,6 +886,72 @@ void test_HTTPClient_Send_HEAD_request_parse_whole_response( void )
/*-----------------------------------------------------------*/
+/* Test successfully parsing a response to a HEAD request. The full response
+ * message is present in the response buffer on the first network read. */
+void test_HTTPClient_Send_HEAD_request_no_parse_body( void )
+{
+ HTTPStatus_t returnStatus = HTTPSuccess;
+
+ llhttp_execute_Stub( llhttp_execute_whole_response );
+
+ response.respOptionFlags |= HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG;
+
+ returnStatus = HTTPClient_Send( &transportInterface,
+ &requestHeaders,
+ NULL,
+ 0,
+ &response,
+ 0 );
+ TEST_ASSERT_EQUAL( HTTPSuccess, returnStatus );
+ TEST_ASSERT_EQUAL( NULL, response.pBody );
+ TEST_ASSERT_EQUAL( 0U, response.bodyLen );
+ TEST_ASSERT_EQUAL( response.pBuffer + ( sizeof( HTTP_STATUS_LINE_OK ) - 1U ), response.pHeaders );
+ TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_LENGTH - ( sizeof( HTTP_STATUS_LINE_OK ) - 1U ) - HTTP_HEADER_END_INDICATOR_LEN,
+ response.headersLen );
+ TEST_ASSERT_EQUAL( HTTP_STATUS_CODE_OK, response.statusCode );
+ TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_CONTENT_LENGTH, response.contentLength );
+ TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_HEADER_COUNT, response.headerCount );
+ TEST_ASSERT_BITS_HIGH( HTTP_RESPONSE_CONNECTION_CLOSE_FLAG, response.respFlags );
+ TEST_ASSERT_BITS_LOW( HTTP_RESPONSE_CONNECTION_KEEP_ALIVE_FLAG, response.respFlags );
+}
+
+/*-----------------------------------------------------------*/
+
+/* Test successfully parsing a response to a HEAD request. The full response
+ * message is present in the response buffer on the first network read. The response
+ * contains a status code but without a reason string. The on_status_complete is called
+ * in this case. */
+void test_HTTPClient_Send_HEAD_request_parse_whole_response_no_reason_string( void )
+{
+ HTTPStatus_t returnStatus = HTTPSuccess;
+
+ pNetworkData = ( uint8_t * ) HTTP_TEST_RESPONSE_HEAD_2;
+ networkDataLen = HTTP_TEST_RESPONSE_HEAD_2_LENGTH;
+
+ llhttp_execute_Stub( llhttp_execute_whole_response );
+
+ returnStatus = HTTPClient_Send( &transportInterface,
+ &requestHeaders,
+ NULL,
+ 0,
+ &response,
+ 0 );
+ TEST_ASSERT_EQUAL( HTTPSuccess, returnStatus );
+ TEST_ASSERT_EQUAL( NULL, response.pBody );
+ TEST_ASSERT_EQUAL( 0U, response.bodyLen );
+ TEST_ASSERT_EQUAL( response.pBuffer + ( sizeof( HTTP_STATUS_LINE_NO_REASON_PHRASE ) - 1U ), response.pHeaders );
+ TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_2_LENGTH - ( sizeof( HTTP_STATUS_LINE_NO_REASON_PHRASE ) - 1U ) - HTTP_HEADER_END_INDICATOR_LEN,
+ response.headersLen );
+ TEST_ASSERT_EQUAL( HTTP_STATUS_CODE_OK, response.statusCode );
+ TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_2_CONTENT_LENGTH, response.contentLength );
+ TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_2_HEADER_COUNT, response.headerCount );
+ TEST_ASSERT_BITS_HIGH( HTTP_RESPONSE_CONNECTION_CLOSE_FLAG, response.respFlags );
+ TEST_ASSERT_BITS_LOW( HTTP_RESPONSE_CONNECTION_KEEP_ALIVE_FLAG, response.respFlags );
+ TEST_ASSERT_EQUAL( 1, statusCompleteCallbackFlag );
+}
+
+/*-----------------------------------------------------------*/
+
/* Test successfully parsing a response to a PUT request. The full response
* message is present in the response buffer on the first network read. */
void test_HTTPClient_Send_PUT_request_parse_whole_response( void )
@@ -1757,6 +1863,25 @@ void test_HTTPClient_Send_parsing_errors( void )
0 );
TEST_ASSERT_EQUAL( HTTPSecurityAlertInvalidContentLength, returnStatus );
+ httpParsingErrno = HPE_PAUSED;
+ returnStatus = HTTPClient_Send( &transportInterface,
+ &requestHeaders,
+ NULL,
+ 0,
+ &response,
+ 0 );
+ TEST_ASSERT_EQUAL( HTTPParserPaused, returnStatus );
+
+ httpParsingErrno = HPE_PAUSED;
+ response.respOptionFlags |= HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG;
+ returnStatus = HTTPClient_Send( &transportInterface,
+ &requestHeaders,
+ NULL,
+ 0,
+ &response,
+ 0 );
+ TEST_ASSERT_EQUAL( HTTPNoResponse, returnStatus );
+
/* Use -1 to indicate an unknown error. */
httpParsingErrno = -1;
returnStatus = HTTPClient_Send( &transportInterface,
diff --git a/test/unit-test/core_http_utest.c b/test/unit-test/core_http_utest.c
index ec22b1c2..e6b4fd14 100644
--- a/test/unit-test/core_http_utest.c
+++ b/test/unit-test/core_http_utest.c
@@ -72,6 +72,10 @@ typedef struct _headers
"%s: %s\r\n" \
"%s: %s\r\n\r\n"
+#define HTTP_TEST_HEADER_NO_USER_AGENT_FORMAT \
+ "%s %s %s\r\n" \
+ "%s: %s\r\n\r\n"
+
#define HTTP_TEST_EXTRA_HEADER_FORMAT \
"%s %s %s\r\n" \
"%s: %s\r\n" \
@@ -94,6 +98,19 @@ typedef struct _headers
HTTP_TEST_HOST_VALUE_LEN + HTTP_HEADER_LINE_SEPARATOR_LEN + \
HTTP_HEADER_LINE_SEPARATOR_LEN )
+/* Length of the following template HTTP header.
+ * \r\n
+ * : \r\n
+ * \r\n
+ * This is used to initialize the expectedHeader string. */
+#define HTTP_TEST_PREFIX_HEADER_NO_USER_AGENT_LEN \
+ ( HTTP_METHOD_GET_LEN + SPACE_CHARACTER_LEN + \
+ HTTP_TEST_REQUEST_PATH_LEN + SPACE_CHARACTER_LEN + \
+ HTTP_PROTOCOL_VERSION_LEN + HTTP_HEADER_LINE_SEPARATOR_LEN + \
+ HTTP_HOST_FIELD_LEN + HTTP_HEADER_FIELD_SEPARATOR_LEN + \
+ HTTP_TEST_HOST_VALUE_LEN + HTTP_HEADER_LINE_SEPARATOR_LEN + \
+ HTTP_HEADER_LINE_SEPARATOR_LEN )
+
/* Add 1 because snprintf(...) writes a null byte at the end. */
#define HTTP_TEST_INITIALIZED_HEADER_BUFFER_LEN \
( HTTP_TEST_PREFIX_HEADER_LEN + 1 )
@@ -472,6 +489,39 @@ void test_Http_InitializeRequestHeaders_Happy_Path()
expectedHeaders.dataLen );
}
+/**
+ * @brief Test happy path with HTTP_REQUEST_NO_USER_AGENT_FLAG.
+ */
+void test_Http_InitializeRequestHeaders_no_user_agent_flag()
+{
+ HTTPStatus_t httpStatus = HTTPSuccess;
+ HTTPRequestHeaders_t requestHeaders = { 0 };
+ HTTPRequestInfo_t requestInfo = { 0 };
+ int numBytes = 0;
+
+ setupRequestInfo( &requestInfo );
+ requestInfo.reqFlags |= HTTP_REQUEST_NO_USER_AGENT_FLAG;
+
+ expectedHeaders.dataLen = HTTP_TEST_PREFIX_HEADER_NO_USER_AGENT_LEN;
+ setupBuffer( &requestHeaders );
+
+ /* Happy Path testing. */
+ numBytes = snprintf( ( char * ) expectedHeaders.buffer, sizeof( expectedHeaders.buffer ),
+ HTTP_TEST_HEADER_NO_USER_AGENT_FORMAT,
+ HTTP_METHOD_GET, HTTP_TEST_REQUEST_PATH,
+ HTTP_PROTOCOL_VERSION,
+ HTTP_HOST_FIELD, HTTP_TEST_HOST_VALUE );
+ /* Make sure that the entire pre-existing data was printed to the buffer. */
+ TEST_ASSERT_GREATER_THAN( 0, numBytes );
+ TEST_ASSERT_LESS_THAN( sizeof( expectedHeaders.buffer ), ( size_t ) numBytes );
+
+ httpStatus = HTTPClient_InitializeRequestHeaders( &requestHeaders, &requestInfo );
+ TEST_ASSERT_EQUAL( HTTPSuccess, httpStatus );
+ TEST_ASSERT_EQUAL( expectedHeaders.dataLen, requestHeaders.headersLen );
+ TEST_ASSERT_EQUAL_MEMORY( expectedHeaders.buffer, requestHeaders.pBuffer,
+ expectedHeaders.dataLen );
+}
+
/**
* @brief Test NULL parameters, following order of else-if blocks in the HTTP library.
*/