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

Revert "unsigned char" parameter to caseInsensitiveStringCmp() #144

Merged
merged 11 commits into from
Aug 31, 2022
31 changes: 21 additions & 10 deletions source/core_http_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,8 @@ static HTTPStatus_t processLlhttpError( const llhttp_t * pHttpParser );
* 0 if str1 is equal to str2
* 1 if str1 is not equal to str2.
*/
static int8_t caseInsensitiveStringCmp( const unsigned char * str1,
const unsigned char * str2,
static int8_t caseInsensitiveStringCmp( const char * str1,
const char * str2,
size_t n );

/*-----------------------------------------------------------*/
Expand All @@ -567,20 +567,31 @@ static uint32_t getZeroTimestampMs( void )
}

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

static int8_t caseInsensitiveStringCmp( const unsigned char * str1,
const unsigned char * str2,
static int8_t caseInsensitiveStringCmp( const char * str1,
const char * str2,
size_t n )
{
size_t i = 0U;
/* Inclusion of inbetween variables for coverity rule 13.2 compliance */
int32_t firstChar;
int32_t secondChar;
/* Inclusion of inbetween variables for MISRA rule 13.2 compliance */
char firstChar;
char secondChar;
int8_t offset = 'a' - 'A';

for( i = 0U; i < n; i++ )
{
firstChar = toupper( ( int32_t ) ( str1[ i ] ) );
secondChar = toupper( ( ( int32_t ) str2[ i ] ) );
firstChar = str1[ i ];
secondChar = str2[ i ];

/* Subtract 32 to go from uppercase to lowercase ASCII character */
Skptak marked this conversation as resolved.
Show resolved Hide resolved
if( ( firstChar >= 'a' ) && ( firstChar <= 'z' ) )
{
firstChar = firstChar - offset;
}

if( ( secondChar >= 'a' ) && ( secondChar <= 'z' ) )
{
secondChar = secondChar - offset;
}

if( ( firstChar ) != ( secondChar ) )
{
Expand Down
12 changes: 6 additions & 6 deletions source/include/core_http_client_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,12 @@ typedef enum HTTPParsingState_t
*/
typedef struct findHeaderContext
{
const unsigned char * pField; /**< The field that is being searched for. */
size_t fieldLen; /**< The length of pField. */
const char ** pValueLoc; /**< The location of the value found in the buffer. */
size_t * pValueLen; /**< the length of the value found. */
uint8_t fieldFound; /**< Indicates that the header field was found during parsing. */
uint8_t valueFound; /**< Indicates that the header value was found during parsing. */
const char * pField; /**< The field that is being searched for. */
size_t fieldLen; /**< The length of pField. */
const char ** pValueLoc; /**< The location of the value found in the buffer. */
size_t * pValueLen; /**< the length of the value found. */
uint8_t fieldFound; /**< Indicates that the header field was found during parsing. */
uint8_t valueFound; /**< Indicates that the header value was found during parsing. */
} findHeaderContext_t;

/**
Expand Down
89 changes: 83 additions & 6 deletions test/unit-test/core_http_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,26 @@ static const char * pTestResponseEmptyValue = "HTTP/1.1 200 OK\r\n"
"test-header2: test-value2\r\n"
"\r\n";

/* Template HTTP response for testing HTTPClient_ReadHeader API
* with special characters. */
static const char * pTestResponseSpecialCharacter = "HTTP/1.1 200 OK\r\n"
"test-header0: test-value0\r\n"
"test-header1: test-value1\r\n"
"test-header2: test|value2\r\n"
"header{_not_in|buff}: test-value3\r\n"
"\r\n";

#define HEADER_INVALID_PARAMS "Header"
#define HEADER_INVALID_PARAMS_LEN ( sizeof( HEADER_INVALID_PARAMS ) - 1 )
#define HEADER_INVALID_PARAMS "Header"
#define HEADER_INVALID_PARAMS_LEN ( sizeof( HEADER_INVALID_PARAMS ) - 1 )

#define HEADER_IN_BUFFER "test-header1"
#define HEADER_IN_BUFFER_LEN ( sizeof( HEADER_IN_BUFFER ) - 1 )
#define HEADER_IN_BUFFER "teSt-hEader1"
#define HEADER_IN_BUFFER_LEN ( sizeof( HEADER_IN_BUFFER ) - 1 )

#define HEADER_NOT_IN_BUFFER "header-not-in-buffer"
#define HEADER_NOT_IN_BUFFER_LEN ( sizeof( HEADER_NOT_IN_BUFFER ) - 1 )
#define HEADER_NOT_IN_BUFFER "header-not-in-buffer"
#define HEADER_NOT_IN_BUFFER_LEN ( sizeof( HEADER_NOT_IN_BUFFER ) - 1 )

#define HEADER_WITH_SPECIAL_CHARACTERS "header{_not-in|buff}"
#define HEADER_WITH_SPECIAL_CHARACTERS_LEN ( sizeof( HEADER_WITH_SPECIAL_CHARACTERS ) - 1 )

/* File-scoped Global variables */
static HTTPStatus_t retCode = HTTPSuccess;
Expand Down Expand Up @@ -1395,6 +1406,72 @@ void test_Http_ReadHeader_Invalid_Response_Only_Header_Field_Found()
TEST_ASSERT_EQUAL( HTTPInvalidResponse, retCode );
}


/**
* @brief Test happy path with zero-initialized requestHeaders and requestInfo.
* Use characters in the header with ASCII values higher than 'z'.
*/
void test_caseInsensitiveStringCmp()
{
/* Add expectations for llhttp dependencies. */
llhttp_settings_init_ExpectAnyArgs();
llhttp_init_ExpectAnyArgs();

/* Configure the llhttp_execute mock. */
invokeHeaderFieldCallback = 1U;
invokeHeaderValueCallback = 1U;
pFieldLocToReturn = &pTestResponseSpecialCharacter[ headerFieldInRespLoc ];
fieldLenToReturn = headerFieldInRespLen;
pValueLocToReturn = &pTestResponseSpecialCharacter[ headerValInRespLoc ];
valueLenToReturn = headerValInRespLen;
expectedValCbRetVal = LLHTTP_CONTINUE_PARSING;
invokeHeaderCompleteCallback = 1U;
parserErrNo = HPE_OK;
llhttp_execute_ExpectAnyArgsAndReturn( HPE_OK );

/* Call the function under test. */
testResponse.bufferLen = strlen( pTestResponseSpecialCharacter );
retCode = HTTPClient_ReadHeader( &testResponse,
HEADER_NOT_IN_BUFFER,
HEADER_NOT_IN_BUFFER_LEN,
&pValueLoc,
&valueLen );
TEST_ASSERT_EQUAL( HTTPHeaderNotFound, retCode );

/* Repeat the test above but with fieldLenToReturn == HEADER_NOT_IN_BUFFER_LEN.
* Doing this allows us to take the branch where the actual contents
* of the fields are compared rather than just the length. */
setUp();
/* Add expectations for llhttp dependencies. */
llhttp_settings_init_ExpectAnyArgs();
llhttp_init_ExpectAnyArgs();
/* Ensure that the header field does NOT match what we're searching. */
TEST_ASSERT_EQUAL( otherHeaderFieldInRespLen, HEADER_NOT_IN_BUFFER_LEN );
TEST_ASSERT_TRUE( memcmp( &pTestResponseSpecialCharacter[ otherHeaderFieldInRespLoc ],
HEADER_WITH_SPECIAL_CHARACTERS,
HEADER_WITH_SPECIAL_CHARACTERS_LEN ) != 0 );
/* Configure the llhttp_execute mock. */
invokeHeaderFieldCallback = 1U;
invokeHeaderValueCallback = 1U;
pFieldLocToReturn = &pTestResponseSpecialCharacter[ otherHeaderFieldInRespLoc ];
fieldLenToReturn = otherHeaderFieldInRespLen;
pValueLocToReturn = &pTestResponseSpecialCharacter[ headerValInRespLoc ];
valueLenToReturn = headerValInRespLen;
expectedValCbRetVal = LLHTTP_CONTINUE_PARSING;
invokeHeaderCompleteCallback = 1U;
parserErrNo = HPE_OK;
llhttp_execute_ExpectAnyArgsAndReturn( HPE_OK );

/* Call the function under test. */
testResponse.bufferLen = strlen( pTestResponseSpecialCharacter );
retCode = HTTPClient_ReadHeader( &testResponse,
HEADER_WITH_SPECIAL_CHARACTERS,
HEADER_WITH_SPECIAL_CHARACTERS_LEN,
&pValueLoc,
&valueLen );
TEST_ASSERT_EQUAL( HTTPHeaderNotFound, retCode );
}

/**
* @brief Test with an invalid HTTP response that does not contain terminating
* characters ("\r\n\r\n") that represent the end of headers in the response.
Expand Down