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