Source code
Revision control
Copy as Markdown
Other Tools
#include "gtest/gtest.h"
#include "nsString.h"
#include <cstring>
#include <vector>
#include "nsTArray.h"
struct ParsedHeader {
nsCString name;
nsTArray<uint8_t> value;
};
extern "C" {
using HeaderCallback = void (*)(void* user_data, const uint8_t* name_ptr,
size_t name_len, const uint8_t* value_ptr,
size_t value_len);
bool neqo_glue_test_parse_headers(const nsACString* headers_input,
HeaderCallback callback, void* user_data);
// C callback that collects headers into a vector
void collect_header_callback(void* user_data, const uint8_t* name_ptr,
size_t name_len, const uint8_t* value_ptr,
size_t value_len) {
auto* headers = static_cast<std::vector<ParsedHeader>*>(user_data);
ParsedHeader header;
header.name.Assign(reinterpret_cast<const char*>(name_ptr), name_len);
header.value.AppendElements(value_ptr, value_len);
headers->push_back(std::move(header));
}
}
TEST(TestParseHeaders, ParseHeadersBasic)
{
nsAutoCString headers;
headers.AssignLiteral(
"\r\nContent-Type: text/html\r\nContent-Length: 1234\r\n");
std::vector<ParsedHeader> parsed_headers;
bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback,
&parsed_headers);
EXPECT_TRUE(success);
ASSERT_EQ(parsed_headers.size(), 2U);
EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("content-type"));
EXPECT_EQ(parsed_headers[0].value.Length(), 9U);
EXPECT_EQ(0, memcmp(parsed_headers[0].value.Elements(), "text/html", 9));
EXPECT_TRUE(parsed_headers[1].name.EqualsLiteral("content-length"));
EXPECT_EQ(parsed_headers[1].value.Length(), 4U);
EXPECT_EQ(0, memcmp(parsed_headers[1].value.Elements(), "1234", 4));
}
TEST(TestParseHeaders, ParseHeadersWithWhitespace)
{
nsAutoCString headers;
headers.AssignLiteral(
"\r\n X-Custom : test-value \r\nUser-Agent: Mozilla/5.0 \r\n");
std::vector<ParsedHeader> parsed_headers;
bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback,
&parsed_headers);
EXPECT_TRUE(success);
ASSERT_EQ(parsed_headers.size(), 2U);
EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("x-custom"));
EXPECT_EQ(parsed_headers[0].value.Length(), 10U);
EXPECT_EQ(0, memcmp(parsed_headers[0].value.Elements(), "test-value", 10));
EXPECT_TRUE(parsed_headers[1].name.EqualsLiteral("user-agent"));
EXPECT_EQ(parsed_headers[1].value.Length(), 11U);
EXPECT_EQ(0, memcmp(parsed_headers[1].value.Elements(), "Mozilla/5.0", 11));
}
TEST(TestParseHeaders, ParseHeadersWithColonInValue)
{
nsAutoCString headers;
std::vector<ParsedHeader> parsed_headers;
bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback,
&parsed_headers);
EXPECT_TRUE(success);
ASSERT_EQ(parsed_headers.size(), 1U);
EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("location"));
EXPECT_EQ(parsed_headers[0].value.Length(), 28U);
EXPECT_EQ(0, memcmp(parsed_headers[0].value.Elements(),
}
TEST(TestParseHeaders, ParseHeadersNonUtf8Value)
{
// Create headers with non-UTF8 bytes in the value
nsAutoCString headers;
headers.AssignLiteral("\r\nX-Custom: ");
headers.Append(char(0xFF));
headers.Append(char(0xFE));
headers.Append(char(0xFD));
headers.AppendLiteral("\r\n");
std::vector<ParsedHeader> parsed_headers;
bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback,
&parsed_headers);
EXPECT_TRUE(success);
ASSERT_EQ(parsed_headers.size(), 1U);
EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("x-custom"));
EXPECT_EQ(parsed_headers[0].value.Length(), 3U);
EXPECT_EQ(parsed_headers[0].value[0], 0xFF);
EXPECT_EQ(parsed_headers[0].value[1], 0xFE);
EXPECT_EQ(parsed_headers[0].value[2], 0xFD);
}
TEST(TestParseHeaders, ParseHeadersExcludesColonHeaders)
{
nsAutoCString headers;
headers.AssignLiteral("\r\n:method: GET\r\nContent-Type: text/html\r\n");
std::vector<ParsedHeader> parsed_headers;
bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback,
&parsed_headers);
EXPECT_TRUE(success);
ASSERT_EQ(parsed_headers.size(), 1U); // :method should be excluded
EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("content-type"));
}
TEST(TestParseHeaders, ParseHeadersExcludesForbiddenHeaders)
{
nsAutoCString headers;
headers.AssignLiteral(
"\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nHost: "
"example.com\r\n");
std::vector<ParsedHeader> parsed_headers;
bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback,
&parsed_headers);
EXPECT_TRUE(success);
ASSERT_EQ(parsed_headers.size(),
1U); // Connection and Host should be excluded
EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("content-type"));
}
TEST(TestParseHeaders, ParseHeadersEmptyValue)
{
nsAutoCString headers;
headers.AssignLiteral("\r\nX-Empty:\r\nX-Spaces: \r\n");
std::vector<ParsedHeader> parsed_headers;
bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback,
&parsed_headers);
EXPECT_TRUE(success);
ASSERT_EQ(parsed_headers.size(), 2U);
EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("x-empty"));
EXPECT_EQ(parsed_headers[0].value.Length(), 0U);
EXPECT_TRUE(parsed_headers[1].name.EqualsLiteral("x-spaces"));
EXPECT_EQ(parsed_headers[1].value.Length(), 0U);
}
TEST(TestParseHeaders, ParseHeadersInvalidUtf8Name)
{
// Create headers with non-UTF8 bytes in the name
nsAutoCString headers;
headers.AssignLiteral("\r\n");
headers.Append(char(0xFF));
headers.Append(char(0xFE));
headers.AppendLiteral(": value\r\n");
std::vector<ParsedHeader> parsed_headers;
bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback,
&parsed_headers);
EXPECT_FALSE(success); // Should fail with invalid UTF-8 in name
}