15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be 35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file. 45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "net/spdy/hpack_huffman_aggregator.h" 55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/metrics/histogram.h" 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/metrics/statistics_recorder.h" 85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "net/base/load_flags.h" 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "net/http/http_request_headers.h" 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "net/http/http_request_info.h" 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "net/http/http_response_headers.h" 125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "testing/gmock/include/gmock/gmock.h" 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "testing/gtest/include/gtest/gtest.h" 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace net { 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing ::testing::Each; 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing ::testing::ElementsAre; 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing ::testing::Eq; 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing ::testing::Pair; 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace { 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kHistogramName[] = "Net.SpdyHpackEncodedCharacterFrequency"; 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} // namespace 255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace test { 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass HpackHuffmanAggregatorPeer { 295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public: 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu explicit HpackHuffmanAggregatorPeer(HpackHuffmanAggregator* agg) 315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu : agg_(agg) {} 325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu std::vector<size_t>* counts() { 345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return &agg_->counts_; 355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackHuffmanAggregator::OriginEncoders* encoders() { 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return &agg_->encoders_; 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu size_t total_counts() { 405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return agg_->total_counts_; 415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu void set_total_counts(size_t total_counts) { 435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu agg_->total_counts_ = total_counts; 445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu void set_max_encoders(size_t max_encoders) { 465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu agg_->max_encoders_ = max_encoders; 475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu static bool IsCrossOrigin(const HttpRequestInfo& request) { 495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return HpackHuffmanAggregator::IsCrossOrigin(request); 505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu static void CreateSpdyHeadersFromHttpResponse( 525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const HttpResponseHeaders& headers, 535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu SpdyHeaderBlock* headers_out) { 545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackHuffmanAggregator::CreateSpdyHeadersFromHttpResponse( 555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu headers, headers_out); 565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackEncoder* ObtainEncoder(const SpdySessionKey& key) { 585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return agg_->ObtainEncoder(key); 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu void PublishCounts() { 615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu agg_->PublishCounts(); 625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private: 655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackHuffmanAggregator* agg_; 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} // namespace test 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass HpackHuffmanAggregatorTest : public ::testing::Test { 715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu protected: 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackHuffmanAggregatorTest() 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu : peer_(&agg_) {} 745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackHuffmanAggregator agg_; 765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu test::HpackHuffmanAggregatorPeer peer_; 775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST_F(HpackHuffmanAggregatorTest, CrossOriginDetermination) { 805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HttpRequestInfo request; 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu request.url = GURL("https://www.foo.com/a/page"); 825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Main load without referer. 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu request.load_flags = LOAD_MAIN_FRAME; 855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_FALSE(peer_.IsCrossOrigin(request)); 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Non-main load without referer. Treated as cross-origin. 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu request.load_flags = 0; 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_TRUE(peer_.IsCrossOrigin(request)); 905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Main load with different referer origin. 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu request.load_flags = LOAD_MAIN_FRAME; 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu request.extra_headers.SetHeader(HttpRequestHeaders::kReferer, 945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "https://www.bar.com/other/page"); 955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_FALSE(peer_.IsCrossOrigin(request)); 965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Non-main load with different referer orign. 985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu request.load_flags = 0; 995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_TRUE(peer_.IsCrossOrigin(request)); 1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Non-main load with same referer orign. 1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu request.extra_headers.SetHeader(HttpRequestHeaders::kReferer, 1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "https://www.foo.com/other/page"); 1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_FALSE(peer_.IsCrossOrigin(request)); 1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Non-main load with same referer host but different schemes. 1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu request.extra_headers.SetHeader(HttpRequestHeaders::kReferer, 1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "http://www.foo.com/other/page"); 1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_TRUE(peer_.IsCrossOrigin(request)); 1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST_F(HpackHuffmanAggregatorTest, EncoderLRUQueue) { 1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu peer_.set_max_encoders(2); 1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu SpdySessionKey key1(HostPortPair("one.com", 443), ProxyServer::Direct(), 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PRIVACY_MODE_ENABLED); 1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu SpdySessionKey key2(HostPortPair("two.com", 443), ProxyServer::Direct(), 1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PRIVACY_MODE_ENABLED); 1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu SpdySessionKey key3(HostPortPair("three.com", 443), ProxyServer::Direct(), 1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PRIVACY_MODE_ENABLED); 1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Creates one.com. 1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackEncoder* one = peer_.ObtainEncoder(key1); 1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(1u, peer_.encoders()->size()); 1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Creates two.com. No evictions. 1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackEncoder* two = peer_.ObtainEncoder(key2); 1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(2u, peer_.encoders()->size()); 1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_NE(one, two); 1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Touch one.com. 1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(one, peer_.ObtainEncoder(key1)); 1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Creates three.com. Evicts two.com, as it's least-recently used. 1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu HpackEncoder* three = peer_.ObtainEncoder(key3); 1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(one, peer_.ObtainEncoder(key1)); 1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_NE(one, three); 1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(2u, peer_.encoders()->size()); 1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST_F(HpackHuffmanAggregatorTest, PublishCounts) { 1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu (*peer_.counts())[0] = 1; 1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu (*peer_.counts())[255] = 10; 1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu (*peer_.counts())[128] = 101; 1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu peer_.set_total_counts(112); 1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu peer_.PublishCounts(); 1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Internal counts were reset after being published. 1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_THAT(*peer_.counts(), Each(Eq(0u))); 1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(0u, peer_.total_counts()); 1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Verify histogram counts match the expectation. 1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_ptr<base::HistogramSamples> samples = 1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::StatisticsRecorder::FindHistogram(kHistogramName) 1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ->SnapshotSamples(); 1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(0, samples->GetCount(0)); 1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(1, samples->GetCount(1)); 1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(101, samples->GetCount(129)); 1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(10, samples->GetCount(256)); 1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(112, samples->TotalCount()); 1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Publish a second round of counts; 1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu (*peer_.counts())[1] = 32; 1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu (*peer_.counts())[128] = 5; 1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu peer_.set_total_counts(37); 1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu peer_.PublishCounts(); 1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Verify they've been aggregated into the previous counts. 1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu samples = base::StatisticsRecorder::FindHistogram(kHistogramName) 1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ->SnapshotSamples(); 1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(0, samples->GetCount(0)); 1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(1, samples->GetCount(1)); 1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(32, samples->GetCount(2)); 1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(106, samples->GetCount(129)); 1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(10, samples->GetCount(256)); 1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_EQ(149, samples->TotalCount()); 1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST_F(HpackHuffmanAggregatorTest, CreateSpdyResponseHeaders) { 1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu char kRawHeaders[] = 1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "HTTP/1.1 202 Accepted \0" 1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "Content-TYPE : text/html; charset=utf-8 \0" 1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "Set-Cookie: foo=bar \0" 1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "Set-Cookie: baz=bing \0" 1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "Cache-Control: pragma=no-cache \0" 1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu "Cache-CONTROL: expires=12345 \0\0"; 1915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_refptr<HttpResponseHeaders> parsed_headers(new HttpResponseHeaders( 1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu std::string(kRawHeaders, arraysize(kRawHeaders) - 1))); 1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu SpdyHeaderBlock headers; 1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu peer_.CreateSpdyHeadersFromHttpResponse(*parsed_headers, &headers); 1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EXPECT_THAT(headers, ElementsAre( 1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu Pair(":status", "202"), 1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu Pair("cache-control", std::string("pragma=no-cache\0expires=12345", 29)), 2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu Pair("content-type", "text/html; charset=utf-8"), 2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu Pair("set-cookie", std::string("foo=bar\0baz=bing", 16)))); 2025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} // namespace net 205