| // 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 <string> | |
| #include <tuple> | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | |
| #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h" | |
| #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h" | |
| #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" | |
| #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" | |
| #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" | |
| using ::testing::Values; | |
| namespace quic { | |
| namespace test { | |
| namespace { | |
| class QpackRoundTripTest : public QuicTestWithParam<FragmentMode> { | |
| public: | |
| QpackRoundTripTest() = default; | |
| ~QpackRoundTripTest() override = default; | |
| spdy::SpdyHeaderBlock EncodeThenDecode( | |
| const spdy::SpdyHeaderBlock& header_list) { | |
| NoopDecoderStreamErrorDelegate decoder_stream_error_delegate; | |
| NoopQpackStreamSenderDelegate encoder_stream_sender_delegate; | |
| QpackEncoder encoder(&decoder_stream_error_delegate); | |
| encoder.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate); | |
| std::string encoded_header_block = | |
| encoder.EncodeHeaderList(/* stream_id = */ 1, header_list, nullptr); | |
| TestHeadersHandler handler; | |
| NoopEncoderStreamErrorDelegate encoder_stream_error_delegate; | |
| NoopQpackStreamSenderDelegate decoder_stream_sender_delegate; | |
| // TODO(b/112770235): Test dynamic table and blocked streams. | |
| QpackDecode( | |
| /* maximum_dynamic_table_capacity = */ 0, | |
| /* maximum_blocked_streams = */ 0, &encoder_stream_error_delegate, | |
| &decoder_stream_sender_delegate, &handler, | |
| FragmentModeToFragmentSizeGenerator(GetParam()), encoded_header_block); | |
| EXPECT_TRUE(handler.decoding_completed()); | |
| EXPECT_FALSE(handler.decoding_error_detected()); | |
| return handler.ReleaseHeaderList(); | |
| } | |
| }; | |
| INSTANTIATE_TEST_SUITE_P(All, | |
| QpackRoundTripTest, | |
| Values(FragmentMode::kSingleChunk, | |
| FragmentMode::kOctetByOctet)); | |
| TEST_P(QpackRoundTripTest, Empty) { | |
| spdy::SpdyHeaderBlock header_list; | |
| spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); | |
| EXPECT_EQ(header_list, output); | |
| } | |
| TEST_P(QpackRoundTripTest, EmptyName) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list["foo"] = "bar"; | |
| header_list[""] = "bar"; | |
| spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); | |
| EXPECT_EQ(header_list, output); | |
| } | |
| TEST_P(QpackRoundTripTest, EmptyValue) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list["foo"] = ""; | |
| header_list[""] = ""; | |
| spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); | |
| EXPECT_EQ(header_list, output); | |
| } | |
| TEST_P(QpackRoundTripTest, MultipleWithLongEntries) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list["foo"] = "bar"; | |
| header_list[":path"] = "/"; | |
| header_list["foobaar"] = std::string(127, 'Z'); | |
| header_list[std::string(1000, 'b')] = std::string(1000, 'c'); | |
| spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); | |
| EXPECT_EQ(header_list, output); | |
| } | |
| TEST_P(QpackRoundTripTest, StaticTable) { | |
| { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[":method"] = "GET"; | |
| header_list["accept-encoding"] = "gzip, deflate"; | |
| header_list["cache-control"] = ""; | |
| header_list["foo"] = "bar"; | |
| header_list[":path"] = "/"; | |
| spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); | |
| EXPECT_EQ(header_list, output); | |
| } | |
| { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[":method"] = "POST"; | |
| header_list["accept-encoding"] = "brotli"; | |
| header_list["cache-control"] = "foo"; | |
| header_list["foo"] = "bar"; | |
| header_list[":path"] = "/"; | |
| spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); | |
| EXPECT_EQ(header_list, output); | |
| } | |
| { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list[":method"] = "CONNECT"; | |
| header_list["accept-encoding"] = ""; | |
| header_list["foo"] = "bar"; | |
| header_list[":path"] = "/"; | |
| spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); | |
| EXPECT_EQ(header_list, output); | |
| } | |
| } | |
| TEST_P(QpackRoundTripTest, ValueHasNullCharacter) { | |
| spdy::SpdyHeaderBlock header_list; | |
| header_list["foo"] = quiche::QuicheStringPiece("bar\0bar\0baz", 11); | |
| spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); | |
| EXPECT_EQ(header_list, output); | |
| } | |
| } // namespace | |
| } // namespace test | |
| } // namespace quic |