| // Copyright (c) 2018 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 "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" | |
| #include <string> | |
| #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" | |
| #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" | |
| using ::testing::Eq; | |
| using ::testing::StrictMock; | |
| using ::testing::Values; | |
| namespace quic { | |
| namespace test { | |
| namespace { | |
| class QpackEncoderTest : public QuicTestWithParam<FragmentMode> { | |
| protected: | |
| QpackEncoderTest() : fragment_mode_(GetParam()) {} | |
| ~QpackEncoderTest() override = default; | |
| std::string Encode(const spdy::SpdyHeaderBlock* header_list) { | |
| return QpackEncode( | |
| &decoder_stream_error_delegate_, &encoder_stream_sender_delegate_, | |
| FragmentModeToFragmentSizeGenerator(fragment_mode_), header_list); | |
| } | |
| StrictMock<MockDecoderStreamErrorDelegate> decoder_stream_error_delegate_; | |
| NoopEncoderStreamSenderDelegate encoder_stream_sender_delegate_; | |
| private: | |
| const FragmentMode fragment_mode_; | |
| }; | |
| INSTANTIATE_TEST_SUITE_P(, | |
| QpackEncoderTest, | |
| Values(FragmentMode::kSingleChunk, | |
| FragmentMode::kOctetByOctet)); | |
| TEST_P(QpackEncoderTest, Empty) { | |
| spdy::SpdyHeaderBlock header_list; | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("0000"), output); | |
| } | |
| TEST_P(QpackEncoderTest, EmptyName) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[""] = "foo"; | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("0000208294e7"), output); | |
| } | |
| TEST_P(QpackEncoderTest, EmptyValue) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list["foo"] = ""; | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("00002a94e700"), output); | |
| } | |
| TEST_P(QpackEncoderTest, EmptyNameAndValue) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[""] = ""; | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("00002000"), output); | |
| } | |
| TEST_P(QpackEncoderTest, Simple) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list["foo"] = "bar"; | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("00002a94e703626172"), output); | |
| } | |
| TEST_P(QpackEncoderTest, Multiple) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list["foo"] = "bar"; | |
| // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used. | |
| header_list["ZZZZZZZ"] = std::string(127, 'Z'); | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ( | |
| QuicTextUtils::HexDecode( | |
| "0000" // prefix | |
| "2a94e703626172" // foo: bar | |
| "27005a5a5a5a5a5a5a" // 7 octet long header name, the smallest number | |
| // that does not fit on a 3-bit prefix. | |
| "7f005a5a5a5a5a5a5a" // 127 octet long header value, the smallest | |
| "5a5a5a5a5a5a5a5a5a" // number that does not fit on a 7-bit prefix. | |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" | |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" | |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" | |
| "5a5a5a5a5a5a5a5a5a"), | |
| output); | |
| } | |
| TEST_P(QpackEncoderTest, StaticTable) { | |
| { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[":method"] = "GET"; | |
| header_list["accept-encoding"] = "gzip, deflate, br"; | |
| header_list["location"] = ""; | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("0000d1dfcc"), output); | |
| } | |
| { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[":method"] = "POST"; | |
| header_list["accept-encoding"] = "compress"; | |
| header_list["location"] = "foo"; | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("0000d45f108621e9aec2a11f5c8294e7"), | |
| output); | |
| } | |
| { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[":method"] = "TRACE"; | |
| header_list["accept-encoding"] = ""; | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("00005f000554524143455f1000"), output); | |
| } | |
| } | |
| TEST_P(QpackEncoderTest, SimpleIndexed) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[":path"] = "/"; | |
| QpackEncoder encoder(&decoder_stream_error_delegate_, | |
| &encoder_stream_sender_delegate_); | |
| auto progressive_encoder = | |
| encoder.EncodeHeaderList(/* stream_id = */ 1, &header_list); | |
| EXPECT_TRUE(progressive_encoder->HasNext()); | |
| // This indexed header field takes exactly three bytes: | |
| // two for the prefix, one for the indexed static entry. | |
| std::string output; | |
| progressive_encoder->Next(3, &output); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("0000c1"), output); | |
| EXPECT_FALSE(progressive_encoder->HasNext()); | |
| } | |
| TEST_P(QpackEncoderTest, DecoderStreamError) { | |
| EXPECT_CALL(decoder_stream_error_delegate_, | |
| OnDecoderStreamError(Eq("Encoded integer too large."))); | |
| QpackEncoder encoder(&decoder_stream_error_delegate_, | |
| &encoder_stream_sender_delegate_); | |
| encoder.DecodeDecoderStreamData( | |
| QuicTextUtils::HexDecode("ffffffffffffffffffffff")); | |
| } | |
| TEST_P(QpackEncoderTest, SplitAlongNullCharacter) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list["foo"] = QuicStringPiece("bar\0bar\0baz", 11); | |
| std::string output = Encode(&header_list); | |
| EXPECT_EQ(QuicTextUtils::HexDecode("0000" // prefix | |
| "2a94e703626172" // foo: bar | |
| "2a94e703626172" // foo: bar | |
| "2a94e70362617a" // foo: baz | |
| ), | |
| output); | |
| } | |
| } // namespace | |
| } // namespace test | |
| } // namespace quic |