TestParseHeaders.cpp (6405B)
1 #include "gtest/gtest.h" 2 #include "nsString.h" 3 #include <cstring> 4 #include <vector> 5 #include "nsTArray.h" 6 7 struct ParsedHeader { 8 nsCString name; 9 nsTArray<uint8_t> value; 10 }; 11 12 extern "C" { 13 using HeaderCallback = void (*)(void* user_data, const uint8_t* name_ptr, 14 size_t name_len, const uint8_t* value_ptr, 15 size_t value_len); 16 17 bool neqo_glue_test_parse_headers(const nsACString* headers_input, 18 HeaderCallback callback, void* user_data); 19 20 // C callback that collects headers into a vector 21 void collect_header_callback(void* user_data, const uint8_t* name_ptr, 22 size_t name_len, const uint8_t* value_ptr, 23 size_t value_len) { 24 auto* headers = static_cast<std::vector<ParsedHeader>*>(user_data); 25 ParsedHeader header; 26 header.name.Assign(reinterpret_cast<const char*>(name_ptr), name_len); 27 header.value.AppendElements(value_ptr, value_len); 28 headers->push_back(std::move(header)); 29 } 30 } 31 32 TEST(TestParseHeaders, ParseHeadersBasic) 33 { 34 nsAutoCString headers; 35 headers.AssignLiteral( 36 "\r\nContent-Type: text/html\r\nContent-Length: 1234\r\n"); 37 38 std::vector<ParsedHeader> parsed_headers; 39 bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback, 40 &parsed_headers); 41 42 EXPECT_TRUE(success); 43 ASSERT_EQ(parsed_headers.size(), 2U); 44 45 EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("content-type")); 46 EXPECT_EQ(parsed_headers[0].value.Length(), 9U); 47 EXPECT_EQ(0, memcmp(parsed_headers[0].value.Elements(), "text/html", 9)); 48 49 EXPECT_TRUE(parsed_headers[1].name.EqualsLiteral("content-length")); 50 EXPECT_EQ(parsed_headers[1].value.Length(), 4U); 51 EXPECT_EQ(0, memcmp(parsed_headers[1].value.Elements(), "1234", 4)); 52 } 53 54 TEST(TestParseHeaders, ParseHeadersWithWhitespace) 55 { 56 nsAutoCString headers; 57 headers.AssignLiteral( 58 "\r\n X-Custom : test-value \r\nUser-Agent: Mozilla/5.0 \r\n"); 59 60 std::vector<ParsedHeader> parsed_headers; 61 bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback, 62 &parsed_headers); 63 64 EXPECT_TRUE(success); 65 ASSERT_EQ(parsed_headers.size(), 2U); 66 67 EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("x-custom")); 68 EXPECT_EQ(parsed_headers[0].value.Length(), 10U); 69 EXPECT_EQ(0, memcmp(parsed_headers[0].value.Elements(), "test-value", 10)); 70 71 EXPECT_TRUE(parsed_headers[1].name.EqualsLiteral("user-agent")); 72 EXPECT_EQ(parsed_headers[1].value.Length(), 11U); 73 EXPECT_EQ(0, memcmp(parsed_headers[1].value.Elements(), "Mozilla/5.0", 11)); 74 } 75 76 TEST(TestParseHeaders, ParseHeadersWithColonInValue) 77 { 78 nsAutoCString headers; 79 headers.AssignLiteral("\r\nLocation: http://example.com:8080/path\r\n"); 80 81 std::vector<ParsedHeader> parsed_headers; 82 bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback, 83 &parsed_headers); 84 85 EXPECT_TRUE(success); 86 ASSERT_EQ(parsed_headers.size(), 1U); 87 EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("location")); 88 EXPECT_EQ(parsed_headers[0].value.Length(), 28U); 89 EXPECT_EQ(0, memcmp(parsed_headers[0].value.Elements(), 90 "http://example.com:8080/path", 28)); 91 } 92 93 TEST(TestParseHeaders, ParseHeadersNonUtf8Value) 94 { 95 // Create headers with non-UTF8 bytes in the value 96 nsAutoCString headers; 97 headers.AssignLiteral("\r\nX-Custom: "); 98 headers.Append(char(0xFF)); 99 headers.Append(char(0xFE)); 100 headers.Append(char(0xFD)); 101 headers.AppendLiteral("\r\n"); 102 103 std::vector<ParsedHeader> parsed_headers; 104 bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback, 105 &parsed_headers); 106 107 EXPECT_TRUE(success); 108 ASSERT_EQ(parsed_headers.size(), 1U); 109 EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("x-custom")); 110 EXPECT_EQ(parsed_headers[0].value.Length(), 3U); 111 EXPECT_EQ(parsed_headers[0].value[0], 0xFF); 112 EXPECT_EQ(parsed_headers[0].value[1], 0xFE); 113 EXPECT_EQ(parsed_headers[0].value[2], 0xFD); 114 } 115 116 TEST(TestParseHeaders, ParseHeadersExcludesColonHeaders) 117 { 118 nsAutoCString headers; 119 headers.AssignLiteral("\r\n:method: GET\r\nContent-Type: text/html\r\n"); 120 121 std::vector<ParsedHeader> parsed_headers; 122 bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback, 123 &parsed_headers); 124 125 EXPECT_TRUE(success); 126 ASSERT_EQ(parsed_headers.size(), 1U); // :method should be excluded 127 EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("content-type")); 128 } 129 130 TEST(TestParseHeaders, ParseHeadersExcludesForbiddenHeaders) 131 { 132 nsAutoCString headers; 133 headers.AssignLiteral( 134 "\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nHost: " 135 "example.com\r\n"); 136 137 std::vector<ParsedHeader> parsed_headers; 138 bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback, 139 &parsed_headers); 140 141 EXPECT_TRUE(success); 142 ASSERT_EQ(parsed_headers.size(), 143 1U); // Connection and Host should be excluded 144 EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("content-type")); 145 } 146 147 TEST(TestParseHeaders, ParseHeadersEmptyValue) 148 { 149 nsAutoCString headers; 150 headers.AssignLiteral("\r\nX-Empty:\r\nX-Spaces: \r\n"); 151 152 std::vector<ParsedHeader> parsed_headers; 153 bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback, 154 &parsed_headers); 155 156 EXPECT_TRUE(success); 157 ASSERT_EQ(parsed_headers.size(), 2U); 158 EXPECT_TRUE(parsed_headers[0].name.EqualsLiteral("x-empty")); 159 EXPECT_EQ(parsed_headers[0].value.Length(), 0U); 160 EXPECT_TRUE(parsed_headers[1].name.EqualsLiteral("x-spaces")); 161 EXPECT_EQ(parsed_headers[1].value.Length(), 0U); 162 } 163 164 TEST(TestParseHeaders, ParseHeadersInvalidUtf8Name) 165 { 166 // Create headers with non-UTF8 bytes in the name 167 nsAutoCString headers; 168 headers.AssignLiteral("\r\n"); 169 headers.Append(char(0xFF)); 170 headers.Append(char(0xFE)); 171 headers.AppendLiteral(": value\r\n"); 172 173 std::vector<ParsedHeader> parsed_headers; 174 bool success = neqo_glue_test_parse_headers(&headers, collect_header_callback, 175 &parsed_headers); 176 177 EXPECT_FALSE(success); // Should fail with invalid UTF-8 in name 178 }