OLD | NEW |
| (Empty) |
1 // 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/http2/hpack/huffman/http2_hpack_huffman_decoder.h" | |
6 | |
7 // Tests of HpackHuffmanDecoder and HuffmanBitBuffer. | |
8 | |
9 #include <iostream> | |
10 #include <string> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/bind_helpers.h" | |
14 #include "base/macros.h" | |
15 #include "base/strings/string_piece.h" | |
16 #include "net/http2/decoder/decode_buffer.h" | |
17 #include "net/http2/decoder/decode_status.h" | |
18 #include "net/http2/tools/failure.h" | |
19 #include "net/http2/tools/random_decoder_test.h" | |
20 #include "net/spdy/spdy_test_utils.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 | |
23 using ::testing::AssertionResult; | |
24 using ::testing::AssertionSuccess; | |
25 using base::StringPiece; | |
26 using std::string; | |
27 | |
28 namespace net { | |
29 namespace test { | |
30 namespace { | |
31 | |
32 TEST(HuffmanBitBufferTest, Reset) { | |
33 HuffmanBitBuffer bb; | |
34 EXPECT_TRUE(bb.IsEmpty()); | |
35 EXPECT_TRUE(bb.InputProperlyTerminated()); | |
36 EXPECT_EQ(bb.count(), 0u); | |
37 EXPECT_EQ(bb.free_count(), 64u); | |
38 EXPECT_EQ(bb.value(), 0u); | |
39 } | |
40 | |
41 TEST(HuffmanBitBufferTest, AppendBytesAligned) { | |
42 string s; | |
43 s.push_back('\x11'); | |
44 s.push_back('\x22'); | |
45 s.push_back('\x33'); | |
46 StringPiece sp(s); | |
47 | |
48 HuffmanBitBuffer bb; | |
49 sp.remove_prefix(bb.AppendBytes(sp)); | |
50 EXPECT_TRUE(sp.empty()); | |
51 EXPECT_FALSE(bb.IsEmpty()) << bb; | |
52 EXPECT_FALSE(bb.InputProperlyTerminated()); | |
53 EXPECT_EQ(bb.count(), 24u) << bb; | |
54 EXPECT_EQ(bb.free_count(), 40u) << bb; | |
55 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x112233) << 40) << bb; | |
56 | |
57 s.clear(); | |
58 s.push_back('\x44'); | |
59 sp = s; | |
60 | |
61 sp.remove_prefix(bb.AppendBytes(sp)); | |
62 EXPECT_TRUE(sp.empty()); | |
63 EXPECT_EQ(bb.count(), 32u) << bb; | |
64 EXPECT_EQ(bb.free_count(), 32u) << bb; | |
65 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x11223344) << 32) << bb; | |
66 | |
67 s.clear(); | |
68 s.push_back('\x55'); | |
69 s.push_back('\x66'); | |
70 s.push_back('\x77'); | |
71 s.push_back('\x88'); | |
72 s.push_back('\x99'); | |
73 sp = s; | |
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 sp.remove_prefix(bb.AppendBytes(sp)); | |
83 EXPECT_EQ(sp.size(), 1u); | |
84 EXPECT_EQ('\x99', sp[0]); | |
85 EXPECT_EQ(bb.count(), 64u) << bb; | |
86 EXPECT_EQ(bb.free_count(), 0u) << bb; | |
87 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x1122334455667788LL)) << bb; | |
88 } | |
89 | |
90 TEST(HuffmanBitBufferTest, ConsumeBits) { | |
91 string s; | |
92 s.push_back('\x11'); | |
93 s.push_back('\x22'); | |
94 s.push_back('\x33'); | |
95 StringPiece sp(s); | |
96 | |
97 HuffmanBitBuffer bb; | |
98 sp.remove_prefix(bb.AppendBytes(sp)); | |
99 EXPECT_TRUE(sp.empty()); | |
100 | |
101 bb.ConsumeBits(1); | |
102 EXPECT_EQ(bb.count(), 23u) << bb; | |
103 EXPECT_EQ(bb.free_count(), 41u) << bb; | |
104 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x112233) << 41) << bb; | |
105 | |
106 bb.ConsumeBits(20); | |
107 EXPECT_EQ(bb.count(), 3u) << bb; | |
108 EXPECT_EQ(bb.free_count(), 61u) << bb; | |
109 EXPECT_EQ(bb.value(), HuffmanAccumulator(0x3) << 61) << bb; | |
110 } | |
111 | |
112 TEST(HuffmanBitBufferTest, AppendBytesUnaligned) { | |
113 string s; | |
114 s.push_back('\x11'); | |
115 s.push_back('\x22'); | |
116 s.push_back('\x33'); | |
117 s.push_back('\x44'); | |
118 s.push_back('\x55'); | |
119 s.push_back('\x66'); | |
120 s.push_back('\x77'); | |
121 s.push_back('\x88'); | |
122 s.push_back('\x99'); | |
123 s.push_back('\xaa'); | |
124 s.push_back('\xbb'); | |
125 s.push_back('\xcc'); | |
126 s.push_back('\xdd'); | |
127 StringPiece sp(s); | |
128 | |
129 HuffmanBitBuffer bb; | |
130 sp.remove_prefix(bb.AppendBytes(sp)); | |
131 EXPECT_EQ(sp.size(), 5u); | |
132 EXPECT_FALSE(bb.InputProperlyTerminated()); | |
133 | |
134 bb.ConsumeBits(15); | |
135 EXPECT_EQ(bb.count(), 49u) << bb; | |
136 EXPECT_EQ(bb.free_count(), 15u) << bb; | |
137 | |
138 HuffmanAccumulator expected(0x1122334455667788); | |
139 expected <<= 15; | |
140 EXPECT_EQ(bb.value(), expected); | |
141 | |
142 sp.remove_prefix(bb.AppendBytes(sp)); | |
143 EXPECT_EQ(sp.size(), 4u); | |
144 EXPECT_EQ(bb.count(), 57u) << bb; | |
145 EXPECT_EQ(bb.free_count(), 7u) << bb; | |
146 | |
147 expected |= (HuffmanAccumulator(0x99) << 7); | |
148 EXPECT_EQ(bb.value(), expected) << bb << std::hex | |
149 << "\n actual: " << bb.value() | |
150 << "\n expected: " << expected; | |
151 } | |
152 | |
153 enum class DecoderChoice { IF_TREE, SHORT_CODE }; | |
154 | |
155 class HpackHuffmanDecoderTest | |
156 : public RandomDecoderTest, | |
157 public ::testing::WithParamInterface<DecoderChoice> { | |
158 protected: | |
159 HpackHuffmanDecoderTest() { | |
160 // The decoder may return true, and its accumulator may be empty, at | |
161 // many boundaries while decoding, and yet the whole string hasn't | |
162 // been decoded. | |
163 stop_decode_on_done_ = false; | |
164 } | |
165 | |
166 DecodeStatus StartDecoding(DecodeBuffer* b) override { | |
167 input_bytes_seen_ = 0; | |
168 output_buffer_.clear(); | |
169 decoder_.Reset(); | |
170 return ResumeDecoding(b); | |
171 } | |
172 | |
173 DecodeStatus ResumeDecoding(DecodeBuffer* b) override { | |
174 input_bytes_seen_ += b->Remaining(); | |
175 StringPiece sp(b->cursor(), b->Remaining()); | |
176 if (DecodeFragment(sp)) { | |
177 b->AdvanceCursor(b->Remaining()); | |
178 // Successfully decoded (or buffered) the bytes in StringPiece. | |
179 EXPECT_LE(input_bytes_seen_, input_bytes_expected_); | |
180 // Have we reached the end of the encoded string? | |
181 if (input_bytes_expected_ == input_bytes_seen_) { | |
182 if (decoder_.InputProperlyTerminated()) { | |
183 return DecodeStatus::kDecodeDone; | |
184 } else { | |
185 return DecodeStatus::kDecodeError; | |
186 } | |
187 } | |
188 return DecodeStatus::kDecodeInProgress; | |
189 } | |
190 return DecodeStatus::kDecodeError; | |
191 } | |
192 | |
193 bool DecodeFragment(StringPiece sp) { | |
194 switch (GetParam()) { | |
195 case DecoderChoice::IF_TREE: | |
196 return decoder_.DecodeWithIfTreeAndStruct(sp, &output_buffer_); | |
197 case DecoderChoice::SHORT_CODE: | |
198 return decoder_.DecodeShortCodesFirst(sp, &output_buffer_); | |
199 } | |
200 | |
201 NOTREACHED(); | |
202 return false; | |
203 } | |
204 | |
205 AssertionResult ValidatorForHuffmanDecodeAndValidateSeveralWays( | |
206 StringPiece expected_plain) { | |
207 VERIFY_EQ(output_buffer_.size(), expected_plain.size()); | |
208 VERIFY_EQ(output_buffer_, expected_plain); | |
209 return AssertionSuccess(); | |
210 } | |
211 | |
212 AssertionResult HuffmanDecodeAndValidateSeveralWays( | |
213 StringPiece encoded, | |
214 StringPiece expected_plain) { | |
215 input_bytes_expected_ = encoded.size(); | |
216 DecodeBuffer db(encoded); | |
217 bool return_non_zero_on_first = false; | |
218 return DecodeAndValidateSeveralWays( | |
219 &db, return_non_zero_on_first, | |
220 ValidateDoneAndEmpty( | |
221 base::Bind(&HpackHuffmanDecoderTest:: | |
222 ValidatorForHuffmanDecodeAndValidateSeveralWays, | |
223 base::Unretained(this), expected_plain))); | |
224 } | |
225 | |
226 HpackHuffmanDecoder decoder_; | |
227 string output_buffer_; | |
228 size_t input_bytes_seen_; | |
229 size_t input_bytes_expected_; | |
230 }; | |
231 INSTANTIATE_TEST_CASE_P(AllDecoders, | |
232 HpackHuffmanDecoderTest, | |
233 ::testing::Values(DecoderChoice::IF_TREE, | |
234 DecoderChoice::SHORT_CODE)); | |
235 | |
236 TEST_P(HpackHuffmanDecoderTest, SpecRequestExamples) { | |
237 HpackHuffmanDecoder decoder; | |
238 string test_table[] = { | |
239 a2b_hex("f1e3c2e5f23a6ba0ab90f4ff"), | |
240 "www.example.com", | |
241 a2b_hex("a8eb10649cbf"), | |
242 "no-cache", | |
243 a2b_hex("25a849e95ba97d7f"), | |
244 "custom-key", | |
245 a2b_hex("25a849e95bb8e8b4bf"), | |
246 "custom-value", | |
247 }; | |
248 for (size_t i = 0; i != arraysize(test_table); i += 2) { | |
249 const string& huffman_encoded(test_table[i]); | |
250 const string& plain_string(test_table[i + 1]); | |
251 string buffer; | |
252 decoder.Reset(); | |
253 EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder; | |
254 EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder; | |
255 EXPECT_EQ(buffer, plain_string); | |
256 } | |
257 } | |
258 | |
259 TEST_P(HpackHuffmanDecoderTest, SpecResponseExamples) { | |
260 HpackHuffmanDecoder decoder; | |
261 // clang-format off | |
262 string test_table[] = { | |
263 a2b_hex("6402"), | |
264 "302", | |
265 a2b_hex("aec3771a4b"), | |
266 "private", | |
267 a2b_hex("d07abe941054d444a8200595040b8166" | |
268 "e082a62d1bff"), | |
269 "Mon, 21 Oct 2013 20:13:21 GMT", | |
270 a2b_hex("9d29ad171863c78f0b97c8e9ae82ae43" | |
271 "d3"), | |
272 "https://www.example.com", | |
273 a2b_hex("94e7821dd7f2e6c7b335dfdfcd5b3960" | |
274 "d5af27087f3672c1ab270fb5291f9587" | |
275 "316065c003ed4ee5b1063d5007"), | |
276 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", | |
277 }; | |
278 // clang-format on | |
279 for (size_t i = 0; i != arraysize(test_table); i += 2) { | |
280 const string& huffman_encoded(test_table[i]); | |
281 const string& plain_string(test_table[i + 1]); | |
282 string buffer; | |
283 decoder.Reset(); | |
284 EXPECT_TRUE(decoder.Decode(huffman_encoded, &buffer)) << decoder; | |
285 EXPECT_TRUE(decoder.InputProperlyTerminated()) << decoder; | |
286 EXPECT_EQ(buffer, plain_string); | |
287 } | |
288 } | |
289 | |
290 } // namespace | |
291 } // namespace test | |
292 } // namespace net | |
OLD | NEW |