Index: net/http/http_util_unittest.cc |
diff --git a/net/http/http_util_unittest.cc b/net/http/http_util_unittest.cc |
deleted file mode 100644 |
index ee501c72bf434d6c550d6e1e4c1aa3fbd79ed864..0000000000000000000000000000000000000000 |
--- a/net/http/http_util_unittest.cc |
+++ /dev/null |
@@ -1,1116 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include <algorithm> |
- |
-#include "base/basictypes.h" |
-#include "base/strings/string_util.h" |
-#include "net/http/http_util.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-using net::HttpUtil; |
- |
-namespace { |
-class HttpUtilTest : public testing::Test {}; |
-} |
- |
-TEST(HttpUtilTest, IsSafeHeader) { |
- static const char* const unsafe_headers[] = { |
- "sec-", |
- "sEc-", |
- "sec-foo", |
- "sEc-FoO", |
- "proxy-", |
- "pRoXy-", |
- "proxy-foo", |
- "pRoXy-FoO", |
- "accept-charset", |
- "accept-encoding", |
- "access-control-request-headers", |
- "access-control-request-method", |
- "connection", |
- "content-length", |
- "cookie", |
- "cookie2", |
- "content-transfer-encoding", |
- "date", |
- "expect", |
- "host", |
- "keep-alive", |
- "origin", |
- "referer", |
- "te", |
- "trailer", |
- "transfer-encoding", |
- "upgrade", |
- "user-agent", |
- "via", |
- }; |
- for (size_t i = 0; i < arraysize(unsafe_headers); ++i) { |
- EXPECT_FALSE(HttpUtil::IsSafeHeader(unsafe_headers[i])) |
- << unsafe_headers[i]; |
- EXPECT_FALSE(HttpUtil::IsSafeHeader(StringToUpperASCII(std::string( |
- unsafe_headers[i])))) << unsafe_headers[i]; |
- } |
- static const char* const safe_headers[] = { |
- "foo", |
- "x-", |
- "x-foo", |
- "content-disposition", |
- "update", |
- "accept-charseta", |
- "accept_charset", |
- "accept-encodinga", |
- "accept_encoding", |
- "access-control-request-headersa", |
- "access-control-request-header", |
- "access_control_request_header", |
- "access-control-request-methoda", |
- "access_control_request_method", |
- "connectiona", |
- "content-lengtha", |
- "content_length", |
- "cookiea", |
- "cookie2a", |
- "cookie3", |
- "content-transfer-encodinga", |
- "content_transfer_encoding", |
- "datea", |
- "expecta", |
- "hosta", |
- "keep-alivea", |
- "keep_alive", |
- "origina", |
- "referera", |
- "referrer", |
- "tea", |
- "trailera", |
- "transfer-encodinga", |
- "transfer_encoding", |
- "upgradea", |
- "user-agenta", |
- "user_agent", |
- "viaa", |
- }; |
- for (size_t i = 0; i < arraysize(safe_headers); ++i) { |
- EXPECT_TRUE(HttpUtil::IsSafeHeader(safe_headers[i])) << safe_headers[i]; |
- EXPECT_TRUE(HttpUtil::IsSafeHeader(StringToUpperASCII(std::string( |
- safe_headers[i])))) << safe_headers[i]; |
- } |
-} |
- |
-TEST(HttpUtilTest, HasHeader) { |
- static const struct { |
- const char* const headers; |
- const char* const name; |
- bool expected_result; |
- } tests[] = { |
- { "", "foo", false }, |
- { "foo\r\nbar", "foo", false }, |
- { "ffoo: 1", "foo", false }, |
- { "foo: 1", "foo", true }, |
- { "foo: 1\r\nbar: 2", "foo", true }, |
- { "fOO: 1\r\nbar: 2", "foo", true }, |
- { "g: 0\r\nfoo: 1\r\nbar: 2", "foo", true }, |
- }; |
- for (size_t i = 0; i < arraysize(tests); ++i) { |
- bool result = HttpUtil::HasHeader(tests[i].headers, tests[i].name); |
- EXPECT_EQ(tests[i].expected_result, result); |
- } |
-} |
- |
-TEST(HttpUtilTest, StripHeaders) { |
- static const char* const headers = |
- "Origin: origin\r\n" |
- "Content-Type: text/plain\r\n" |
- "Cookies: foo1\r\n" |
- "Custom: baz\r\n" |
- "COOKIES: foo2\r\n" |
- "Server: Apache\r\n" |
- "OrIGin: origin2\r\n"; |
- |
- static const char* const header_names[] = { |
- "origin", "content-type", "cookies" |
- }; |
- |
- static const char* const expected_stripped_headers = |
- "Custom: baz\r\n" |
- "Server: Apache\r\n"; |
- |
- EXPECT_EQ(expected_stripped_headers, |
- HttpUtil::StripHeaders(headers, header_names, |
- arraysize(header_names))); |
-} |
- |
-TEST(HttpUtilTest, HeadersIterator) { |
- std::string headers = "foo: 1\t\r\nbar: hello world\r\nbaz: 3 \r\n"; |
- |
- HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); |
- |
- ASSERT_TRUE(it.GetNext()); |
- EXPECT_EQ(std::string("foo"), it.name()); |
- EXPECT_EQ(std::string("1"), it.values()); |
- |
- ASSERT_TRUE(it.GetNext()); |
- EXPECT_EQ(std::string("bar"), it.name()); |
- EXPECT_EQ(std::string("hello world"), it.values()); |
- |
- ASSERT_TRUE(it.GetNext()); |
- EXPECT_EQ(std::string("baz"), it.name()); |
- EXPECT_EQ(std::string("3"), it.values()); |
- |
- EXPECT_FALSE(it.GetNext()); |
-} |
- |
-TEST(HttpUtilTest, HeadersIterator_MalformedLine) { |
- std::string headers = "foo: 1\n: 2\n3\nbar: 4"; |
- |
- HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n"); |
- |
- ASSERT_TRUE(it.GetNext()); |
- EXPECT_EQ(std::string("foo"), it.name()); |
- EXPECT_EQ(std::string("1"), it.values()); |
- |
- ASSERT_TRUE(it.GetNext()); |
- EXPECT_EQ(std::string("bar"), it.name()); |
- EXPECT_EQ(std::string("4"), it.values()); |
- |
- EXPECT_FALSE(it.GetNext()); |
-} |
- |
-TEST(HttpUtilTest, HeadersIterator_AdvanceTo) { |
- std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4"; |
- |
- HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); |
- EXPECT_TRUE(it.AdvanceTo("foo")); |
- EXPECT_EQ("foo", it.name()); |
- EXPECT_TRUE(it.AdvanceTo("bar")); |
- EXPECT_EQ("bar", it.name()); |
- EXPECT_FALSE(it.AdvanceTo("blat")); |
- EXPECT_FALSE(it.GetNext()); // should be at end of headers |
-} |
- |
-TEST(HttpUtilTest, HeadersIterator_Reset) { |
- std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4"; |
- HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); |
- // Search past "foo". |
- EXPECT_TRUE(it.AdvanceTo("bar")); |
- // Now try advancing to "foo". This time it should fail since the iterator |
- // position is past it. |
- EXPECT_FALSE(it.AdvanceTo("foo")); |
- it.Reset(); |
- // Now that we reset the iterator position, we should find 'foo' |
- EXPECT_TRUE(it.AdvanceTo("foo")); |
-} |
- |
-TEST(HttpUtilTest, ValuesIterator) { |
- std::string values = " must-revalidate, no-cache=\"foo, bar\"\t, private "; |
- |
- HttpUtil::ValuesIterator it(values.begin(), values.end(), ','); |
- |
- ASSERT_TRUE(it.GetNext()); |
- EXPECT_EQ(std::string("must-revalidate"), it.value()); |
- |
- ASSERT_TRUE(it.GetNext()); |
- EXPECT_EQ(std::string("no-cache=\"foo, bar\""), it.value()); |
- |
- ASSERT_TRUE(it.GetNext()); |
- EXPECT_EQ(std::string("private"), it.value()); |
- |
- EXPECT_FALSE(it.GetNext()); |
-} |
- |
-TEST(HttpUtilTest, ValuesIterator_Blanks) { |
- std::string values = " \t "; |
- |
- HttpUtil::ValuesIterator it(values.begin(), values.end(), ','); |
- |
- EXPECT_FALSE(it.GetNext()); |
-} |
- |
-TEST(HttpUtilTest, Unquote) { |
- // Replace <backslash> " with ". |
- EXPECT_STREQ("xyz\"abc", HttpUtil::Unquote("\"xyz\\\"abc\"").c_str()); |
- |
- // Replace <backslash> <backslash> with <backslash> |
- EXPECT_STREQ("xyz\\abc", HttpUtil::Unquote("\"xyz\\\\abc\"").c_str()); |
- EXPECT_STREQ("xyz\\\\\\abc", |
- HttpUtil::Unquote("\"xyz\\\\\\\\\\\\abc\"").c_str()); |
- |
- // Replace <backslash> X with X |
- EXPECT_STREQ("xyzXabc", HttpUtil::Unquote("\"xyz\\Xabc\"").c_str()); |
- |
- // Act as identity function on unquoted inputs. |
- EXPECT_STREQ("X", HttpUtil::Unquote("X").c_str()); |
- EXPECT_STREQ("\"", HttpUtil::Unquote("\"").c_str()); |
- |
- // Allow single quotes to act as quote marks. |
- // Not part of RFC 2616. |
- EXPECT_STREQ("x\"", HttpUtil::Unquote("'x\"'").c_str()); |
-} |
- |
-TEST(HttpUtilTest, Quote) { |
- EXPECT_STREQ("\"xyz\\\"abc\"", HttpUtil::Quote("xyz\"abc").c_str()); |
- |
- // Replace <backslash> <backslash> with <backslash> |
- EXPECT_STREQ("\"xyz\\\\abc\"", HttpUtil::Quote("xyz\\abc").c_str()); |
- |
- // Replace <backslash> X with X |
- EXPECT_STREQ("\"xyzXabc\"", HttpUtil::Quote("xyzXabc").c_str()); |
-} |
- |
-TEST(HttpUtilTest, LocateEndOfHeaders) { |
- struct { |
- const char* const input; |
- int expected_result; |
- } tests[] = { |
- { "foo\r\nbar\r\n\r\n", 12 }, |
- { "foo\nbar\n\n", 9 }, |
- { "foo\r\nbar\r\n\r\njunk", 12 }, |
- { "foo\nbar\n\njunk", 9 }, |
- { "foo\nbar\n\r\njunk", 10 }, |
- { "foo\nbar\r\n\njunk", 10 }, |
- }; |
- for (size_t i = 0; i < arraysize(tests); ++i) { |
- int input_len = static_cast<int>(strlen(tests[i].input)); |
- int eoh = HttpUtil::LocateEndOfHeaders(tests[i].input, input_len); |
- EXPECT_EQ(tests[i].expected_result, eoh); |
- } |
-} |
- |
-TEST(HttpUtilTest, AssembleRawHeaders) { |
- struct { |
- const char* const input; // with '|' representing '\0' |
- const char* const expected_result; // with '\0' changed to '|' |
- } tests[] = { |
- { "HTTP/1.0 200 OK\r\nFoo: 1\r\nBar: 2\r\n\r\n", |
- "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" }, |
- |
- { "HTTP/1.0 200 OK\nFoo: 1\nBar: 2\n\n", |
- "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" }, |
- |
- // Valid line continuation (single SP). |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- " continuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1 continuation|" |
- "Bar: 2||" |
- }, |
- |
- // Valid line continuation (single HT). |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- "\tcontinuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1 continuation|" |
- "Bar: 2||" |
- }, |
- |
- // Valid line continuation (multiple SP). |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- " continuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1 continuation|" |
- "Bar: 2||" |
- }, |
- |
- // Valid line continuation (multiple HT). |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- "\t\t\tcontinuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1 continuation|" |
- "Bar: 2||" |
- }, |
- |
- // Valid line continuation (mixed HT, SP). |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- " \t \t continuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1 continuation|" |
- "Bar: 2||" |
- }, |
- |
- // Valid multi-line continuation |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- " continuation1\n" |
- "\tcontinuation2\n" |
- " continuation3\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1 continuation1 continuation2 continuation3|" |
- "Bar: 2||" |
- }, |
- |
- // Continuation of quoted value. |
- // This is different from what Firefox does, since it |
- // will preserve the LWS. |
- { |
- "HTTP/1.0 200 OK\n" |
- "Etag: \"34534-d3\n" |
- " 134q\"\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Etag: \"34534-d3 134q\"|" |
- "Bar: 2||" |
- }, |
- |
- // Valid multi-line continuation, full LWS lines |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- " \n" |
- "\t\t\t\t\n" |
- "\t continuation\n" |
- "Bar: 2\n\n", |
- |
- // One SP per continued line = 3. |
- "HTTP/1.0 200 OK|" |
- "Foo: 1 continuation|" |
- "Bar: 2||" |
- }, |
- |
- // Valid multi-line continuation, all LWS |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- " \n" |
- "\t\t\t\t\n" |
- "\t \n" |
- "Bar: 2\n\n", |
- |
- // One SP per continued line = 3. |
- "HTTP/1.0 200 OK|" |
- "Foo: 1 |" |
- "Bar: 2||" |
- }, |
- |
- // Valid line continuation (No value bytes in first line). |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo:\n" |
- " value\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: value|" |
- "Bar: 2||" |
- }, |
- |
- // Not a line continuation (can't continue status line). |
- { |
- "HTTP/1.0 200 OK\n" |
- " Foo: 1\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- " Foo: 1|" |
- "Bar: 2||" |
- }, |
- |
- // Not a line continuation (can't continue status line). |
- { |
- "HTTP/1.0\n" |
- " 200 OK\n" |
- "Foo: 1\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0|" |
- " 200 OK|" |
- "Foo: 1|" |
- "Bar: 2||" |
- }, |
- |
- // Not a line continuation (can't continue status line). |
- { |
- "HTTP/1.0 404\n" |
- " Not Found\n" |
- "Foo: 1\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 404|" |
- " Not Found|" |
- "Foo: 1|" |
- "Bar: 2||" |
- }, |
- |
- // Unterminated status line. |
- { |
- "HTTP/1.0 200 OK", |
- |
- "HTTP/1.0 200 OK||" |
- }, |
- |
- // Single terminated, with headers |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- "Bar: 2\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1|" |
- "Bar: 2||" |
- }, |
- |
- // Not terminated, with headers |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- "Bar: 2", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1|" |
- "Bar: 2||" |
- }, |
- |
- // Not a line continuation (VT) |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- "\vInvalidContinuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1|" |
- "\vInvalidContinuation|" |
- "Bar: 2||" |
- }, |
- |
- // Not a line continuation (formfeed) |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- "\fInvalidContinuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1|" |
- "\fInvalidContinuation|" |
- "Bar: 2||" |
- }, |
- |
- // Not a line continuation -- can't continue header names. |
- { |
- "HTTP/1.0 200 OK\n" |
- "Serv\n" |
- " er: Apache\n" |
- "\tInvalidContinuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Serv|" |
- " er: Apache|" |
- "\tInvalidContinuation|" |
- "Bar: 2||" |
- }, |
- |
- // Not a line continuation -- no value to continue. |
- { |
- "HTTP/1.0 200 OK\n" |
- "Foo: 1\n" |
- "garbage\n" |
- " not-a-continuation\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- "Foo: 1|" |
- "garbage|" |
- " not-a-continuation|" |
- "Bar: 2||", |
- }, |
- |
- // Not a line continuation -- no valid name. |
- { |
- "HTTP/1.0 200 OK\n" |
- ": 1\n" |
- " garbage\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- ": 1|" |
- " garbage|" |
- "Bar: 2||", |
- }, |
- |
- // Not a line continuation -- no valid name (whitespace) |
- { |
- "HTTP/1.0 200 OK\n" |
- " : 1\n" |
- " garbage\n" |
- "Bar: 2\n\n", |
- |
- "HTTP/1.0 200 OK|" |
- " : 1|" |
- " garbage|" |
- "Bar: 2||", |
- }, |
- |
- // Embed NULLs in the status line. They should not be understood |
- // as line separators. |
- { |
- "HTTP/1.0 200 OK|Bar2:0|Baz2:1\r\nFoo: 1\r\nBar: 2\r\n\r\n", |
- "HTTP/1.0 200 OKBar2:0Baz2:1|Foo: 1|Bar: 2||" |
- }, |
- |
- // Embed NULLs in a header line. They should not be understood as |
- // line separators. |
- { |
- "HTTP/1.0 200 OK\nFoo: 1|Foo2: 3\nBar: 2\n\n", |
- "HTTP/1.0 200 OK|Foo: 1Foo2: 3|Bar: 2||" |
- }, |
- }; |
- for (size_t i = 0; i < arraysize(tests); ++i) { |
- std::string input = tests[i].input; |
- std::replace(input.begin(), input.end(), '|', '\0'); |
- std::string raw = HttpUtil::AssembleRawHeaders(input.data(), input.size()); |
- std::replace(raw.begin(), raw.end(), '\0', '|'); |
- EXPECT_EQ(tests[i].expected_result, raw); |
- } |
-} |
- |
-// Test SpecForRequest() and PathForRequest(). |
-TEST(HttpUtilTest, RequestUrlSanitize) { |
- struct { |
- const char* const url; |
- const char* const expected_spec; |
- const char* const expected_path; |
- } tests[] = { |
- { // Check that #hash is removed. |
- "http://www.google.com:78/foobar?query=1#hash", |
- "http://www.google.com:78/foobar?query=1", |
- "/foobar?query=1" |
- }, |
- { // The reference may itself contain # -- strip all of it. |
- "http://192.168.0.1?query=1#hash#10#11#13#14", |
- "http://192.168.0.1/?query=1", |
- "/?query=1" |
- }, |
- { // Strip username/password. |
- "http://user:pass@google.com", |
- "http://google.com/", |
- "/" |
- }, |
- { // https scheme |
- "https://www.google.com:78/foobar?query=1#hash", |
- "https://www.google.com:78/foobar?query=1", |
- "/foobar?query=1" |
- }, |
- { // WebSocket's ws scheme |
- "ws://www.google.com:78/foobar?query=1#hash", |
- "ws://www.google.com:78/foobar?query=1", |
- "/foobar?query=1" |
- }, |
- { // WebSocket's wss scheme |
- "wss://www.google.com:78/foobar?query=1#hash", |
- "wss://www.google.com:78/foobar?query=1", |
- "/foobar?query=1" |
- } |
- }; |
- for (size_t i = 0; i < arraysize(tests); ++i) { |
- GURL url(GURL(tests[i].url)); |
- std::string expected_spec(tests[i].expected_spec); |
- std::string expected_path(tests[i].expected_path); |
- |
- EXPECT_EQ(expected_spec, HttpUtil::SpecForRequest(url)); |
- EXPECT_EQ(expected_path, HttpUtil::PathForRequest(url)); |
- } |
-} |
- |
-// Test SpecForRequest() for "ftp" scheme. |
-TEST(HttpUtilTest, SpecForRequestForUrlWithFtpScheme) { |
- GURL ftp_url("ftp://user:pass@google.com/pub/chromium/"); |
- EXPECT_EQ("ftp://google.com/pub/chromium/", |
- HttpUtil::SpecForRequest(ftp_url)); |
-} |
- |
-TEST(HttpUtilTest, GenerateAcceptLanguageHeader) { |
- EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6"), |
- HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de")); |
- EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6,ko;q=0.4,zh-CN;q=0.2," |
- "ja;q=0.2"), |
- HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de,ko,zh-CN,ja")); |
-} |
- |
-// HttpResponseHeadersTest.GetMimeType also tests ParseContentType. |
-TEST(HttpUtilTest, ParseContentType) { |
- const struct { |
- const char* const content_type; |
- const char* const expected_mime_type; |
- const char* const expected_charset; |
- const bool expected_had_charset; |
- const char* const expected_boundary; |
- } tests[] = { |
- { "text/html; charset=utf-8", |
- "text/html", |
- "utf-8", |
- true, |
- "" |
- }, |
- { "text/html; charset =utf-8", |
- "text/html", |
- "utf-8", |
- true, |
- "" |
- }, |
- { "text/html; charset= utf-8", |
- "text/html", |
- "utf-8", |
- true, |
- "" |
- }, |
- { "text/html; charset=utf-8 ", |
- "text/html", |
- "utf-8", |
- true, |
- "" |
- }, |
- { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs\"", |
- "text/html", |
- "", |
- false, |
- "\"WebKit-ada-df-dsf-adsfadsfs\"" |
- }, |
- { "text/html; boundary =\"WebKit-ada-df-dsf-adsfadsfs\"", |
- "text/html", |
- "", |
- false, |
- "\"WebKit-ada-df-dsf-adsfadsfs\"" |
- }, |
- { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\"", |
- "text/html", |
- "", |
- false, |
- "\"WebKit-ada-df-dsf-adsfadsfs\"" |
- }, |
- { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\" ", |
- "text/html", |
- "", |
- false, |
- "\"WebKit-ada-df-dsf-adsfadsfs\"" |
- }, |
- { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs \"", |
- "text/html", |
- "", |
- false, |
- "\"WebKit-ada-df-dsf-adsfadsfs \"" |
- }, |
- { "text/html; boundary=WebKit-ada-df-dsf-adsfadsfs", |
- "text/html", |
- "", |
- false, |
- "WebKit-ada-df-dsf-adsfadsfs" |
- }, |
- // TODO(abarth): Add more interesting test cases. |
- }; |
- for (size_t i = 0; i < arraysize(tests); ++i) { |
- std::string mime_type; |
- std::string charset; |
- bool had_charset = false; |
- std::string boundary; |
- net::HttpUtil::ParseContentType(tests[i].content_type, &mime_type, |
- &charset, &had_charset, &boundary); |
- EXPECT_EQ(tests[i].expected_mime_type, mime_type) << "i=" << i; |
- EXPECT_EQ(tests[i].expected_charset, charset) << "i=" << i; |
- EXPECT_EQ(tests[i].expected_had_charset, had_charset) << "i=" << i; |
- EXPECT_EQ(tests[i].expected_boundary, boundary) << "i=" << i; |
- } |
-} |
- |
-TEST(HttpUtilTest, ParseRanges) { |
- const struct { |
- const char* const headers; |
- bool expected_return_value; |
- size_t expected_ranges_size; |
- const struct { |
- int64 expected_first_byte_position; |
- int64 expected_last_byte_position; |
- int64 expected_suffix_length; |
- } expected_ranges[10]; |
- } tests[] = { |
- { "Range: bytes=0-10", |
- true, |
- 1, |
- { {0, 10, -1}, } |
- }, |
- { "Range: bytes=10-0", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: BytES=0-10", |
- true, |
- 1, |
- { {0, 10, -1}, } |
- }, |
- { "Range: megabytes=0-10", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: bytes0-10", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: bytes=0-0,0-10,10-20,100-200,100-,-200", |
- true, |
- 6, |
- { {0, 0, -1}, |
- {0, 10, -1}, |
- {10, 20, -1}, |
- {100, 200, -1}, |
- {100, -1, -1}, |
- {-1, -1, 200}, |
- } |
- }, |
- { "Range: bytes=0-10\r\n" |
- "Range: bytes=0-10,10-20,100-200,100-,-200", |
- true, |
- 1, |
- { {0, 10, -1} |
- } |
- }, |
- { "Range: bytes=", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: bytes=-", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: bytes=0-10-", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: bytes=-0-10", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: bytes =0-10\r\n", |
- true, |
- 1, |
- { {0, 10, -1} |
- } |
- }, |
- { "Range: bytes= 0-10 \r\n", |
- true, |
- 1, |
- { {0, 10, -1} |
- } |
- }, |
- { "Range: bytes = 0 - 10 \r\n", |
- true, |
- 1, |
- { {0, 10, -1} |
- } |
- }, |
- { "Range: bytes= 0-1 0\r\n", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: bytes= 0- -10\r\n", |
- false, |
- 0, |
- {} |
- }, |
- { "Range: bytes= 0 - 1 , 10 -20, 100- 200 , 100-, -200 \r\n", |
- true, |
- 5, |
- { {0, 1, -1}, |
- {10, 20, -1}, |
- {100, 200, -1}, |
- {100, -1, -1}, |
- {-1, -1, 200}, |
- } |
- }, |
- }; |
- |
- for (size_t i = 0; i < arraysize(tests); ++i) { |
- std::vector<net::HttpByteRange> ranges; |
- bool return_value = HttpUtil::ParseRanges(std::string(tests[i].headers), |
- &ranges); |
- EXPECT_EQ(tests[i].expected_return_value, return_value); |
- if (return_value) { |
- EXPECT_EQ(tests[i].expected_ranges_size, ranges.size()); |
- for (size_t j = 0; j < ranges.size(); ++j) { |
- EXPECT_EQ(tests[i].expected_ranges[j].expected_first_byte_position, |
- ranges[j].first_byte_position()); |
- EXPECT_EQ(tests[i].expected_ranges[j].expected_last_byte_position, |
- ranges[j].last_byte_position()); |
- EXPECT_EQ(tests[i].expected_ranges[j].expected_suffix_length, |
- ranges[j].suffix_length()); |
- } |
- } |
- } |
-} |
- |
-TEST(HttpUtilTest, ParseRetryAfterHeader) { |
- base::Time::Exploded now_exploded = { 2014, 11, -1, 5, 22, 39, 30, 0 }; |
- base::Time now = base::Time::FromUTCExploded(now_exploded); |
- |
- base::Time::Exploded later_exploded = { 2015, 1, -1, 1, 12, 34, 56, 0 }; |
- base::Time later = base::Time::FromUTCExploded(later_exploded); |
- |
- const struct { |
- const char* retry_after_string; |
- bool expected_return_value; |
- base::TimeDelta expected_retry_after; |
- } tests[] = { |
- { "", false, base::TimeDelta() }, |
- { "-3", false, base::TimeDelta() }, |
- { "-2", false, base::TimeDelta() }, |
- { "-1", false, base::TimeDelta() }, |
- { "0", true, base::TimeDelta::FromSeconds(0) }, |
- { "1", true, base::TimeDelta::FromSeconds(1) }, |
- { "2", true, base::TimeDelta::FromSeconds(2) }, |
- { "3", true, base::TimeDelta::FromSeconds(3) }, |
- { "60", true, base::TimeDelta::FromSeconds(60) }, |
- { "3600", true, base::TimeDelta::FromSeconds(3600) }, |
- { "86400", true, base::TimeDelta::FromSeconds(86400) }, |
- { "Thu, 1 Jan 2015 12:34:56 GMT", true, later - now }, |
- { "Mon, 1 Jan 1900 12:34:56 GMT", false, base::TimeDelta() } |
- }; |
- |
- for (size_t i = 0; i < arraysize(tests); ++i) { |
- base::TimeDelta retry_after; |
- bool return_value = HttpUtil::ParseRetryAfterHeader( |
- tests[i].retry_after_string, now, &retry_after); |
- EXPECT_EQ(tests[i].expected_return_value, return_value) |
- << "Test case " << i << ": expected " << tests[i].expected_return_value |
- << " but got " << return_value << "."; |
- if (tests[i].expected_return_value && return_value) { |
- EXPECT_EQ(tests[i].expected_retry_after, retry_after) |
- << "Test case " << i << ": expected " |
- << tests[i].expected_retry_after.InSeconds() << "s but got " |
- << retry_after.InSeconds() << "s."; |
- } |
- } |
-} |
- |
-namespace { |
-void CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator* parser, |
- bool expect_valid, |
- std::string expected_name, |
- std::string expected_value) { |
- ASSERT_EQ(expect_valid, parser->valid()); |
- if (!expect_valid) { |
- return; |
- } |
- |
- // Let's make sure that these never change (i.e., when a quoted value is |
- // unquoted, it should be cached on the first calls and not regenerated |
- // later). |
- std::string::const_iterator first_value_begin = parser->value_begin(); |
- std::string::const_iterator first_value_end = parser->value_end(); |
- |
- ASSERT_EQ(expected_name, std::string(parser->name_begin(), |
- parser->name_end())); |
- ASSERT_EQ(expected_name, parser->name()); |
- ASSERT_EQ(expected_value, std::string(parser->value_begin(), |
- parser->value_end())); |
- ASSERT_EQ(expected_value, parser->value()); |
- |
- // Make sure they didn't/don't change. |
- ASSERT_TRUE(first_value_begin == parser->value_begin()); |
- ASSERT_TRUE(first_value_end == parser->value_end()); |
-} |
- |
-void CheckNextNameValuePair(HttpUtil::NameValuePairsIterator* parser, |
- bool expect_next, |
- bool expect_valid, |
- std::string expected_name, |
- std::string expected_value) { |
- ASSERT_EQ(expect_next, parser->GetNext()); |
- ASSERT_EQ(expect_valid, parser->valid()); |
- if (!expect_next || !expect_valid) { |
- return; |
- } |
- |
- CheckCurrentNameValuePair(parser, |
- expect_valid, |
- expected_name, |
- expected_value); |
-} |
- |
-void CheckInvalidNameValuePair(std::string valid_part, |
- std::string invalid_part) { |
- std::string whole_string = valid_part + invalid_part; |
- |
- HttpUtil::NameValuePairsIterator valid_parser(valid_part.begin(), |
- valid_part.end(), |
- ';'); |
- HttpUtil::NameValuePairsIterator invalid_parser(whole_string.begin(), |
- whole_string.end(), |
- ';'); |
- |
- ASSERT_TRUE(valid_parser.valid()); |
- ASSERT_TRUE(invalid_parser.valid()); |
- |
- // Both parsers should return all the same values until "valid_parser" is |
- // exhausted. |
- while (valid_parser.GetNext()) { |
- ASSERT_TRUE(invalid_parser.GetNext()); |
- ASSERT_TRUE(valid_parser.valid()); |
- ASSERT_TRUE(invalid_parser.valid()); |
- ASSERT_EQ(valid_parser.name(), invalid_parser.name()); |
- ASSERT_EQ(valid_parser.value(), invalid_parser.value()); |
- } |
- |
- // valid_parser is exhausted and remains 'valid' |
- ASSERT_TRUE(valid_parser.valid()); |
- |
- // invalid_parser's corresponding call to GetNext also returns false... |
- ASSERT_FALSE(invalid_parser.GetNext()); |
- // ...but the parser is in an invalid state. |
- ASSERT_FALSE(invalid_parser.valid()); |
-} |
- |
-} // anonymous namespace |
- |
-TEST(HttpUtilTest, NameValuePairsIteratorCopyAndAssign) { |
- std::string data = "alpha='\\'a\\''; beta=\" b \"; cappa='c;'; delta=\"d\""; |
- HttpUtil::NameValuePairsIterator parser_a(data.begin(), data.end(), ';'); |
- |
- EXPECT_TRUE(parser_a.valid()); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser_a, true, true, "alpha", "'a'")); |
- |
- HttpUtil::NameValuePairsIterator parser_b(parser_a); |
- // a and b now point to same location |
- ASSERT_NO_FATAL_FAILURE( |
- CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckCurrentNameValuePair(&parser_a, true, "alpha", "'a'")); |
- |
- // advance a, no effect on b |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser_a, true, true, "beta", " b ")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'")); |
- |
- // assign b the current state of a, no effect on a |
- parser_b = parser_a; |
- ASSERT_NO_FATAL_FAILURE( |
- CheckCurrentNameValuePair(&parser_b, true, "beta", " b ")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckCurrentNameValuePair(&parser_a, true, "beta", " b ")); |
- |
- // advance b, no effect on a |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser_b, true, true, "cappa", "c;")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckCurrentNameValuePair(&parser_a, true, "beta", " b ")); |
-} |
- |
-TEST(HttpUtilTest, NameValuePairsIteratorEmptyInput) { |
- std::string data; |
- HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); |
- |
- EXPECT_TRUE(parser.valid()); |
- ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair( |
- &parser, false, true, std::string(), std::string())); |
-} |
- |
-TEST(HttpUtilTest, NameValuePairsIterator) { |
- std::string data = "alpha=1; beta= 2 ;cappa =' 3; ';" |
- "delta= \" \\\"4\\\" \"; e= \" '5'\"; e=6;" |
- "f='\\'\\h\\e\\l\\l\\o\\ \\w\\o\\r\\l\\d\\'';" |
- "g=''; h='hello'"; |
- HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); |
- EXPECT_TRUE(parser.valid()); |
- |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "alpha", "1")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "beta", "2")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "cappa", " 3; ")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "delta", " \"4\" ")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "e", " '5'")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "e", "6")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "f", "'hello world'")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "g", std::string())); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "h", "hello")); |
- ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair( |
- &parser, false, true, std::string(), std::string())); |
-} |
- |
-TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) { |
- ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; beta")); |
- ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "beta")); |
- |
- ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; 'beta'=2")); |
- ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "'beta'=2")); |
- ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";beta=")); |
- ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", |
- ";beta=;cappa=2")); |
- |
- // According to the spec this is an error, but it doesn't seem appropriate to |
- // change our behaviour to be less permissive at this time. |
- // See NameValuePairsIteratorExtraSeparators test |
- // ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";; beta=2")); |
-} |
- |
-// If we are going to support extra separators against the spec, let's just make |
-// sure they work rationally. |
-TEST(HttpUtilTest, NameValuePairsIteratorExtraSeparators) { |
- std::string data = " ; ;;alpha=1; ;; ; beta= 2;cappa=3;;; ; "; |
- HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); |
- EXPECT_TRUE(parser.valid()); |
- |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "alpha", "1")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "beta", "2")); |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "cappa", "3")); |
- ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair( |
- &parser, false, true, std::string(), std::string())); |
-} |
- |
-// See comments on the implementation of NameValuePairsIterator::GetNext |
-// regarding this derogation from the spec. |
-TEST(HttpUtilTest, NameValuePairsIteratorMissingEndQuote) { |
- std::string data = "name='value"; |
- HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); |
- EXPECT_TRUE(parser.valid()); |
- |
- ASSERT_NO_FATAL_FAILURE( |
- CheckNextNameValuePair(&parser, true, true, "name", "value")); |
- ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair( |
- &parser, false, true, std::string(), std::string())); |
-} |