Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <algorithm>
      6 
      7 #include "base/basictypes.h"
      8 #include "net/http/http_util.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 using net::HttpUtil;
     12 
     13 namespace {
     14 class HttpUtilTest : public testing::Test {};
     15 }
     16 
     17 TEST(HttpUtilTest, HasHeader) {
     18   static const struct {
     19     const char* headers;
     20     const char* name;
     21     bool expected_result;
     22   } tests[] = {
     23     { "", "foo", false },
     24     { "foo\r\nbar", "foo", false },
     25     { "ffoo: 1", "foo", false },
     26     { "foo: 1", "foo", true },
     27     { "foo: 1\r\nbar: 2", "foo", true },
     28     { "fOO: 1\r\nbar: 2", "foo", true },
     29     { "g: 0\r\nfoo: 1\r\nbar: 2", "foo", true },
     30   };
     31   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
     32     bool result = HttpUtil::HasHeader(tests[i].headers, tests[i].name);
     33     EXPECT_EQ(tests[i].expected_result, result);
     34   }
     35 }
     36 
     37 TEST(HttpUtilTest, StripHeaders) {
     38   static const char* headers =
     39       "Origin: origin\r\n"
     40       "Content-Type: text/plain\r\n"
     41       "Cookies: foo1\r\n"
     42       "Custom: baz\r\n"
     43       "COOKIES: foo2\r\n"
     44       "Server: Apache\r\n"
     45       "OrIGin: origin2\r\n";
     46 
     47   static const char* header_names[] = {
     48     "origin", "content-type", "cookies"
     49   };
     50 
     51   static const char* expected_stripped_headers =
     52       "Custom: baz\r\n"
     53       "Server: Apache\r\n";
     54 
     55   EXPECT_EQ(expected_stripped_headers,
     56             HttpUtil::StripHeaders(headers, header_names,
     57                                    arraysize(header_names)));
     58 }
     59 
     60 TEST(HttpUtilTest, HeadersIterator) {
     61   std::string headers = "foo: 1\t\r\nbar: hello world\r\nbaz: 3 \r\n";
     62 
     63   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
     64 
     65   ASSERT_TRUE(it.GetNext());
     66   EXPECT_EQ(std::string("foo"), it.name());
     67   EXPECT_EQ(std::string("1"), it.values());
     68 
     69   ASSERT_TRUE(it.GetNext());
     70   EXPECT_EQ(std::string("bar"), it.name());
     71   EXPECT_EQ(std::string("hello world"), it.values());
     72 
     73   ASSERT_TRUE(it.GetNext());
     74   EXPECT_EQ(std::string("baz"), it.name());
     75   EXPECT_EQ(std::string("3"), it.values());
     76 
     77   EXPECT_FALSE(it.GetNext());
     78 }
     79 
     80 TEST(HttpUtilTest, HeadersIterator_MalformedLine) {
     81   std::string headers = "foo: 1\n: 2\n3\nbar: 4";
     82 
     83   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
     84 
     85   ASSERT_TRUE(it.GetNext());
     86   EXPECT_EQ(std::string("foo"), it.name());
     87   EXPECT_EQ(std::string("1"), it.values());
     88 
     89   ASSERT_TRUE(it.GetNext());
     90   EXPECT_EQ(std::string("bar"), it.name());
     91   EXPECT_EQ(std::string("4"), it.values());
     92 
     93   EXPECT_FALSE(it.GetNext());
     94 }
     95 
     96 TEST(HttpUtilTest, HeadersIterator_AdvanceTo) {
     97   std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4";
     98 
     99   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
    100   EXPECT_TRUE(it.AdvanceTo("foo"));
    101   EXPECT_EQ("foo", it.name());
    102   EXPECT_TRUE(it.AdvanceTo("bar"));
    103   EXPECT_EQ("bar", it.name());
    104   EXPECT_FALSE(it.AdvanceTo("blat"));
    105   EXPECT_FALSE(it.GetNext());  // should be at end of headers
    106 }
    107 
    108 TEST(HttpUtilTest, HeadersIterator_Reset) {
    109   std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4";
    110   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
    111   // Search past "foo".
    112   EXPECT_TRUE(it.AdvanceTo("bar"));
    113   // Now try advancing to "foo".  This time it should fail since the iterator
    114   // position is past it.
    115   EXPECT_FALSE(it.AdvanceTo("foo"));
    116   it.Reset();
    117   // Now that we reset the iterator position, we should find 'foo'
    118   EXPECT_TRUE(it.AdvanceTo("foo"));
    119 }
    120 
    121 TEST(HttpUtilTest, ValuesIterator) {
    122   std::string values = " must-revalidate,   no-cache=\"foo, bar\"\t, private ";
    123 
    124   HttpUtil::ValuesIterator it(values.begin(), values.end(), ',');
    125 
    126   ASSERT_TRUE(it.GetNext());
    127   EXPECT_EQ(std::string("must-revalidate"), it.value());
    128 
    129   ASSERT_TRUE(it.GetNext());
    130   EXPECT_EQ(std::string("no-cache=\"foo, bar\""), it.value());
    131 
    132   ASSERT_TRUE(it.GetNext());
    133   EXPECT_EQ(std::string("private"), it.value());
    134 
    135   EXPECT_FALSE(it.GetNext());
    136 }
    137 
    138 TEST(HttpUtilTest, ValuesIterator_Blanks) {
    139   std::string values = " \t ";
    140 
    141   HttpUtil::ValuesIterator it(values.begin(), values.end(), ',');
    142 
    143   EXPECT_FALSE(it.GetNext());
    144 }
    145 
    146 TEST(HttpUtilTest, Unquote) {
    147   // Replace <backslash> " with ".
    148   EXPECT_STREQ("xyz\"abc", HttpUtil::Unquote("\"xyz\\\"abc\"").c_str());
    149 
    150   // Replace <backslash> <backslash> with <backslash>
    151   EXPECT_STREQ("xyz\\abc", HttpUtil::Unquote("\"xyz\\\\abc\"").c_str());
    152   EXPECT_STREQ("xyz\\\\\\abc",
    153                HttpUtil::Unquote("\"xyz\\\\\\\\\\\\abc\"").c_str());
    154 
    155   // Replace <backslash> X with X
    156   EXPECT_STREQ("xyzXabc", HttpUtil::Unquote("\"xyz\\Xabc\"").c_str());
    157 
    158   // Act as identity function on unquoted inputs.
    159   EXPECT_STREQ("X", HttpUtil::Unquote("X").c_str());
    160   EXPECT_STREQ("\"", HttpUtil::Unquote("\"").c_str());
    161 
    162   // Allow single quotes to act as quote marks.
    163   // Not part of RFC 2616.
    164   EXPECT_STREQ("x\"", HttpUtil::Unquote("'x\"'").c_str());
    165 }
    166 
    167 TEST(HttpUtilTest, Quote) {
    168   EXPECT_STREQ("\"xyz\\\"abc\"", HttpUtil::Quote("xyz\"abc").c_str());
    169 
    170   // Replace <backslash> <backslash> with <backslash>
    171   EXPECT_STREQ("\"xyz\\\\abc\"", HttpUtil::Quote("xyz\\abc").c_str());
    172 
    173   // Replace <backslash> X with X
    174   EXPECT_STREQ("\"xyzXabc\"", HttpUtil::Quote("xyzXabc").c_str());
    175 }
    176 
    177 TEST(HttpUtilTest, LocateEndOfHeaders) {
    178   struct {
    179     const char* input;
    180     int expected_result;
    181   } tests[] = {
    182     { "foo\r\nbar\r\n\r\n", 12 },
    183     { "foo\nbar\n\n", 9 },
    184     { "foo\r\nbar\r\n\r\njunk", 12 },
    185     { "foo\nbar\n\njunk", 9 },
    186     { "foo\nbar\n\r\njunk", 10 },
    187     { "foo\nbar\r\n\njunk", 10 },
    188   };
    189   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    190     int input_len = static_cast<int>(strlen(tests[i].input));
    191     int eoh = HttpUtil::LocateEndOfHeaders(tests[i].input, input_len);
    192     EXPECT_EQ(tests[i].expected_result, eoh);
    193   }
    194 }
    195 
    196 TEST(HttpUtilTest, AssembleRawHeaders) {
    197   struct {
    198     const char* input;
    199     const char* expected_result;  // with '\0' changed to '|'
    200   } tests[] = {
    201     { "HTTP/1.0 200 OK\r\nFoo: 1\r\nBar: 2\r\n\r\n",
    202       "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" },
    203 
    204     { "HTTP/1.0 200 OK\nFoo: 1\nBar: 2\n\n",
    205       "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" },
    206 
    207     // Valid line continuation (single SP).
    208     {
    209       "HTTP/1.0 200 OK\n"
    210       "Foo: 1\n"
    211       " continuation\n"
    212       "Bar: 2\n\n",
    213 
    214       "HTTP/1.0 200 OK|"
    215       "Foo: 1 continuation|"
    216       "Bar: 2||"
    217     },
    218 
    219     // Valid line continuation (single HT).
    220     {
    221       "HTTP/1.0 200 OK\n"
    222       "Foo: 1\n"
    223       "\tcontinuation\n"
    224       "Bar: 2\n\n",
    225 
    226       "HTTP/1.0 200 OK|"
    227       "Foo: 1 continuation|"
    228       "Bar: 2||"
    229     },
    230 
    231     // Valid line continuation (multiple SP).
    232     {
    233       "HTTP/1.0 200 OK\n"
    234       "Foo: 1\n"
    235       "   continuation\n"
    236       "Bar: 2\n\n",
    237 
    238       "HTTP/1.0 200 OK|"
    239       "Foo: 1 continuation|"
    240       "Bar: 2||"
    241     },
    242 
    243     // Valid line continuation (multiple HT).
    244     {
    245       "HTTP/1.0 200 OK\n"
    246       "Foo: 1\n"
    247       "\t\t\tcontinuation\n"
    248       "Bar: 2\n\n",
    249 
    250       "HTTP/1.0 200 OK|"
    251       "Foo: 1 continuation|"
    252       "Bar: 2||"
    253     },
    254 
    255     // Valid line continuation (mixed HT, SP).
    256     {
    257       "HTTP/1.0 200 OK\n"
    258       "Foo: 1\n"
    259       " \t \t continuation\n"
    260       "Bar: 2\n\n",
    261 
    262       "HTTP/1.0 200 OK|"
    263       "Foo: 1 continuation|"
    264       "Bar: 2||"
    265     },
    266 
    267     // Valid multi-line continuation
    268     {
    269       "HTTP/1.0 200 OK\n"
    270       "Foo: 1\n"
    271       " continuation1\n"
    272       "\tcontinuation2\n"
    273       "  continuation3\n"
    274       "Bar: 2\n\n",
    275 
    276       "HTTP/1.0 200 OK|"
    277       "Foo: 1 continuation1 continuation2 continuation3|"
    278       "Bar: 2||"
    279     },
    280 
    281     // Continuation of quoted value.
    282     // This is different from what Firefox does, since it
    283     // will preserve the LWS.
    284     {
    285       "HTTP/1.0 200 OK\n"
    286       "Etag: \"34534-d3\n"
    287       "    134q\"\n"
    288       "Bar: 2\n\n",
    289 
    290       "HTTP/1.0 200 OK|"
    291       "Etag: \"34534-d3 134q\"|"
    292       "Bar: 2||"
    293     },
    294 
    295     // Valid multi-line continuation, full LWS lines
    296     {
    297       "HTTP/1.0 200 OK\n"
    298       "Foo: 1\n"
    299       "         \n"
    300       "\t\t\t\t\n"
    301       "\t  continuation\n"
    302       "Bar: 2\n\n",
    303 
    304       // One SP per continued line = 3.
    305       "HTTP/1.0 200 OK|"
    306       "Foo: 1   continuation|"
    307       "Bar: 2||"
    308     },
    309 
    310     // Valid multi-line continuation, all LWS
    311     {
    312       "HTTP/1.0 200 OK\n"
    313       "Foo: 1\n"
    314       "         \n"
    315       "\t\t\t\t\n"
    316       "\t  \n"
    317       "Bar: 2\n\n",
    318 
    319       // One SP per continued line = 3.
    320       "HTTP/1.0 200 OK|"
    321       "Foo: 1   |"
    322       "Bar: 2||"
    323     },
    324 
    325     // Valid line continuation (No value bytes in first line).
    326     {
    327       "HTTP/1.0 200 OK\n"
    328       "Foo:\n"
    329       " value\n"
    330       "Bar: 2\n\n",
    331 
    332       "HTTP/1.0 200 OK|"
    333       "Foo: value|"
    334       "Bar: 2||"
    335     },
    336 
    337     // Not a line continuation (can't continue status line).
    338     {
    339       "HTTP/1.0 200 OK\n"
    340       " Foo: 1\n"
    341       "Bar: 2\n\n",
    342 
    343       "HTTP/1.0 200 OK|"
    344       " Foo: 1|"
    345       "Bar: 2||"
    346     },
    347 
    348     // Not a line continuation (can't continue status line).
    349     {
    350       "HTTP/1.0\n"
    351       " 200 OK\n"
    352       "Foo: 1\n"
    353       "Bar: 2\n\n",
    354 
    355       "HTTP/1.0|"
    356       " 200 OK|"
    357       "Foo: 1|"
    358       "Bar: 2||"
    359     },
    360 
    361     // Not a line continuation (can't continue status line).
    362     {
    363       "HTTP/1.0 404\n"
    364       " Not Found\n"
    365       "Foo: 1\n"
    366       "Bar: 2\n\n",
    367 
    368       "HTTP/1.0 404|"
    369       " Not Found|"
    370       "Foo: 1|"
    371       "Bar: 2||"
    372     },
    373 
    374     // Unterminated status line.
    375     {
    376       "HTTP/1.0 200 OK",
    377 
    378       "HTTP/1.0 200 OK||"
    379     },
    380 
    381     // Single terminated, with headers
    382     {
    383       "HTTP/1.0 200 OK\n"
    384       "Foo: 1\n"
    385       "Bar: 2\n",
    386 
    387       "HTTP/1.0 200 OK|"
    388       "Foo: 1|"
    389       "Bar: 2||"
    390     },
    391 
    392     // Not terminated, with headers
    393     {
    394       "HTTP/1.0 200 OK\n"
    395       "Foo: 1\n"
    396       "Bar: 2",
    397 
    398       "HTTP/1.0 200 OK|"
    399       "Foo: 1|"
    400       "Bar: 2||"
    401     },
    402 
    403     // Not a line continuation (VT)
    404     {
    405       "HTTP/1.0 200 OK\n"
    406       "Foo: 1\n"
    407       "\vInvalidContinuation\n"
    408       "Bar: 2\n\n",
    409 
    410       "HTTP/1.0 200 OK|"
    411       "Foo: 1|"
    412       "\vInvalidContinuation|"
    413       "Bar: 2||"
    414     },
    415 
    416     // Not a line continuation (formfeed)
    417     {
    418       "HTTP/1.0 200 OK\n"
    419       "Foo: 1\n"
    420       "\fInvalidContinuation\n"
    421       "Bar: 2\n\n",
    422 
    423       "HTTP/1.0 200 OK|"
    424       "Foo: 1|"
    425       "\fInvalidContinuation|"
    426       "Bar: 2||"
    427     },
    428 
    429     // Not a line continuation -- can't continue header names.
    430     {
    431       "HTTP/1.0 200 OK\n"
    432       "Serv\n"
    433       " er: Apache\n"
    434       "\tInvalidContinuation\n"
    435       "Bar: 2\n\n",
    436 
    437       "HTTP/1.0 200 OK|"
    438       "Serv|"
    439       " er: Apache|"
    440       "\tInvalidContinuation|"
    441       "Bar: 2||"
    442     },
    443 
    444     // Not a line continuation -- no value to continue.
    445     {
    446       "HTTP/1.0 200 OK\n"
    447       "Foo: 1\n"
    448       "garbage\n"
    449       "  not-a-continuation\n"
    450       "Bar: 2\n\n",
    451 
    452       "HTTP/1.0 200 OK|"
    453       "Foo: 1|"
    454       "garbage|"
    455       "  not-a-continuation|"
    456       "Bar: 2||",
    457     },
    458 
    459     // Not a line continuation -- no valid name.
    460     {
    461       "HTTP/1.0 200 OK\n"
    462       ": 1\n"
    463       "  garbage\n"
    464       "Bar: 2\n\n",
    465 
    466       "HTTP/1.0 200 OK|"
    467       ": 1|"
    468       "  garbage|"
    469       "Bar: 2||",
    470     },
    471 
    472     // Not a line continuation -- no valid name (whitespace)
    473     {
    474       "HTTP/1.0 200 OK\n"
    475       "   : 1\n"
    476       "  garbage\n"
    477       "Bar: 2\n\n",
    478 
    479       "HTTP/1.0 200 OK|"
    480       "   : 1|"
    481       "  garbage|"
    482       "Bar: 2||",
    483     },
    484 
    485   };
    486   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    487     int input_len = static_cast<int>(strlen(tests[i].input));
    488     std::string raw = HttpUtil::AssembleRawHeaders(tests[i].input, input_len);
    489     std::replace(raw.begin(), raw.end(), '\0', '|');
    490     EXPECT_TRUE(raw == tests[i].expected_result);
    491   }
    492 }
    493 
    494 // Test SpecForRequest() and PathForRequest().
    495 TEST(HttpUtilTest, RequestUrlSanitize) {
    496   struct {
    497     const char* url;
    498     const char* expected_spec;
    499     const char* expected_path;
    500   } tests[] = {
    501     { // Check that #hash is removed.
    502       "http://www.google.com:78/foobar?query=1#hash",
    503       "http://www.google.com:78/foobar?query=1",
    504       "/foobar?query=1"
    505     },
    506     { // The reference may itself contain # -- strip all of it.
    507       "http://192.168.0.1?query=1#hash#10#11#13#14",
    508       "http://192.168.0.1/?query=1",
    509       "/?query=1"
    510     },
    511     { // Strip username/password.
    512       "http://user:pass@google.com",
    513       "http://google.com/",
    514       "/"
    515     }
    516   };
    517   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    518     GURL url(GURL(tests[i].url));
    519     std::string expected_spec(tests[i].expected_spec);
    520     std::string expected_path(tests[i].expected_path);
    521 
    522     EXPECT_EQ(expected_spec, HttpUtil::SpecForRequest(url));
    523     EXPECT_EQ(expected_path, HttpUtil::PathForRequest(url));
    524   }
    525 }
    526 
    527 TEST(HttpUtilTest, GenerateAcceptLanguageHeader) {
    528   EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6"),
    529             HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de"));
    530   EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6,ko;q=0.4,zh-CN;q=0.2,"
    531                         "ja;q=0.2"),
    532             HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de,ko,zh-CN,ja"));
    533 }
    534 
    535 TEST(HttpUtilTest, GenerateAcceptCharsetHeader) {
    536   EXPECT_EQ(std::string("utf-8,*;q=0.5"),
    537             HttpUtil::GenerateAcceptCharsetHeader("utf-8"));
    538   EXPECT_EQ(std::string("EUC-JP,utf-8;q=0.7,*;q=0.3"),
    539             HttpUtil::GenerateAcceptCharsetHeader("EUC-JP"));
    540 }
    541 
    542 TEST(HttpUtilTest, ParseRanges) {
    543   const struct {
    544     const char* headers;
    545     bool expected_return_value;
    546     size_t expected_ranges_size;
    547     const struct {
    548       int64 expected_first_byte_position;
    549       int64 expected_last_byte_position;
    550       int64 expected_suffix_length;
    551     } expected_ranges[10];
    552   } tests[] = {
    553     { "Range: bytes=0-10",
    554       true,
    555       1,
    556       { {0, 10, -1}, }
    557     },
    558     { "Range: bytes=10-0",
    559       false,
    560       0,
    561       {}
    562     },
    563     { "Range: BytES=0-10",
    564       true,
    565       1,
    566       { {0, 10, -1}, }
    567     },
    568     { "Range: megabytes=0-10",
    569       false,
    570       0,
    571       {}
    572     },
    573     { "Range: bytes0-10",
    574       false,
    575       0,
    576       {}
    577     },
    578     { "Range: bytes=0-0,0-10,10-20,100-200,100-,-200",
    579       true,
    580       6,
    581       { {0, 0, -1},
    582         {0, 10, -1},
    583         {10, 20, -1},
    584         {100, 200, -1},
    585         {100, -1, -1},
    586         {-1, -1, 200},
    587       }
    588     },
    589     { "Range: bytes=0-10\r\n"
    590       "Range: bytes=0-10,10-20,100-200,100-,-200",
    591       true,
    592       1,
    593       { {0, 10, -1}
    594       }
    595     },
    596     { "Range: bytes=",
    597       false,
    598       0,
    599       {}
    600     },
    601     { "Range: bytes=-",
    602       false,
    603       0,
    604       {}
    605     },
    606     { "Range: bytes=0-10-",
    607       false,
    608       0,
    609       {}
    610     },
    611     { "Range: bytes=-0-10",
    612       false,
    613       0,
    614       {}
    615     },
    616     { "Range: bytes =0-10\r\n",
    617       true,
    618       1,
    619       { {0, 10, -1}
    620       }
    621     },
    622     { "Range: bytes=  0-10      \r\n",
    623       true,
    624       1,
    625       { {0, 10, -1}
    626       }
    627     },
    628     { "Range: bytes  =   0  -   10      \r\n",
    629       true,
    630       1,
    631       { {0, 10, -1}
    632       }
    633     },
    634     { "Range: bytes=   0-1   0\r\n",
    635       false,
    636       0,
    637       {}
    638     },
    639     { "Range: bytes=   0-     -10\r\n",
    640       false,
    641       0,
    642       {}
    643     },
    644     { "Range: bytes=   0  -  1   ,   10 -20,   100- 200 ,  100-,  -200 \r\n",
    645       true,
    646       5,
    647       { {0, 1, -1},
    648         {10, 20, -1},
    649         {100, 200, -1},
    650         {100, -1, -1},
    651         {-1, -1, 200},
    652       }
    653     },
    654   };
    655 
    656   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    657     std::vector<net::HttpByteRange> ranges;
    658     bool return_value = HttpUtil::ParseRanges(std::string(tests[i].headers),
    659                                               &ranges);
    660     EXPECT_EQ(tests[i].expected_return_value, return_value);
    661     if (return_value) {
    662       EXPECT_EQ(tests[i].expected_ranges_size, ranges.size());
    663       for (size_t j = 0; j < ranges.size(); ++j) {
    664         EXPECT_EQ(tests[i].expected_ranges[j].expected_first_byte_position,
    665                   ranges[j].first_byte_position());
    666         EXPECT_EQ(tests[i].expected_ranges[j].expected_last_byte_position,
    667                   ranges[j].last_byte_position());
    668         EXPECT_EQ(tests[i].expected_ranges[j].expected_suffix_length,
    669                   ranges[j].suffix_length());
    670       }
    671     }
    672   }
    673 }
    674 
    675 namespace {
    676 void CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator* parser,
    677                                bool expect_valid,
    678                                std::string expected_name,
    679                                std::string expected_value) {
    680   ASSERT_EQ(expect_valid, parser->valid());
    681   if (!expect_valid) {
    682     return;
    683   }
    684 
    685   // Let's make sure that these never change (i.e., when a quoted value is
    686   // unquoted, it should be cached on the first calls and not regenerated
    687   // later).
    688   std::string::const_iterator first_value_begin = parser->value_begin();
    689   std::string::const_iterator first_value_end = parser->value_end();
    690 
    691   ASSERT_EQ(expected_name, std::string(parser->name_begin(),
    692                                        parser->name_end()));
    693   ASSERT_EQ(expected_name, parser->name());
    694   ASSERT_EQ(expected_value, std::string(parser->value_begin(),
    695                                         parser->value_end()));
    696   ASSERT_EQ(expected_value, parser->value());
    697 
    698   // Make sure they didn't/don't change.
    699   ASSERT_TRUE(first_value_begin == parser->value_begin());
    700   ASSERT_TRUE(first_value_end == parser->value_end());
    701 }
    702 
    703 void CheckNextNameValuePair(HttpUtil::NameValuePairsIterator* parser,
    704                             bool expect_next,
    705                             bool expect_valid,
    706                             std::string expected_name,
    707                             std::string expected_value) {
    708   ASSERT_EQ(expect_next, parser->GetNext());
    709   ASSERT_EQ(expect_valid, parser->valid());
    710   if (!expect_next || !expect_valid) {
    711     return;
    712   }
    713 
    714   CheckCurrentNameValuePair(parser,
    715                             expect_valid,
    716                             expected_name,
    717                             expected_value);
    718 }
    719 
    720 void CheckInvalidNameValuePair(std::string valid_part,
    721                                std::string invalid_part) {
    722   std::string whole_string = valid_part + invalid_part;
    723 
    724   HttpUtil::NameValuePairsIterator valid_parser(valid_part.begin(),
    725                                                 valid_part.end(),
    726                                                 ';');
    727   HttpUtil::NameValuePairsIterator invalid_parser(whole_string.begin(),
    728                                                   whole_string.end(),
    729                                                   ';');
    730 
    731   ASSERT_TRUE(valid_parser.valid());
    732   ASSERT_TRUE(invalid_parser.valid());
    733 
    734   // Both parsers should return all the same values until "valid_parser" is
    735   // exhausted.
    736   while (valid_parser.GetNext()) {
    737     ASSERT_TRUE(invalid_parser.GetNext());
    738     ASSERT_TRUE(valid_parser.valid());
    739     ASSERT_TRUE(invalid_parser.valid());
    740     ASSERT_EQ(valid_parser.name(), invalid_parser.name());
    741     ASSERT_EQ(valid_parser.value(), invalid_parser.value());
    742   }
    743 
    744   // valid_parser is exhausted and remains 'valid'
    745   ASSERT_TRUE(valid_parser.valid());
    746 
    747   // invalid_parser's corresponding call to GetNext also returns false...
    748   ASSERT_FALSE(invalid_parser.GetNext());
    749   // ...but the parser is in an invalid state.
    750   ASSERT_FALSE(invalid_parser.valid());
    751 }
    752 
    753 }  // anonymous namespace
    754 
    755 TEST(HttpUtilTest, NameValuePairsIteratorCopyAndAssign) {
    756   std::string data = "alpha='\\'a\\''; beta=\" b \"; cappa='c;'; delta=\"d\"";
    757   HttpUtil::NameValuePairsIterator parser_a(data.begin(), data.end(), ';');
    758 
    759   EXPECT_TRUE(parser_a.valid());
    760   ASSERT_NO_FATAL_FAILURE(
    761       CheckNextNameValuePair(&parser_a, true, true, "alpha", "'a'"));
    762 
    763   HttpUtil::NameValuePairsIterator parser_b(parser_a);
    764   // a and b now point to same location
    765   ASSERT_NO_FATAL_FAILURE(
    766       CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'"));
    767   ASSERT_NO_FATAL_FAILURE(
    768       CheckCurrentNameValuePair(&parser_a, true, "alpha", "'a'"));
    769 
    770   // advance a, no effect on b
    771   ASSERT_NO_FATAL_FAILURE(
    772       CheckNextNameValuePair(&parser_a, true, true, "beta", " b "));
    773   ASSERT_NO_FATAL_FAILURE(
    774       CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'"));
    775 
    776   // assign b the current state of a, no effect on a
    777   parser_b = parser_a;
    778   ASSERT_NO_FATAL_FAILURE(
    779       CheckCurrentNameValuePair(&parser_b, true, "beta", " b "));
    780   ASSERT_NO_FATAL_FAILURE(
    781       CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
    782 
    783   // advance b, no effect on a
    784   ASSERT_NO_FATAL_FAILURE(
    785       CheckNextNameValuePair(&parser_b, true, true, "cappa", "c;"));
    786   ASSERT_NO_FATAL_FAILURE(
    787       CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
    788 }
    789 
    790 TEST(HttpUtilTest, NameValuePairsIteratorEmptyInput) {
    791   std::string data = "";
    792   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
    793 
    794   EXPECT_TRUE(parser.valid());
    795   ASSERT_NO_FATAL_FAILURE(
    796       CheckNextNameValuePair(&parser, false, true, "", ""));
    797 }
    798 
    799 TEST(HttpUtilTest, NameValuePairsIterator) {
    800   std::string data = "alpha=1; beta= 2 ;cappa =' 3; ';"
    801                      "delta= \" \\\"4\\\" \"; e= \" '5'\"; e=6;"
    802                      "f='\\'\\h\\e\\l\\l\\o\\ \\w\\o\\r\\l\\d\\'';"
    803                      "g=''; h='hello'";
    804   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
    805   EXPECT_TRUE(parser.valid());
    806 
    807   ASSERT_NO_FATAL_FAILURE(
    808       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
    809   ASSERT_NO_FATAL_FAILURE(
    810       CheckNextNameValuePair(&parser, true, true, "beta", "2"));
    811   ASSERT_NO_FATAL_FAILURE(
    812       CheckNextNameValuePair(&parser, true, true, "cappa", " 3; "));
    813   ASSERT_NO_FATAL_FAILURE(
    814       CheckNextNameValuePair(&parser, true, true, "delta", " \"4\" "));
    815   ASSERT_NO_FATAL_FAILURE(
    816       CheckNextNameValuePair(&parser, true, true, "e", " '5'"));
    817   ASSERT_NO_FATAL_FAILURE(
    818       CheckNextNameValuePair(&parser, true, true, "e", "6"));
    819   ASSERT_NO_FATAL_FAILURE(
    820       CheckNextNameValuePair(&parser, true, true, "f", "'hello world'"));
    821   ASSERT_NO_FATAL_FAILURE(
    822       CheckNextNameValuePair(&parser, true, true, "g", ""));
    823   ASSERT_NO_FATAL_FAILURE(
    824       CheckNextNameValuePair(&parser, true, true, "h", "hello"));
    825   ASSERT_NO_FATAL_FAILURE(
    826       CheckNextNameValuePair(&parser, false, true, "", ""));
    827 }
    828 
    829 TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) {
    830   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; beta"));
    831   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("", "beta"));
    832 
    833   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; 'beta'=2"));
    834   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("", "'beta'=2"));
    835   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";beta="));
    836   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1",
    837                                                     ";beta=;cappa=2"));
    838 
    839   // According to the spec this is an error, but it doesn't seem appropriate to
    840   // change our behaviour to be less permissive at this time.
    841   // See NameValuePairsIteratorExtraSeparators test
    842   // ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";; beta=2"));
    843 }
    844 
    845 // If we are going to support extra separators against the spec, let's just make
    846 // sure they work rationally.
    847 TEST(HttpUtilTest, NameValuePairsIteratorExtraSeparators) {
    848   std::string data = " ; ;;alpha=1; ;; ; beta= 2;cappa=3;;; ; ";
    849   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
    850   EXPECT_TRUE(parser.valid());
    851 
    852   ASSERT_NO_FATAL_FAILURE(
    853       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
    854   ASSERT_NO_FATAL_FAILURE(
    855       CheckNextNameValuePair(&parser, true, true, "beta", "2"));
    856   ASSERT_NO_FATAL_FAILURE(
    857       CheckNextNameValuePair(&parser, true, true, "cappa", "3"));
    858   ASSERT_NO_FATAL_FAILURE(
    859       CheckNextNameValuePair(&parser, false, true, "", ""));
    860 }
    861 
    862 // See comments on the implementation of NameValuePairsIterator::GetNext
    863 // regarding this derogation from the spec.
    864 TEST(HttpUtilTest, NameValuePairsIteratorMissingEndQuote) {
    865   std::string data = "name='value";
    866   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
    867   EXPECT_TRUE(parser.valid());
    868 
    869   ASSERT_NO_FATAL_FAILURE(
    870       CheckNextNameValuePair(&parser, true, true, "name", "value"));
    871   ASSERT_NO_FATAL_FAILURE(
    872       CheckNextNameValuePair(&parser, false, true, "", ""));
    873 }
    874