OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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 <cmath> |
| 6 #include <ctime> |
| 7 #include <map> |
| 8 #include <string> |
| 9 #include <vector> |
| 10 |
| 11 #include "base/rand_util.h" |
| 12 #include "net/spdy/hpack_constants.h" |
| 13 #include "net/spdy/hpack_decoder.h" |
| 14 #include "net/spdy/hpack_encoder.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 |
| 17 namespace net { |
| 18 |
| 19 using std::map; |
| 20 using std::string; |
| 21 using std::vector; |
| 22 |
| 23 namespace { |
| 24 |
| 25 class HpackRoundTripTest : public ::testing::Test { |
| 26 protected: |
| 27 HpackRoundTripTest() |
| 28 : encoder_(ObtainHpackHuffmanTable()), |
| 29 decoder_(ObtainHpackHuffmanTable()) {} |
| 30 |
| 31 virtual void SetUp() { |
| 32 // Use a small table size to tickle eviction handling. |
| 33 encoder_.ApplyHeaderTableSizeSetting(256); |
| 34 decoder_.ApplyHeaderTableSizeSetting(256); |
| 35 } |
| 36 |
| 37 bool RoundTrip(const map<string, string>& header_set) { |
| 38 string encoded; |
| 39 encoder_.EncodeHeaderSet(header_set, &encoded); |
| 40 |
| 41 bool success = decoder_.HandleControlFrameHeadersData( |
| 42 1, encoded.data(), encoded.size()); |
| 43 success &= decoder_.HandleControlFrameHeadersComplete(1); |
| 44 |
| 45 EXPECT_EQ(header_set, decoder_.decoded_block()); |
| 46 return success; |
| 47 } |
| 48 |
| 49 size_t SampleExponential(size_t mean, size_t sanity_bound) { |
| 50 return std::min<size_t>(-std::log(base::RandDouble()) * mean, |
| 51 sanity_bound); |
| 52 } |
| 53 |
| 54 HpackEncoder encoder_; |
| 55 HpackDecoder decoder_; |
| 56 }; |
| 57 |
| 58 TEST_F(HpackRoundTripTest, ResponseFixtures) { |
| 59 { |
| 60 map<string, string> headers; |
| 61 headers[":status"] = "302"; |
| 62 headers["cache-control"] = "private"; |
| 63 headers["date"] = "Mon, 21 Oct 2013 20:13:21 GMT"; |
| 64 headers["location"] = "https://www.example.com"; |
| 65 EXPECT_TRUE(RoundTrip(headers)); |
| 66 } |
| 67 { |
| 68 map<string, string> headers; |
| 69 headers[":status"] = "200"; |
| 70 headers["cache-control"] = "private"; |
| 71 headers["date"] = "Mon, 21 Oct 2013 20:13:21 GMT"; |
| 72 headers["location"] = "https://www.example.com"; |
| 73 EXPECT_TRUE(RoundTrip(headers)); |
| 74 } |
| 75 { |
| 76 map<string, string> headers; |
| 77 headers[":status"] = "200"; |
| 78 headers["cache-control"] = "private"; |
| 79 headers["content-encoding"] = "gzip"; |
| 80 headers["date"] = "Mon, 21 Oct 2013 20:13:22 GMT"; |
| 81 headers["location"] = "https://www.example.com"; |
| 82 headers["set-cookie"] = "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" |
| 83 " max-age=3600; version=1"; |
| 84 EXPECT_TRUE(RoundTrip(headers)); |
| 85 } |
| 86 } |
| 87 |
| 88 TEST_F(HpackRoundTripTest, RequestFixtures) { |
| 89 { |
| 90 map<string, string> headers; |
| 91 headers[":authority"] = "www.example.com"; |
| 92 headers[":method"] = "GET"; |
| 93 headers[":path"] = "/"; |
| 94 headers[":scheme"] = "http"; |
| 95 headers["cookie"] = "baz=bing; foo=bar"; |
| 96 EXPECT_TRUE(RoundTrip(headers)); |
| 97 } |
| 98 { |
| 99 map<string, string> headers; |
| 100 headers[":authority"] = "www.example.com"; |
| 101 headers[":method"] = "GET"; |
| 102 headers[":path"] = "/"; |
| 103 headers[":scheme"] = "http"; |
| 104 headers["cache-control"] = "no-cache"; |
| 105 headers["cookie"] = "fizzle=fazzle; foo=bar"; |
| 106 EXPECT_TRUE(RoundTrip(headers)); |
| 107 } |
| 108 { |
| 109 map<string, string> headers; |
| 110 headers[":authority"] = "www.example.com"; |
| 111 headers[":method"] = "GET"; |
| 112 headers[":path"] = "/index.html"; |
| 113 headers[":scheme"] = "https"; |
| 114 headers["custom-key"] = "custom-value"; |
| 115 headers["cookie"] = "baz=bing; fizzle=fazzle; garbage"; |
| 116 EXPECT_TRUE(RoundTrip(headers)); |
| 117 } |
| 118 } |
| 119 |
| 120 TEST_F(HpackRoundTripTest, RandomizedExamples) { |
| 121 // Grow vectors of names & values, which are seeded with fixtures and then |
| 122 // expanded with dynamically generated data. Samples are taken using the |
| 123 // exponential distribution. |
| 124 vector<string> names; |
| 125 names.push_back(":authority"); |
| 126 names.push_back(":path"); |
| 127 names.push_back(":status"); |
| 128 // TODO(jgraettinger): Enable "cookie" as a name fixture. Crumbs may be |
| 129 // reconstructed in any order, which breaks the simple validation used here. |
| 130 |
| 131 vector<string> values; |
| 132 values.push_back("/"); |
| 133 values.push_back("/index.html"); |
| 134 values.push_back("200"); |
| 135 values.push_back("404"); |
| 136 values.push_back(""); |
| 137 values.push_back("baz=bing; foo=bar; garbage"); |
| 138 values.push_back("baz=bing; fizzle=fazzle; garbage"); |
| 139 |
| 140 int seed = std::time(NULL); |
| 141 LOG(INFO) << "Seeding with srand(" << seed << ")"; |
| 142 srand(seed); |
| 143 |
| 144 for (size_t i = 0; i != 2000; ++i) { |
| 145 map<string, string> headers; |
| 146 |
| 147 size_t header_count = 1 + SampleExponential(7, 50); |
| 148 for (size_t j = 0; j != header_count; ++j) { |
| 149 size_t name_index = SampleExponential(20, 200); |
| 150 size_t value_index = SampleExponential(20, 200); |
| 151 |
| 152 string name, value; |
| 153 if (name_index >= names.size()) { |
| 154 names.push_back(base::RandBytesAsString(1 + SampleExponential(5, 30))); |
| 155 name = names.back(); |
| 156 } else { |
| 157 name = names[name_index]; |
| 158 } |
| 159 if (value_index >= values.size()) { |
| 160 values.push_back(base::RandBytesAsString( |
| 161 1 + SampleExponential(15, 75))); |
| 162 value = values.back(); |
| 163 } else { |
| 164 value = values[value_index]; |
| 165 } |
| 166 headers[name] = value; |
| 167 } |
| 168 EXPECT_TRUE(RoundTrip(headers)); |
| 169 } |
| 170 } |
| 171 |
| 172 } // namespace |
| 173 |
| 174 } // namespace net |
OLD | NEW |