blob: 30b586fd2a631efd89a358e5f0dbcc014b7a0eab [file] [log] [blame]
QUICHE teamfd50a402018-12-07 22:54:05 -05001// Copyright 2016 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/http2/hpack/huffman/hpack_huffman_decoder.h"
6
7// Tests of HpackHuffmanDecoder and HuffmanBitBuffer.
8
9#include <iostream>
10
QUICHE teamfd50a402018-12-07 22:54:05 -050011#include "testing/gtest/include/gtest/gtest.h"
12#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
13#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
14#include "net/third_party/quiche/src/http2/platform/api/http2_arraysize.h"
15#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
16#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
17#include "net/third_party/quiche/src/http2/tools/random_decoder_test.h"
18
19using ::testing::AssertionResult;
20
21namespace http2 {
22namespace test {
23namespace {
24
25TEST(HuffmanBitBufferTest, Reset) {
26 HuffmanBitBuffer bb;
27 EXPECT_TRUE(bb.IsEmpty());
28 EXPECT_TRUE(bb.InputProperlyTerminated());
29 EXPECT_EQ(bb.count(), 0u);
30 EXPECT_EQ(bb.free_count(), 64u);
31 EXPECT_EQ(bb.value(), 0u);
32}
33
34TEST(HuffmanBitBufferTest, AppendBytesAligned) {
35 Http2String s;
36 s.push_back('\x11');
37 s.push_back('\x22');
38 s.push_back('\x33');
39 Http2StringPiece sp(s);
40
41 HuffmanBitBuffer bb;
42 sp.remove_prefix(bb.AppendBytes(sp));
43 EXPECT_TRUE(sp.empty());
44 EXPECT_FALSE(bb.IsEmpty()) << bb;
45 EXPECT_FALSE(bb.InputProperlyTerminated());
46 EXPECT_EQ(bb.count(), 24u) << bb;
47 EXPECT_EQ(bb.free_count(), 40u) << bb;
48 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x112233) << 40) << bb;
49
50 s.clear();
51 s.push_back('\x44');
52 sp = s;
53
54 sp.remove_prefix(bb.AppendBytes(sp));
55 EXPECT_TRUE(sp.empty());
56 EXPECT_EQ(bb.count(), 32u) << bb;
57 EXPECT_EQ(bb.free_count(), 32u) << bb;
58 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x11223344) << 32) << bb;
59
60 s.clear();
61 s.push_back('\x55');
62 s.push_back('\x66');
63 s.push_back('\x77');
64 s.push_back('\x88');
65 s.push_back('\x99');
66 sp = s;
67
68 sp.remove_prefix(bb.AppendBytes(sp));
69 EXPECT_EQ(sp.size(), 1u);
70 EXPECT_EQ('\x99', sp[0]);
71 EXPECT_EQ(bb.count(), 64u) << bb;
72 EXPECT_EQ(bb.free_count(), 0u) << bb;
73 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x1122334455667788LL)) << bb;
74
75 sp.remove_prefix(bb.AppendBytes(sp));
76 EXPECT_EQ(sp.size(), 1u);
77 EXPECT_EQ('\x99', sp[0]);
78 EXPECT_EQ(bb.count(), 64u) << bb;
79 EXPECT_EQ(bb.free_count(), 0u) << bb;
80 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x1122334455667788LL)) << bb;
81}
82
83TEST(HuffmanBitBufferTest, ConsumeBits) {
84 Http2String s;
85 s.push_back('\x11');
86 s.push_back('\x22');
87 s.push_back('\x33');
88 Http2StringPiece sp(s);
89
90 HuffmanBitBuffer bb;
91 sp.remove_prefix(bb.AppendBytes(sp));
92 EXPECT_TRUE(sp.empty());
93
94 bb.ConsumeBits(1);
95 EXPECT_EQ(bb.count(), 23u) << bb;
96 EXPECT_EQ(bb.free_count(), 41u) << bb;
97 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x112233) << 41) << bb;
98
99 bb.ConsumeBits(20);
100 EXPECT_EQ(bb.count(), 3u) << bb;
101 EXPECT_EQ(bb.free_count(), 61u) << bb;
102 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x3) << 61) << bb;
103}
104
105TEST(HuffmanBitBufferTest, AppendBytesUnaligned) {
106 Http2String s;
107 s.push_back('\x11');
108 s.push_back('\x22');
109 s.push_back('\x33');
110 s.push_back('\x44');
111 s.push_back('\x55');
112 s.push_back('\x66');
113 s.push_back('\x77');
114 s.push_back('\x88');
115 s.push_back('\x99');
116 s.push_back('\xaa');
117 s.push_back('\xbb');
118 s.push_back('\xcc');
119 s.push_back('\xdd');
120 Http2StringPiece sp(s);
121
122 HuffmanBitBuffer bb;
123 sp.remove_prefix(bb.AppendBytes(sp));
124 EXPECT_EQ(sp.size(), 5u);
125 EXPECT_FALSE(bb.InputProperlyTerminated());
126
127 bb.ConsumeBits(15);
128 EXPECT_EQ(bb.count(), 49u) << bb;
129 EXPECT_EQ(bb.free_count(), 15u) << bb;
130
131 HuffmanAccumulator expected(0x1122334455667788);
132 expected <<= 15;
133 EXPECT_EQ(bb.value(), expected);
134
135 sp.remove_prefix(bb.AppendBytes(sp));
136 EXPECT_EQ(sp.size(), 4u);
137 EXPECT_EQ(bb.count(), 57u) << bb;
138 EXPECT_EQ(bb.free_count(), 7u) << bb;
139
140 expected |= (HuffmanAccumulator(0x99) << 7);
141 EXPECT_EQ(bb.value(), expected)
142 << bb << std::hex << "\n actual: " << bb.value()
143 << "\n expected: " << expected;
144}
145
146class HpackHuffmanDecoderTest : public RandomDecoderTest {
147 protected:
148 HpackHuffmanDecoderTest() {
149 // The decoder may return true, and its accumulator may be empty, at
150 // many boundaries while decoding, and yet the whole string hasn't
151 // been decoded.
152 stop_decode_on_done_ = false;
153 }
154
155 DecodeStatus StartDecoding(DecodeBuffer* b) override {
156 input_bytes_seen_ = 0;
157 output_buffer_.clear();
158 decoder_.Reset();
159 return ResumeDecoding(b);
160 }
161
162 DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
163 input_bytes_seen_ += b->Remaining();
164 Http2StringPiece sp(b->cursor(), b->Remaining());
165 if (decoder_.Decode(sp, &output_buffer_)) {
166 b->AdvanceCursor(b->Remaining());
167 // Successfully decoded (or buffered) the bytes in Http2StringPiece.
168 EXPECT_LE(input_bytes_seen_, input_bytes_expected_);
169 // Have we reached the end of the encoded string?
170 if (input_bytes_expected_ == input_bytes_seen_) {
171 if (decoder_.InputProperlyTerminated()) {
172 return DecodeStatus::kDecodeDone;
173 } else {
174 return DecodeStatus::kDecodeError;
175 }
176 }
177 return DecodeStatus::kDecodeInProgress;
178 }
179 return DecodeStatus::kDecodeError;
180 }
181
182 HpackHuffmanDecoder decoder_;
183 Http2String output_buffer_;
184 size_t input_bytes_seen_;
185 size_t input_bytes_expected_;
186};
187
188TEST_F(HpackHuffmanDecoderTest, SpecRequestExamples) {
189 HpackHuffmanDecoder decoder;
190 Http2String test_table[] = {
191 Http2HexDecode("f1e3c2e5f23a6ba0ab90f4ff"),
192 "www.example.com",
193 Http2HexDecode("a8eb10649cbf"),
194 "no-cache",
195 Http2HexDecode("25a849e95ba97d7f"),
196 "custom-key",
197 Http2HexDecode("25a849e95bb8e8b4bf"),
198 "custom-value",
199 };
200 for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); i += 2) {
201 const Http2String& huffman_encoded(test_table[i]);
202 const Http2String& plain_string(test_table[i + 1]);
203 Http2String buffer;
204 decoder.Reset();
205 EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder;
206 EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder;
207 EXPECT_EQ(buffer, plain_string);
208 }
209}
210
211TEST_F(HpackHuffmanDecoderTest, SpecResponseExamples) {
212 HpackHuffmanDecoder decoder;
213 // clang-format off
214 Http2String test_table[] = {
215 Http2HexDecode("6402"),
216 "302",
217 Http2HexDecode("aec3771a4b"),
218 "private",
219 Http2HexDecode("d07abe941054d444a8200595040b8166"
220 "e082a62d1bff"),
221 "Mon, 21 Oct 2013 20:13:21 GMT",
222 Http2HexDecode("9d29ad171863c78f0b97c8e9ae82ae43"
223 "d3"),
224 "https://www.example.com",
225 Http2HexDecode("94e7821dd7f2e6c7b335dfdfcd5b3960"
226 "d5af27087f3672c1ab270fb5291f9587"
227 "316065c003ed4ee5b1063d5007"),
228 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
229 };
230 // clang-format on
231 for (size_t i = 0; i != HTTP2_ARRAYSIZE(test_table); i += 2) {
232 const Http2String& huffman_encoded(test_table[i]);
233 const Http2String& plain_string(test_table[i + 1]);
234 Http2String buffer;
235 decoder.Reset();
236 EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder;
237 EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder;
238 EXPECT_EQ(buffer, plain_string);
239 }
240}
241
242} // namespace
243} // namespace test
244} // namespace http2