tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }