blob: f0d1d1d05647007497fa60d5033358163a22f64e [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
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include "testing/gmock/include/gmock/gmock.h"
10#include "testing/gtest/include/gtest/gtest.h"
11#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
12#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
vasilvv0fb44432019-03-13 22:47:36 -070013#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050014#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
16
17using ::testing::_;
18using ::testing::Eq;
19using ::testing::Expectation;
20using ::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));
65 MOCK_METHOD1(OnError, void(QuicStringPiece error_message));
66};
67
68class QpackInstructionDecoderTest : public QuicTestWithParam<FragmentMode> {
69 public:
70 QpackInstructionDecoderTest()
71 : decoder_(TestLanguage(), &delegate_), fragment_mode_(GetParam()) {}
72 ~QpackInstructionDecoderTest() override = default;
73
74 protected:
75 // Decode one full instruction with fragment sizes dictated by
76 // |fragment_mode_|.
77 // Verifies that AtInstructionBoundary() returns true before and after the
78 // instruction, and returns false while decoding is in progress.
79 void DecodeInstruction(QuicStringPiece data) {
80 EXPECT_TRUE(decoder_.AtInstructionBoundary());
81
82 FragmentSizeGenerator fragment_size_generator =
83 FragmentModeToFragmentSizeGenerator(fragment_mode_);
84
85 while (!data.empty()) {
86 size_t fragment_size = std::min(fragment_size_generator(), data.size());
87 decoder_.Decode(data.substr(0, fragment_size));
88 data = data.substr(fragment_size);
89 if (!data.empty()) {
90 EXPECT_FALSE(decoder_.AtInstructionBoundary());
91 }
92 }
93
94 EXPECT_TRUE(decoder_.AtInstructionBoundary());
95 }
96
97 StrictMock<MockDelegate> delegate_;
98 QpackInstructionDecoder decoder_;
99
100 private:
101 const FragmentMode fragment_mode_;
102};
103
104INSTANTIATE_TEST_SUITE_P(,
105 QpackInstructionDecoderTest,
106 Values(FragmentMode::kSingleChunk,
107 FragmentMode::kOctetByOctet));
108
109TEST_P(QpackInstructionDecoderTest, SBitAndVarint2) {
110 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()));
111 DecodeInstruction(QuicTextUtils::HexDecode("7f01ff65"));
112
113 EXPECT_TRUE(decoder_.s_bit());
114 EXPECT_EQ(64u, decoder_.varint());
115 EXPECT_EQ(356u, decoder_.varint2());
116
117 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()));
118 DecodeInstruction(QuicTextUtils::HexDecode("05c8"));
119
120 EXPECT_FALSE(decoder_.s_bit());
121 EXPECT_EQ(5u, decoder_.varint());
122 EXPECT_EQ(200u, decoder_.varint2());
123}
124
125TEST_P(QpackInstructionDecoderTest, NameAndValue) {
126 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
127 DecodeInstruction(QuicTextUtils::HexDecode("83666f6f03626172"));
128
129 EXPECT_EQ("foo", decoder_.name());
130 EXPECT_EQ("bar", decoder_.value());
131
132 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
133 DecodeInstruction(QuicTextUtils::HexDecode("8000"));
134
135 EXPECT_EQ("", decoder_.name());
136 EXPECT_EQ("", decoder_.value());
137
138 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
139 DecodeInstruction(QuicTextUtils::HexDecode("c294e7838c767f"));
140
141 EXPECT_EQ("foo", decoder_.name());
142 EXPECT_EQ("bar", decoder_.value());
143}
144
145TEST_P(QpackInstructionDecoderTest, InvalidHuffmanEncoding) {
146 EXPECT_CALL(delegate_, OnError(Eq("Error in Huffman-encoded string.")));
147 decoder_.Decode(QuicTextUtils::HexDecode("c1ff"));
148}
149
150TEST_P(QpackInstructionDecoderTest, InvalidVarintEncoding) {
151 EXPECT_CALL(delegate_, OnError(Eq("Encoded integer too large.")));
152 decoder_.Decode(QuicTextUtils::HexDecode("ffffffffffffffffffffff"));
153}
154
155TEST_P(QpackInstructionDecoderTest, DelegateSignalsError) {
156 // First instruction is valid.
157 Expectation first_call =
158 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()))
159 .WillOnce(Return(true));
160 // Second instruction is invalid. Decoding must halt.
161 EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()))
162 .After(first_call)
163 .WillOnce(Return(false));
164 decoder_.Decode(QuicTextUtils::HexDecode("01000200030004000500"));
165
166 EXPECT_EQ(2u, decoder_.varint());
167}
168
169} // namespace
170} // namespace test
171} // namespace quic