blob: 99cda08dd28719aaba83fc3f8292c7d4ebb3969a [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright 2018 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h"
6
7#include <algorithm>
8
bnc3b58cfc2019-11-27 12:52:39 -08009#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
vasilvv0fb44432019-03-13 22:47:36 -070010#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050011#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
bnce42f7ad2019-10-25 17:46:31 -070012#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
QUICHE team11f55d42019-12-11 10:36:09 -080013#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
14#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015
16using ::testing::_;
17using ::testing::Eq;
18using ::testing::Expectation;
bncfb4f4fc2019-11-18 17:14:56 -080019using ::testing::Invoke;
QUICHE teama6ef0a62019-03-07 20:34:33 -050020using ::testing::Return;
21using ::testing::StrictMock;
22using ::testing::Values;
23
24namespace quic {
25namespace test {
26namespace {
27
28// This instruction has three fields: an S bit and two varints.
29const QpackInstruction* TestInstruction1() {
30 static const QpackInstruction* const instruction =
31 new QpackInstruction{QpackInstructionOpcode{0x00, 0x80},
32 {{QpackInstructionFieldType::kSbit, 0x40},
33 {QpackInstructionFieldType::kVarint, 6},
34 {QpackInstructionFieldType::kVarint2, 8}}};
35 return instruction;
36}
37
38// This instruction has two fields: a header name with a 6-bit prefix, and a
39// header value with a 7-bit prefix, both preceded by a Huffman bit.
40const QpackInstruction* TestInstruction2() {
41 static const QpackInstruction* const instruction =
42 new QpackInstruction{QpackInstructionOpcode{0x80, 0x80},
43 {{QpackInstructionFieldType::kName, 6},
44 {QpackInstructionFieldType::kValue, 7}}};
45 return instruction;
46}
47
48const QpackLanguage* TestLanguage() {
49 static const QpackLanguage* const language =
50 new QpackLanguage{TestInstruction1(), TestInstruction2()};
51 return language;
52}
53
54class MockDelegate : public QpackInstructionDecoder::Delegate {
55 public:
56 MockDelegate() {
57 ON_CALL(*this, OnInstructionDecoded(_)).WillByDefault(Return(true));
58 }
59
60 MockDelegate(const MockDelegate&) = delete;
61 MockDelegate& operator=(const MockDelegate&) = delete;
62 ~MockDelegate() override = default;
63
64 MOCK_METHOD1(OnInstructionDecoded, bool(const QpackInstruction* instruction));
QUICHE team11f55d42019-12-11 10:36:09 -080065 MOCK_METHOD1(OnError, void(quiche::QuicheStringPiece error_message));
QUICHE teama6ef0a62019-03-07 20:34:33 -050066};
67
68class QpackInstructionDecoderTest : public QuicTestWithParam<FragmentMode> {
bncfb4f4fc2019-11-18 17:14:56 -080069 protected:
QUICHE teama6ef0a62019-03-07 20:34:33 -050070 QpackInstructionDecoderTest()
bncfb4f4fc2019-11-18 17:14:56 -080071 : decoder_(std::make_unique<QpackInstructionDecoder>(TestLanguage(),
72 &delegate_)),
73 fragment_mode_(GetParam()) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050074 ~QpackInstructionDecoderTest() override = default;
75
bncfb4f4fc2019-11-18 17:14:56 -080076 void SetUp() override {
77 // Destroy QpackInstructionDecoder on error to test that it does not crash.
78 // See https://crbug.com/1025209.
79 ON_CALL(delegate_, OnError(_))
QUICHE team11f55d42019-12-11 10:36:09 -080080 .WillByDefault(
81 Invoke([this](quiche::QuicheStringPiece /* error_message */) {
82 decoder_.reset();
83 }));
bncfb4f4fc2019-11-18 17:14:56 -080084 }
85
QUICHE teama6ef0a62019-03-07 20:34:33 -050086 // Decode one full instruction with fragment sizes dictated by
87 // |fragment_mode_|.
bncfb4f4fc2019-11-18 17:14:56 -080088 // Assumes that |data| is a single complete instruction, and accordingly
89 // verifies that AtInstructionBoundary() returns true before and after the
QUICHE teama6ef0a62019-03-07 20:34:33 -050090 // instruction, and returns false while decoding is in progress.
bncfb4f4fc2019-11-18 17:14:56 -080091 // Assumes that delegate methods destroy |decoder_| if they return false.
QUICHE team11f55d42019-12-11 10:36:09 -080092 void DecodeInstruction(quiche::QuicheStringPiece data) {
bncfb4f4fc2019-11-18 17:14:56 -080093 EXPECT_TRUE(decoder_->AtInstructionBoundary());
QUICHE teama6ef0a62019-03-07 20:34:33 -050094
95 FragmentSizeGenerator fragment_size_generator =
96 FragmentModeToFragmentSizeGenerator(fragment_mode_);
97
98 while (!data.empty()) {
99 size_t fragment_size = std::min(fragment_size_generator(), data.size());
bncfb4f4fc2019-11-18 17:14:56 -0800100 bool success = decoder_->Decode(data.substr(0, fragment_size));
101 if (!decoder_) {
102 EXPECT_FALSE(success);
103 return;
104 }
105 EXPECT_TRUE(success);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500106 data = data.substr(fragment_size);
107 if (!data.empty()) {
bncfb4f4fc2019-11-18 17:14:56 -0800108 EXPECT_FALSE(decoder_->AtInstructionBoundary());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500109 }
110 }
111
bncfb4f4fc2019-11-18 17:14:56 -0800112 EXPECT_TRUE(decoder_->AtInstructionBoundary());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113 }
114
115 StrictMock<MockDelegate> delegate_;
bncfb4f4fc2019-11-18 17:14:56 -0800116 std::unique_ptr<QpackInstructionDecoder> decoder_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117
118 private:
119 const FragmentMode fragment_mode_;
120};
121
QUICHE team1bfe0d72019-09-23 04:50:47 -0700122INSTANTIATE_TEST_SUITE_P(All,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500123 QpackInstructionDecoderTest,
124 Values(FragmentMode::kSingleChunk,
125 FragmentMode::kOctetByOctet));
126
127TEST_P(QpackInstructionDecoderTest, SBitAndVarint2) {
128 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()));
QUICHE team11f55d42019-12-11 10:36:09 -0800129 DecodeInstruction(quiche::QuicheTextUtils::HexDecode("7f01ff65"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500130
bncfb4f4fc2019-11-18 17:14:56 -0800131 EXPECT_TRUE(decoder_->s_bit());
132 EXPECT_EQ(64u, decoder_->varint());
133 EXPECT_EQ(356u, decoder_->varint2());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500134
135 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()));
QUICHE team11f55d42019-12-11 10:36:09 -0800136 DecodeInstruction(quiche::QuicheTextUtils::HexDecode("05c8"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500137
bncfb4f4fc2019-11-18 17:14:56 -0800138 EXPECT_FALSE(decoder_->s_bit());
139 EXPECT_EQ(5u, decoder_->varint());
140 EXPECT_EQ(200u, decoder_->varint2());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500141}
142
143TEST_P(QpackInstructionDecoderTest, NameAndValue) {
144 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
QUICHE team11f55d42019-12-11 10:36:09 -0800145 DecodeInstruction(quiche::QuicheTextUtils::HexDecode("83666f6f03626172"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500146
bncfb4f4fc2019-11-18 17:14:56 -0800147 EXPECT_EQ("foo", decoder_->name());
148 EXPECT_EQ("bar", decoder_->value());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500149
150 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
QUICHE team11f55d42019-12-11 10:36:09 -0800151 DecodeInstruction(quiche::QuicheTextUtils::HexDecode("8000"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500152
bncfb4f4fc2019-11-18 17:14:56 -0800153 EXPECT_EQ("", decoder_->name());
154 EXPECT_EQ("", decoder_->value());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500155
156 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
QUICHE team11f55d42019-12-11 10:36:09 -0800157 DecodeInstruction(quiche::QuicheTextUtils::HexDecode("c294e7838c767f"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500158
bncfb4f4fc2019-11-18 17:14:56 -0800159 EXPECT_EQ("foo", decoder_->name());
160 EXPECT_EQ("bar", decoder_->value());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500161}
162
163TEST_P(QpackInstructionDecoderTest, InvalidHuffmanEncoding) {
164 EXPECT_CALL(delegate_, OnError(Eq("Error in Huffman-encoded string.")));
QUICHE team11f55d42019-12-11 10:36:09 -0800165 DecodeInstruction(quiche::QuicheTextUtils::HexDecode("c1ff"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500166}
167
168TEST_P(QpackInstructionDecoderTest, InvalidVarintEncoding) {
169 EXPECT_CALL(delegate_, OnError(Eq("Encoded integer too large.")));
QUICHE team11f55d42019-12-11 10:36:09 -0800170 DecodeInstruction(
171 quiche::QuicheTextUtils::HexDecode("ffffffffffffffffffffff"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500172}
173
174TEST_P(QpackInstructionDecoderTest, DelegateSignalsError) {
175 // First instruction is valid.
176 Expectation first_call =
177 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()))
bncfb4f4fc2019-11-18 17:14:56 -0800178 .WillOnce(Invoke(
179 [this](const QpackInstruction * /* instruction */) -> bool {
180 EXPECT_EQ(1u, decoder_->varint());
181 return true;
182 }));
183
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184 // Second instruction is invalid. Decoding must halt.
185 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()))
186 .After(first_call)
bncfb4f4fc2019-11-18 17:14:56 -0800187 .WillOnce(
188 Invoke([this](const QpackInstruction * /* instruction */) -> bool {
189 EXPECT_EQ(2u, decoder_->varint());
190 return false;
191 }));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500192
QUICHE team11f55d42019-12-11 10:36:09 -0800193 EXPECT_FALSE(decoder_->Decode(
194 quiche::QuicheTextUtils::HexDecode("01000200030004000500")));
bncfb4f4fc2019-11-18 17:14:56 -0800195}
196
197// QpackInstructionDecoder must not crash if it is destroyed from a
198// Delegate::OnInstructionDecoded() call as long as it returns false.
199TEST_P(QpackInstructionDecoderTest, DelegateSignalsErrorAndDestroysDecoder) {
200 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()))
201 .WillOnce(
202 Invoke([this](const QpackInstruction * /* instruction */) -> bool {
203 EXPECT_EQ(1u, decoder_->varint());
204 decoder_.reset();
205 return false;
206 }));
QUICHE team11f55d42019-12-11 10:36:09 -0800207 DecodeInstruction(quiche::QuicheTextUtils::HexDecode("0100"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500208}
209
210} // namespace
211} // namespace test
212} // namespace quic