| // 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 "quiche/quic/core/qpack/qpack_encoder_stream_receiver.h" |
| |
| #include "absl/strings/escaping.h" |
| #include "absl/strings/string_view.h" |
| #include "quiche/quic/platform/api/quic_test.h" |
| |
| using testing::Eq; |
| using testing::StrictMock; |
| |
| namespace quic { |
| namespace test { |
| namespace { |
| |
| class MockDelegate : public QpackEncoderStreamReceiver::Delegate { |
| public: |
| ~MockDelegate() override = default; |
| |
| MOCK_METHOD(void, OnInsertWithNameReference, |
| (bool is_static, uint64_t name_index, absl::string_view value), |
| (override)); |
| MOCK_METHOD(void, OnInsertWithoutNameReference, |
| (absl::string_view name, absl::string_view value), (override)); |
| MOCK_METHOD(void, OnDuplicate, (uint64_t index), (override)); |
| MOCK_METHOD(void, OnSetDynamicTableCapacity, (uint64_t capacity), (override)); |
| MOCK_METHOD(void, OnErrorDetected, |
| (QuicErrorCode error_code, absl::string_view error_message), |
| (override)); |
| }; |
| |
| class QpackEncoderStreamReceiverTest : public QuicTest { |
| protected: |
| QpackEncoderStreamReceiverTest() : stream_(&delegate_) {} |
| ~QpackEncoderStreamReceiverTest() override = default; |
| |
| void Decode(absl::string_view data) { stream_.Decode(data); } |
| StrictMock<MockDelegate>* delegate() { return &delegate_; } |
| |
| private: |
| QpackEncoderStreamReceiver stream_; |
| StrictMock<MockDelegate> delegate_; |
| }; |
| |
| TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReference) { |
| // Static, index fits in prefix, empty value. |
| EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 5, Eq(""))); |
| // Static, index fits in prefix, Huffman encoded value. |
| EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 2, Eq("foo"))); |
| // Not static, index does not fit in prefix, not Huffman encoded value. |
| EXPECT_CALL(*delegate(), OnInsertWithNameReference(false, 137, Eq("bar"))); |
| // Value length does not fit in prefix. |
| // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used. |
| EXPECT_CALL(*delegate(), |
| OnInsertWithNameReference(false, 42, Eq(std::string(127, 'Z')))); |
| |
| Decode(absl::HexStringToBytes( |
| "c500" |
| "c28294e7" |
| "bf4a03626172" |
| "aa7f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a")); |
| } |
| |
| TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReferenceIndexTooLarge) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INTEGER_TOO_LARGE, |
| Eq("Encoded integer too large."))); |
| |
| Decode(absl::HexStringToBytes("bfffffffffffffffffffffff")); |
| } |
| |
| TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReferenceValueTooLong) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INTEGER_TOO_LARGE, |
| Eq("Encoded integer too large."))); |
| |
| Decode(absl::HexStringToBytes("c57fffffffffffffffffffff")); |
| } |
| |
| TEST_F(QpackEncoderStreamReceiverTest, InsertWithoutNameReference) { |
| // Empty name and value. |
| EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq(""), Eq(""))); |
| // Huffman encoded short strings. |
| EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq("bar"), Eq("bar"))); |
| // Not Huffman encoded short strings. |
| EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq("foo"), Eq("foo"))); |
| // Not Huffman encoded long strings; length does not fit on prefix. |
| // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used. |
| EXPECT_CALL(*delegate(), |
| OnInsertWithoutNameReference(Eq(std::string(31, 'Z')), |
| Eq(std::string(127, 'Z')))); |
| |
| Decode(absl::HexStringToBytes( |
| "4000" |
| "4362617203626172" |
| "6294e78294e7" |
| "5f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a7f005a" |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" |
| "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a")); |
| } |
| |
| // Name Length value is too large for varint decoder to decode. |
| TEST_F(QpackEncoderStreamReceiverTest, |
| InsertWithoutNameReferenceNameTooLongForVarintDecoder) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INTEGER_TOO_LARGE, |
| Eq("Encoded integer too large."))); |
| |
| Decode(absl::HexStringToBytes("5fffffffffffffffffffff")); |
| } |
| |
| // Name Length value can be decoded by varint decoder but exceeds 1 MB limit. |
| TEST_F(QpackEncoderStreamReceiverTest, |
| InsertWithoutNameReferenceNameExceedsLimit) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_STRING_LITERAL_TOO_LONG, |
| Eq("String literal too long."))); |
| |
| Decode(absl::HexStringToBytes("5fffff7f")); |
| } |
| |
| // Value Length value is too large for varint decoder to decode. |
| TEST_F(QpackEncoderStreamReceiverTest, |
| InsertWithoutNameReferenceValueTooLongForVarintDecoder) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INTEGER_TOO_LARGE, |
| Eq("Encoded integer too large."))); |
| |
| Decode(absl::HexStringToBytes("436261727fffffffffffffffffffff")); |
| } |
| |
| // Value Length value can be decoded by varint decoder but exceeds 1 MB limit. |
| TEST_F(QpackEncoderStreamReceiverTest, |
| InsertWithoutNameReferenceValueExceedsLimit) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_STRING_LITERAL_TOO_LONG, |
| Eq("String literal too long."))); |
| |
| Decode(absl::HexStringToBytes("436261727fffff7f")); |
| } |
| |
| TEST_F(QpackEncoderStreamReceiverTest, Duplicate) { |
| // Small index fits in prefix. |
| EXPECT_CALL(*delegate(), OnDuplicate(17)); |
| // Large index requires two extension bytes. |
| EXPECT_CALL(*delegate(), OnDuplicate(500)); |
| |
| Decode(absl::HexStringToBytes("111fd503")); |
| } |
| |
| TEST_F(QpackEncoderStreamReceiverTest, DuplicateIndexTooLarge) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INTEGER_TOO_LARGE, |
| Eq("Encoded integer too large."))); |
| |
| Decode(absl::HexStringToBytes("1fffffffffffffffffffff")); |
| } |
| |
| TEST_F(QpackEncoderStreamReceiverTest, SetDynamicTableCapacity) { |
| // Small capacity fits in prefix. |
| EXPECT_CALL(*delegate(), OnSetDynamicTableCapacity(17)); |
| // Large capacity requires two extension bytes. |
| EXPECT_CALL(*delegate(), OnSetDynamicTableCapacity(500)); |
| |
| Decode(absl::HexStringToBytes("313fd503")); |
| } |
| |
| TEST_F(QpackEncoderStreamReceiverTest, SetDynamicTableCapacityTooLarge) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_INTEGER_TOO_LARGE, |
| Eq("Encoded integer too large."))); |
| |
| Decode(absl::HexStringToBytes("3fffffffffffffffffffff")); |
| } |
| |
| TEST_F(QpackEncoderStreamReceiverTest, InvalidHuffmanEncoding) { |
| EXPECT_CALL(*delegate(), |
| OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_HUFFMAN_ENCODING_ERROR, |
| Eq("Error in Huffman-encoded string."))); |
| |
| Decode(absl::HexStringToBytes("c281ff")); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace quic |