112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org// Copyright 2014 The Chromium Authors. All rights reserved. 212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org// Use of this source code is governed by a BSD-style license that can be 312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org// found in the LICENSE file. 412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include <cmath> 612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include <ctime> 712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include <map> 812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include <string> 912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include <vector> 1012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 1112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include "base/rand_util.h" 1212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include "net/spdy/hpack_constants.h" 1312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include "net/spdy/hpack_decoder.h" 1412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include "net/spdy/hpack_encoder.h" 1512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include "testing/gtest/include/gtest/gtest.h" 1612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 1712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgnamespace net { 1812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 1912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgusing std::map; 2012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgusing std::string; 2112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgusing std::vector; 2212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 2312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgnamespace { 2412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 2512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgclass HpackRoundTripTest : public ::testing::Test { 2612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org protected: 2712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org HpackRoundTripTest() 2812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org : encoder_(ObtainHpackHuffmanTable()), 2912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org decoder_(ObtainHpackHuffmanTable()) {} 3012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 3112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org virtual void SetUp() { 3212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // Use a small table size to tickle eviction handling. 3312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org encoder_.ApplyHeaderTableSizeSetting(256); 3412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org decoder_.ApplyHeaderTableSizeSetting(256); 3512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 3612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 3712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org bool RoundTrip(const map<string, string>& header_set) { 3812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org string encoded; 3912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org encoder_.EncodeHeaderSet(header_set, &encoded); 4012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 4112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org bool success = decoder_.HandleControlFrameHeadersData( 4212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 1, encoded.data(), encoded.size()); 4312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org success &= decoder_.HandleControlFrameHeadersComplete(1); 4412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 4512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org EXPECT_EQ(header_set, decoder_.decoded_block()); 4612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org return success; 4712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 4812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 4912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org size_t SampleExponential(size_t mean, size_t sanity_bound) { 5012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org return std::min<size_t>(-std::log(base::RandDouble()) * mean, 5112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org sanity_bound); 5212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 5312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 5412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org HpackEncoder encoder_; 5512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org HpackDecoder decoder_; 5612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org}; 5712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 5812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgTEST_F(HpackRoundTripTest, ResponseFixtures) { 5912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org { 6012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org map<string, string> headers; 6112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":status"] = "302"; 6212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["cache-control"] = "private"; 6312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["date"] = "Mon, 21 Oct 2013 20:13:21 GMT"; 6412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["location"] = "https://www.example.com"; 6512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org EXPECT_TRUE(RoundTrip(headers)); 6612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 6712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org { 6812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org map<string, string> headers; 6912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":status"] = "200"; 70e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org headers["cache-control"] = "private"; 7112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["date"] = "Mon, 21 Oct 2013 20:13:21 GMT"; 7212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["location"] = "https://www.example.com"; 7312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org EXPECT_TRUE(RoundTrip(headers)); 7412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 7512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org { 7612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org map<string, string> headers; 7712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":status"] = "200"; 7812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["cache-control"] = "private"; 7912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["content-encoding"] = "gzip"; 8012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["date"] = "Mon, 21 Oct 2013 20:13:22 GMT"; 8112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["location"] = "https://www.example.com"; 8212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["set-cookie"] = "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" 8312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org " max-age=3600; version=1"; 8412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["multivalue"] = string("foo\0bar", 7); 8512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org EXPECT_TRUE(RoundTrip(headers)); 8612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 8712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org} 8812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 8912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgTEST_F(HpackRoundTripTest, RequestFixtures) { 9012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org { 9112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org map<string, string> headers; 9212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":authority"] = "www.example.com"; 9312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":method"] = "GET"; 9412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":path"] = "/"; 9512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":scheme"] = "http"; 9612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["cookie"] = "baz=bing; foo=bar"; 9712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org EXPECT_TRUE(RoundTrip(headers)); 9812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 9912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org { 10012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org map<string, string> headers; 10112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":authority"] = "www.example.com"; 10212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":method"] = "GET"; 10312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":path"] = "/"; 10412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":scheme"] = "http"; 10512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["cache-control"] = "no-cache"; 10612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["cookie"] = "foo=bar; fizzle=fazzle"; 10712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org EXPECT_TRUE(RoundTrip(headers)); 10812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 10912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org { 11012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org map<string, string> headers; 11112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":authority"] = "www.example.com"; 11212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":method"] = "GET"; 11312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":path"] = "/index.html"; 11412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[":scheme"] = "https"; 115e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org headers["custom-key"] = "custom-value"; 11612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["cookie"] = "baz=bing; fizzle=fazzle; garbage"; 11712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers["multivalue"] = string("foo\0bar", 7); 11812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org EXPECT_TRUE(RoundTrip(headers)); 11912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 12012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org} 12112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 12212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.orgTEST_F(HpackRoundTripTest, RandomizedExamples) { 12312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // Grow vectors of names & values, which are seeded with fixtures and then 12412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // expanded with dynamically generated data. Samples are taken using the 12512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // exponential distribution. 12612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org vector<string> names; 12712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org names.push_back(":authority"); 12812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org names.push_back(":path"); 12912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org names.push_back(":status"); 13012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // TODO(jgraettinger): Enable "cookie" as a name fixture. Crumbs may be 13112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // reconstructed in any order, which breaks the simple validation used here. 13212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 13312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org vector<string> values; 13412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org values.push_back("/"); 13512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org values.push_back("/index.html"); 13612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org values.push_back("200"); 13712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org values.push_back("404"); 13812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org values.push_back(""); 13912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org values.push_back("baz=bing; foo=bar; garbage"); 14012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org values.push_back("baz=bing; fizzle=fazzle; garbage"); 14112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 14212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org int seed = std::time(NULL); 14312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org LOG(INFO) << "Seeding with srand(" << seed << ")"; 14412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org srand(seed); 14512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 14612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org for (size_t i = 0; i != 2000; ++i) { 14712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org map<string, string> headers; 14812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 14912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org size_t header_count = 1 + SampleExponential(7, 50); 15012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org for (size_t j = 0; j != header_count; ++j) { 15112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org size_t name_index = SampleExponential(20, 200); 15212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org size_t value_index = SampleExponential(20, 200); 15312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 15412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org string name, value; 155e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org if (name_index >= names.size()) { 15612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org names.push_back(base::RandBytesAsString(1 + SampleExponential(5, 30))); 15712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org name = names.back(); 15812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } else { 15912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org name = names[name_index]; 16012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 16112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org if (value_index >= values.size()) { 16212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org string newvalue = 16312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org base::RandBytesAsString(1 + SampleExponential(15, 75)); 16412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // Currently order is not preserved in the encoder. In particular, 16512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // when a value is decomposed at \0 delimiters, its parts might get 16612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // encoded out of order if some but not all of them already exist in 16712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org // the header table. For now, avoid \0 bytes in values. 16812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org std::replace(newvalue.begin(), newvalue.end(), '\x00', '\x01'); 16912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org values.push_back(newvalue); 17012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org value = values.back(); 17112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } else { 17212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org value = values[value_index]; 17312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 17412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org headers[name] = value; 17512e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 17612e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org EXPECT_TRUE(RoundTrip(headers)); 17712e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org } 17812e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org} 17912e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 18012e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org} // namespace 18112e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org 18212e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org} // namespace net 18312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org