This source file includes following definitions.
- header_table
- HandleHeaderRepresentation
- DecodeNextName
- context_peer
- set_cookie_name
- cookie_name
- set_cookie_value
- cookie_value
- decoded_block
- headers_block_buffer
- context_peer_
- DecodeHeaderBlock
- decoded_block
- DecodeUniqueHeaderSet
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "net/spdy/hpack_decoder.h"
#include <map>
#include <string>
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "net/spdy/hpack_encoder.h"
#include "net/spdy/hpack_input_stream.h"
#include "net/spdy/hpack_output_stream.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace test {
using base::StringPiece;
using std::string;
class HpackEncodingContextPeer {
public:
explicit HpackEncodingContextPeer(const HpackEncodingContext& context)
: context_(context) {}
const HpackHeaderTable& header_table() {
return context_.header_table_;
}
private:
const HpackEncodingContext& context_;
};
class HpackDecoderPeer {
public:
explicit HpackDecoderPeer(HpackDecoder* decoder)
: decoder_(decoder) {}
void HandleHeaderRepresentation(StringPiece name, StringPiece value) {
decoder_->HandleHeaderRepresentation(name, value);
}
bool DecodeNextName(HpackInputStream* in, StringPiece* out) {
return decoder_->DecodeNextName(in, out);
}
HpackEncodingContextPeer context_peer() {
return HpackEncodingContextPeer(decoder_->context_);
}
void set_cookie_name(string name) {
decoder_->cookie_name_ = name;
}
string cookie_name() {
return decoder_->cookie_name_;
}
void set_cookie_value(string value) {
decoder_->cookie_value_ = value;
}
string cookie_value() {
return decoder_->cookie_value_;
}
const std::map<string, string>& decoded_block() const {
return decoder_->decoded_block_;
}
const string& headers_block_buffer() const {
return decoder_->headers_block_buffer_;
}
private:
HpackDecoder* decoder_;
};
}
namespace {
using base::StringPiece;
using std::string;
using testing::ElementsAre;
using testing::Pair;
const size_t kLiteralBound = 1024;
class HpackDecoderTest : public ::testing::Test {
protected:
HpackDecoderTest()
: decoder_(ObtainHpackHuffmanTable()),
decoder_peer_(&decoder_),
context_peer_(decoder_peer_.context_peer()) {}
bool DecodeHeaderBlock(StringPiece str) {
return decoder_.HandleControlFrameHeadersData(0, str.data(), str.size()) &&
decoder_.HandleControlFrameHeadersComplete(0);
}
const std::map<string, string>& decoded_block() const {
return decoder_peer_.decoded_block();
}
const std::map<string, string>& DecodeUniqueHeaderSet(StringPiece str) {
EXPECT_TRUE(DecodeHeaderBlock(str));
return decoded_block();
}
HpackDecoder decoder_;
test::HpackDecoderPeer decoder_peer_;
test::HpackEncodingContextPeer context_peer_;
};
TEST_F(HpackDecoderTest, HandleControlFrameHeadersData) {
EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(
0, "small string one", 16));
EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(
0, "small string two", 16));
EXPECT_FALSE(decoder_.HandleControlFrameHeadersData(
0, "fails", kMaxDecodeBufferSize - 32 + 1));
EXPECT_EQ(decoder_peer_.headers_block_buffer(),
"small string onesmall string two");
}
TEST_F(HpackDecoderTest, HandleControlFrameHeadersComplete) {
EXPECT_TRUE(DecodeHeaderBlock("\x82\x86"));
decoder_peer_.set_cookie_name("CooKie");
decoder_peer_.set_cookie_value("foobar=baz");
decoder_.HandleControlFrameHeadersData(0, NULL, 0);
decoder_.HandleControlFrameHeadersComplete(0);
EXPECT_THAT(decoded_block(), ElementsAre(
Pair(":method", "GET"),
Pair(":path", "/index.html"),
Pair("CooKie", "foobar=baz")));
EXPECT_EQ(decoder_peer_.cookie_name(), "");
EXPECT_EQ(decoder_peer_.cookie_value(), "");
}
TEST_F(HpackDecoderTest, HandleHeaderRepresentation) {
decoder_peer_.HandleHeaderRepresentation("cOOkie", " part 1");
decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 ");
decoder_peer_.HandleHeaderRepresentation("cookie", "part3");
decoder_peer_.HandleHeaderRepresentation("passed-through",
string("foo\0baz", 7));
decoder_peer_.HandleHeaderRepresentation("joined", "not joined");
decoder_peer_.HandleHeaderRepresentation("joineD", "value 1");
decoder_peer_.HandleHeaderRepresentation("joineD", "value 2");
decoder_peer_.HandleHeaderRepresentation("empty", "");
decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
decoder_peer_.HandleHeaderRepresentation("empty-joined", "foo");
decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
decoder_peer_.HandleHeaderRepresentation("Cookie", " fin!");
decoder_.HandleControlFrameHeadersComplete(0);
EXPECT_THAT(decoded_block(), ElementsAre(
Pair("cOOkie", " part 1; part 2 ; part3; fin!"),
Pair("empty", ""),
Pair("empty-joined", string("\0foo\0\0", 6)),
Pair("joineD", string("value 1\0value 2", 15)),
Pair("joined", "not joined"),
Pair("passed-through", string("foo\0baz", 7))));
}
TEST_F(HpackDecoderTest, DecodeNextNameLiteral) {
HpackInputStream input_stream(kLiteralBound, StringPiece("\x00\x04name", 6));
StringPiece string_piece;
EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
EXPECT_EQ("name", string_piece);
EXPECT_FALSE(input_stream.HasMoreData());
}
TEST_F(HpackDecoderTest, DecodeNextNameLiteralWithHuffmanEncoding) {
char input[] = "\x00\x88\x4e\xb0\x8b\x74\x97\x90\xfa\x7f";
StringPiece foo(input, arraysize(input) - 1);
HpackInputStream input_stream(kLiteralBound, foo);
StringPiece string_piece;
EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
EXPECT_EQ("custom-key", string_piece);
EXPECT_FALSE(input_stream.HasMoreData());
}
TEST_F(HpackDecoderTest, DecodeNextNameIndexed) {
HpackInputStream input_stream(kLiteralBound, "\x01");
StringPiece string_piece;
EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
EXPECT_EQ(":authority", string_piece);
EXPECT_FALSE(input_stream.HasMoreData());
}
TEST_F(HpackDecoderTest, DecodeNextNameInvalidIndex) {
HpackInputStream input_stream(kLiteralBound, "\x3d");
StringPiece string_piece;
EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
}
TEST_F(HpackDecoderTest, IndexedHeaderBasic) {
std::map<string, string> header_set1 =
DecodeUniqueHeaderSet("\x82\x86");
std::map<string, string> expected_header_set1;
expected_header_set1[":method"] = "GET";
expected_header_set1[":path"] = "/index.html";
EXPECT_EQ(expected_header_set1, header_set1);
std::map<string, string> expected_header_set2;
expected_header_set2[":path"] = "/index.html";
std::map<string, string> header_set2 =
DecodeUniqueHeaderSet("\x82");
EXPECT_EQ(expected_header_set2, header_set2);
}
TEST_F(HpackDecoderTest, InvalidIndexedHeader) {
EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xbd", 1)));
}
TEST_F(HpackDecoderTest, ContextUpdateMaximumSize) {
EXPECT_EQ(kDefaultHeaderTableSizeSetting,
context_peer_.header_table().max_size());
{
EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x80\x7e", 2)));
EXPECT_EQ(126u, context_peer_.header_table().max_size());
}
string input;
{
HpackOutputStream output_stream(kuint32max);
output_stream.AppendBits(0x80, 8);
output_stream.AppendBits(0x00, 1);
output_stream.AppendUint32ForTest(kDefaultHeaderTableSizeSetting);
output_stream.TakeString(&input);
EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
EXPECT_EQ(kDefaultHeaderTableSizeSetting,
context_peer_.header_table().max_size());
}
{
HpackOutputStream output_stream(kuint32max);
output_stream.AppendBits(0x80, 8);
output_stream.AppendBits(0x00, 1);
output_stream.AppendUint32ForTest(kDefaultHeaderTableSizeSetting + 1);
output_stream.TakeString(&input);
EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input)));
EXPECT_EQ(kDefaultHeaderTableSizeSetting,
context_peer_.header_table().max_size());
}
}
TEST_F(HpackDecoderTest, ContextUpdateClearReferenceSet) {
std::map<string, string> header_set1 =
DecodeUniqueHeaderSet("\x82\x86");
std::map<string, string> expected_header_set1;
expected_header_set1[":method"] = "GET";
expected_header_set1[":path"] = "/index.html";
EXPECT_EQ(expected_header_set1, header_set1);
std::map<string, string> header_set2 =
DecodeUniqueHeaderSet("\x80\x80");
std::map<string, string> expected_header_set2;
EXPECT_EQ(expected_header_set2, header_set2);
}
TEST_F(HpackDecoderTest, LiteralHeaderNoIndexing) {
std::map<string, string> header_set =
DecodeUniqueHeaderSet(
"\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2");
std::map<string, string> expected_header_set;
expected_header_set[":path"] = "/sample/path";
expected_header_set[":path2"] = "/sample/path/2";
EXPECT_EQ(expected_header_set, header_set);
}
TEST_F(HpackDecoderTest, LiteralHeaderIncrementalIndexing) {
std::map<string, string> header_set = DecodeUniqueHeaderSet(
StringPiece("\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2", 37));
std::map<string, string> expected_header_set;
expected_header_set[":path"] = "/sample/path";
expected_header_set[":path2"] = "/sample/path/2";
EXPECT_EQ(expected_header_set, header_set);
std::map<string, string> header_set2 = DecodeUniqueHeaderSet("");
EXPECT_EQ(expected_header_set, header_set2);
}
TEST_F(HpackDecoderTest, LiteralHeaderInvalidIndices) {
EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7d", 1)));
EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x40", 1)));
EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x3d", 1)));
EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x00", 1)));
}
TEST_F(HpackDecoderTest, BasicE21) {
HpackEncoder encoder;
std::map<string, string> expected_header_set;
expected_header_set[":method"] = "GET";
expected_header_set[":scheme"] = "http";
expected_header_set[":path"] = "/";
expected_header_set[":authority"] = "www.example.com";
string encoded_header_set;
EXPECT_TRUE(encoder.EncodeHeaderSet(
expected_header_set, &encoded_header_set));
EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set));
EXPECT_EQ(expected_header_set, decoded_block());
}
TEST_F(HpackDecoderTest, SectionD3RequestHuffmanExamples) {
std::map<string, string> header_set;
char first[] =
"\x82\x87\x86\x04\x8b\xdb\x6d\x88\x3e\x68\xd1\xcb\x12\x25\xba\x7f";
header_set = DecodeUniqueHeaderSet(StringPiece(first, arraysize(first)-1));
EXPECT_THAT(header_set, ElementsAre(
Pair(":authority", "www.example.com"),
Pair(":method", "GET"),
Pair(":path", "/"),
Pair(":scheme", "http")));
char second[] = "\x1b\x86\x63\x65\x4a\x13\x98\xff";
header_set = DecodeUniqueHeaderSet(StringPiece(second, arraysize(second)-1));
EXPECT_THAT(header_set, ElementsAre(
Pair(":authority", "www.example.com"),
Pair(":method", "GET"),
Pair(":path", "/"),
Pair(":scheme", "http"),
Pair("cache-control", "no-cache")));
char third[] =
"\x80\x80\x85\x8c\x8b\x84\x00\x88\x4e\xb0\x8b\x74\x97\x90\xfa\x7f\x89"
"\x4e\xb0\x8b\x74\x97\x9a\x17\xa8\xff";
header_set = DecodeUniqueHeaderSet(StringPiece(third, arraysize(third)-1));
EXPECT_THAT(header_set, ElementsAre(
Pair(":authority", "www.example.com"),
Pair(":method", "GET"),
Pair(":path", "/index.html"),
Pair(":scheme", "https"),
Pair("custom-key", "custom-value")));
}
TEST_F(HpackDecoderTest, SectionD5ResponseHuffmanExamples) {
std::map<string, string> header_set;
decoder_.ApplyHeaderTableSizeSetting(256);
char first[] =
"\x08\x82\x98\xa7\x18\x85\x73\xd5\xcd\x11\x1f\x22\x98\xef\x6b"
"\x3a\x7a\x0e\x6e\x8f\xa2\x63\xd0\x72\x9a\x6e\x83\x97\xd8\x69\xbd\x87"
"\x37\x47\xbb\xbf\xc7\x30\x90\xce\x31\x74\x3d\x80\x1b\x6d\xb1\x07\xcd"
"\x1a\x39\x62\x44\xb7\x4f";
header_set = DecodeUniqueHeaderSet(StringPiece(first, arraysize(first)-1));
EXPECT_THAT(header_set, ElementsAre(
Pair(":status", "302"),
Pair("cache-control", "private"),
Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
Pair("location", "https://www.example.com")));
char second[] = "\x8c";
header_set = DecodeUniqueHeaderSet(StringPiece(second, arraysize(second)-1));
EXPECT_THAT(header_set, ElementsAre(
Pair(":status", "200"),
Pair("cache-control", "private"),
Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
Pair("location", "https://www.example.com")));
char third[] =
"\x84\x84\x03\x98\xef\x6b\x3a\x7a\x0e\x6e\x8f\xa2\x63\xd0\x72"
"\x9a\x6e\x83\x97\xd8\x69\xbd\x87\x3f\x47\xbb\xbf\xc7\x1d\x83\xcb\xd5"
"\x4e\x84\x84\x83\x83\x3a\xb3\xc5\xad\xb7\x7f\x87\x6f\xc7\xfb\xf7\xfd"
"\xbf\xbe\xbf\xf3\xf7\xf4\xfb\x7e\xbb\xbe\x9f\x5f\x87\xe3\x7f\xef\xed"
"\xfa\xee\xfa\x7c\x3f\x1d\x5d\x1a\x23\xce\x54\x64\x36\xcd\x49\x4b\xd5"
"\xd1\xcc\x5f\x05\x35\x96\x9b";
header_set = DecodeUniqueHeaderSet(StringPiece(third, arraysize(third)-1));
EXPECT_THAT(header_set, ElementsAre(
Pair(":status", "200"),
Pair("cache-control", "private"),
Pair("content-encoding", "gzip"),
Pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
Pair("location", "https://www.example.com"),
Pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
" max-age=3600; version=1")));
}
}
}