Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(428)

Side by Side Diff: net/http2/decoder/decode_buffer_test.cc

Issue 2293613002: Add new HTTP/2 and HPACK decoder in net/http2/. (Closed)
Patch Set: Replace LOG(INFO) by VLOG(2) in DecodeBufferTest.SlowDecodeTestStruct so that trybots do not fail. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/http2/decoder/decode_buffer.cc ('k') | net/http2/decoder/decode_http2_structures.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/decoder/decode_buffer.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/logging.h"
13 #include "base/strings/string_piece.h"
14 #include "net/http2/tools/http2_random.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using base::StringPiece;
18 using std::string;
19
20 namespace net {
21 namespace test {
22
23 enum class TestEnumClass32 {
24 kValue1 = 1,
25 kValue99 = 99,
26 kValue1M = 1000000,
27 };
28
29 enum class TestEnumClass8 {
30 kValue1 = 1,
31 kValue2 = 1,
32 kValue99 = 99,
33 kValue255 = 255,
34 };
35
36 enum TestEnum8 {
37 kMaskLo = 0x01,
38 kMaskHi = 0x80,
39 };
40
41 struct TestStruct {
42 uint8_t f1;
43 uint16_t f2;
44 uint32_t f3; // Decoded as a uint24
45 uint32_t f4;
46 uint32_t f5; // Decoded as if uint31
47 TestEnumClass32 f6;
48 TestEnumClass8 f7;
49 TestEnum8 f8;
50 };
51
52 const size_t kF1Offset = 0;
53 const size_t kF2Offset = 1;
54 const size_t kF3Offset = 3;
55 const size_t kF4Offset = 6;
56 const size_t kF5Offset = 10;
57 const size_t kF6Offset = 14;
58 const size_t kF7Offset = 18;
59 const size_t kF8Offset = 19;
60
61 class DecodeBufferTest : public ::testing::Test {
62 public:
63 DecodeBufferTest() {}
64
65 protected:
66 // Double checks the call fn(f).
67 template <typename T>
68 bool SlowDecodeField(DecodeBuffer* b,
69 size_t field_size,
70 size_t field_offset,
71 const base::Callback<bool(DecodeBuffer*)>& fn,
72 T* f) {
73 VLOG(2) << "Remaining: " << b->Remaining();
74 VLOG(2) << "field_size: " << field_size;
75 VLOG(2) << "field_offset: " << field_offset;
76 VLOG(2) << "decode_offset_: " << decode_offset_;
77 EXPECT_GE(decode_offset_, field_offset);
78 bool had_data = b->HasData();
79 VLOG(2) << "had_data: " << had_data;
80 uint32_t old = static_cast<uint32_t>(*f);
81 VLOG(2) << "old: " << old;
82 size_t old_decode_offset = decode_offset_;
83 bool done = fn.Run(b);
84 VLOG(2) << "done: " << done;
85 if (old_decode_offset == decode_offset_) {
86 // Didn't do any decoding (may have no input, or may have already
87 // decoded this field).
88 if (done) {
89 EXPECT_LE(field_offset + field_size, decode_offset_);
90 // Shouldn't have modified already decoded field.
91 EXPECT_EQ(old, static_cast<uint32_t>(*f));
92 } else {
93 EXPECT_TRUE(!had_data);
94 }
95 } else {
96 // Did some decoding.
97 EXPECT_TRUE(had_data);
98 EXPECT_LT(old_decode_offset, decode_offset_);
99 if (done) {
100 EXPECT_EQ(field_offset + field_size, decode_offset_);
101 } else {
102 EXPECT_GT(field_offset + field_size, decode_offset_);
103 }
104 }
105 VLOG(2) << "---------------------------------------";
106 return done;
107 }
108
109 bool decode_f1(TestStruct* p, DecodeBuffer* db) {
110 return db->SlowDecodeUInt8(kF1Offset, &decode_offset_, &p->f1);
111 }
112 bool decode_f2(TestStruct* p, DecodeBuffer* db) {
113 return db->SlowDecodeUInt16(kF2Offset, &decode_offset_, &p->f2);
114 }
115 bool decode_f3(TestStruct* p, DecodeBuffer* db) {
116 return db->SlowDecodeUInt24(kF3Offset, &decode_offset_, &p->f3);
117 }
118 bool decode_f4(TestStruct* p, DecodeBuffer* db) {
119 return db->SlowDecodeUInt32(kF4Offset, &decode_offset_, &p->f4);
120 }
121 bool decode_f5(TestStruct* p, DecodeBuffer* db) {
122 return db->SlowDecodeUInt31(kF5Offset, &decode_offset_, &p->f5);
123 }
124 bool decode_f6(TestStruct* p, DecodeBuffer* db) {
125 return db->SlowDecodeEnum(4, kF6Offset, &decode_offset_, &p->f6);
126 }
127 bool decode_f7(TestStruct* p, DecodeBuffer* db) {
128 return db->SlowDecodeEnum(1, kF7Offset, &decode_offset_, &p->f7);
129 }
130 bool decode_f8(TestStruct* p, DecodeBuffer* db) {
131 return db->SlowDecodeEnum(1, kF8Offset, &decode_offset_, &p->f8);
132 }
133
134 void SlowDecodeTestStruct(StringPiece input, TestStruct* p) {
135 VLOG(2) << "############################################################";
136 EXPECT_LE(10u, input.size());
137 decode_offset_ = 0;
138 while (input.size() > 0) {
139 size_t size = input.size();
140 // Sometimes check that zero length input is OK.
141 auto r = random_.Next();
142 if (r % 100 == 0) {
143 size = 0;
144 } else if (size > 1) {
145 auto r = random_.Next();
146 size = (r % size) + 1;
147 }
148 VLOG(2) << "================= input size " << size;
149 DecodeBuffer b(input.data(), size);
150 size_t old_decode_offset = decode_offset_;
151 if (SlowDecodeField(&b, 1, kF1Offset,
152 base::Bind(&DecodeBufferTest::decode_f1,
153 base::Unretained(this), p),
154 &p->f1) &&
155 SlowDecodeField(&b, 2, kF2Offset,
156 base::Bind(&DecodeBufferTest::decode_f2,
157 base::Unretained(this), p),
158 &p->f2) &&
159 SlowDecodeField(&b, 3, kF3Offset,
160 base::Bind(&DecodeBufferTest::decode_f3,
161 base::Unretained(this), p),
162 &p->f3) &&
163 SlowDecodeField(&b, 4, kF4Offset,
164 base::Bind(&DecodeBufferTest::decode_f4,
165 base::Unretained(this), p),
166 &p->f4) &&
167 SlowDecodeField(&b, 4, kF5Offset,
168 base::Bind(&DecodeBufferTest::decode_f5,
169 base::Unretained(this), p),
170 &p->f5) &&
171 SlowDecodeField(&b, 4, kF6Offset,
172 base::Bind(&DecodeBufferTest::decode_f6,
173 base::Unretained(this), p),
174 &p->f6) &&
175 SlowDecodeField(&b, 1, kF7Offset,
176 base::Bind(&DecodeBufferTest::decode_f7,
177 base::Unretained(this), p),
178 &p->f7) &&
179 SlowDecodeField(&b, 1, kF8Offset,
180 base::Bind(&DecodeBufferTest::decode_f8,
181 base::Unretained(this), p),
182 &p->f8)) {
183 EXPECT_TRUE(b.Empty());
184 EXPECT_EQ(size, input.size());
185 EXPECT_EQ(input.size(), b.Offset()); // All input consumed.
186 return;
187 }
188 EXPECT_EQ(old_decode_offset + size, decode_offset_);
189 EXPECT_TRUE(b.Empty());
190 EXPECT_EQ(size, b.Offset()); // All input consumed.
191 EXPECT_LT(size, input.size()); // More remains.
192 input = StringPiece(input.data() + size, input.size() - size);
193 }
194 ADD_FAILURE() << "Ran out of input! decode_offset_ = " << decode_offset_;
195 }
196
197 Http2Random random_;
198 uint32_t decode_offset_;
199 };
200
201 TEST_F(DecodeBufferTest, DecodesFixedInts) {
202 const char data[] = "\x01\x12\x23\x34\x45\x56\x67\x78\x89\x9a";
203 DecodeBuffer b1(data, strlen(data));
204 EXPECT_EQ(1, b1.DecodeUInt8());
205 EXPECT_EQ(0x1223u, b1.DecodeUInt16());
206 EXPECT_EQ(0x344556u, b1.DecodeUInt24());
207 EXPECT_EQ(0x6778899Au, b1.DecodeUInt32());
208
209 DecodeBuffer b2(data, strlen(data));
210 uint8_t b;
211 decode_offset_ = 0;
212 EXPECT_TRUE(b2.SlowDecodeUInt8(0, &decode_offset_, &b));
213 EXPECT_EQ(1, b);
214 uint16_t s;
215 decode_offset_ = 0;
216 EXPECT_TRUE(b2.SlowDecodeUInt16(0, &decode_offset_, &s));
217 EXPECT_EQ(0x1223, s);
218 uint32_t i;
219 decode_offset_ = 0;
220 EXPECT_TRUE(b2.SlowDecodeUInt24(0, &decode_offset_, &i));
221 // EXPECT_EQ(0x344556, b1.DecodeUInt24());
222 // EXPECT_EQ(0x6778899a, b1.DecodeUInt32());
223 }
224
225 // Decode the structure many times, where we'll pass different partitions
226 // into DecodeSlowly.
227 TEST_F(DecodeBufferTest, SlowDecodeTestStruct) {
228 // clang-format off
229 const char data[] = {
230 0x12u, // f1
231 0x23u, 0x34u, // f2
232 0x45u, 0x56u, 0x67u, // f3
233 0x78u, 0x89u, 0x9au, 0xabu, // f4
234 0xfeu, 0xedu, 0xdcu, 0xcbu, // f5 (high-bit will be cleared.)
235 0x00u, 0x0fu, 0x42u, 0x40u, // f6 (kValue1M)
236 0x63u, // f7 (kValue99)
237 0x81u, // f8 (kMaskLo | kMaskHi)
238 };
239 // clang-format on
240 StringPiece input(data, sizeof data);
241 for (int i = 0; i < 200; ++i) {
242 TestStruct ts;
243 // Init the struct to random garbage.
244 ts.f1 = random_.Rand8();
245 ts.f2 = random_.Rand16();
246 ts.f3 = random_.Rand32();
247 ts.f4 = random_.Rand32();
248 // Ensure high-bit is set.
249 ts.f5 = 0x80000000 | random_.Rand32(); // Ensure high-bit is set.
250 ts.f6 = static_cast<TestEnumClass32>(random_.Rand32());
251 ts.f7 = static_cast<TestEnumClass8>(random_.Rand8());
252 ts.f8 = static_cast<TestEnum8>(random_.Rand8());
253 SlowDecodeTestStruct(input, &ts);
254 ASSERT_EQ(0x12u, ts.f1);
255 ASSERT_EQ(0x2334u, ts.f2);
256 ASSERT_EQ(0x455667u, ts.f3);
257 ASSERT_EQ(0x78899AABu, ts.f4);
258 ASSERT_EQ(0x7EEDDCCBu, ts.f5);
259 ASSERT_EQ(TestEnumClass32::kValue1M, ts.f6);
260 ASSERT_EQ(TestEnumClass8::kValue99, ts.f7);
261 ASSERT_EQ(kMaskLo | kMaskHi, ts.f8);
262 }
263 }
264
265 // Make sure that DecodeBuffer is not copying input, just pointing into
266 // provided input buffer.
267 TEST_F(DecodeBufferTest, HasNotCopiedInput) {
268 const char data[] = "ab";
269 DecodeBuffer b1(data, 2);
270
271 EXPECT_EQ(2u, b1.Remaining());
272 EXPECT_EQ(0u, b1.Offset());
273 EXPECT_FALSE(b1.Empty());
274 EXPECT_EQ(data, b1.cursor()); // cursor points to input buffer
275 EXPECT_TRUE(b1.HasData());
276
277 b1.AdvanceCursor(1);
278
279 EXPECT_EQ(1u, b1.Remaining());
280 EXPECT_EQ(1u, b1.Offset());
281 EXPECT_FALSE(b1.Empty());
282 EXPECT_EQ(&data[1], b1.cursor());
283 EXPECT_TRUE(b1.HasData());
284
285 b1.AdvanceCursor(1);
286
287 EXPECT_EQ(0u, b1.Remaining());
288 EXPECT_EQ(2u, b1.Offset());
289 EXPECT_TRUE(b1.Empty());
290 EXPECT_EQ(&data[2], b1.cursor());
291 EXPECT_FALSE(b1.HasData());
292
293 DecodeBuffer b2(data, 0);
294
295 EXPECT_EQ(0u, b2.Remaining());
296 EXPECT_EQ(0u, b2.Offset());
297 EXPECT_TRUE(b2.Empty());
298 EXPECT_EQ(data, b2.cursor());
299 EXPECT_FALSE(b2.HasData());
300 }
301
302 // DecodeBufferSubset can't go beyond the end of the base buffer.
303 TEST_F(DecodeBufferTest, DecodeBufferSubsetLimited) {
304 const char data[] = "abc";
305 DecodeBuffer base(data, 3);
306 base.AdvanceCursor(1);
307 DecodeBufferSubset subset(&base, 100);
308 EXPECT_EQ(2u, subset.FullSize());
309 }
310
311 // DecodeBufferSubset advances the cursor of its base upon destruction.
312 TEST_F(DecodeBufferTest, DecodeBufferSubsetAdvancesCursor) {
313 const char data[] = "abc";
314 const size_t size = sizeof(data) - 1;
315 EXPECT_EQ(3u, size);
316 DecodeBuffer base(data, size);
317 {
318 // First no change to the cursor.
319 DecodeBufferSubset subset(&base, size + 100);
320 EXPECT_EQ(size, subset.FullSize());
321 EXPECT_EQ(base.FullSize(), subset.FullSize());
322 EXPECT_EQ(0u, subset.Offset());
323 }
324 EXPECT_EQ(0u, base.Offset());
325 EXPECT_EQ(size, base.Remaining());
326 }
327
328 // Make sure that DecodeBuffer ctor complains about bad args.
329 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
330 TEST(DecodeBufferDeathTest, NonNullBufferRequired) {
331 EXPECT_DEBUG_DEATH({ DecodeBuffer b(nullptr, 3); }, "nullptr");
332 }
333
334 // Make sure that DecodeBuffer ctor complains about bad args.
335 TEST(DecodeBufferDeathTest, ModestBufferSizeRequired) {
336 EXPECT_DEBUG_DEATH(
337 {
338 const char data[] = "abc";
339 size_t len = 0;
340 DecodeBuffer b(data, ~len);
341 },
342 "Max.*Length");
343 }
344
345 // Make sure that DecodeBuffer detects advance beyond end, in debug mode.
346 TEST(DecodeBufferDeathTest, LimitedAdvance) {
347 {
348 // Advance right up to end is OK.
349 const char data[] = "abc";
350 DecodeBuffer b(data, 3);
351 b.AdvanceCursor(3); // OK
352 EXPECT_TRUE(b.Empty());
353 }
354 EXPECT_DEBUG_DEATH(
355 {
356 // Going beyond is not OK.
357 const char data[] = "abc";
358 DecodeBuffer b(data, 3);
359 b.AdvanceCursor(4);
360 },
361 "4 vs. 3");
362 }
363
364 // Make sure that DecodeBuffer detects decode beyond end, in debug mode.
365 TEST(DecodeBufferDeathTest, DecodeUInt8PastEnd) {
366 const char data[] = {0x12, 0x23};
367 DecodeBuffer b(data, sizeof data);
368 EXPECT_EQ(2u, b.FullSize());
369 EXPECT_EQ(0x1223, b.DecodeUInt16());
370 EXPECT_DEBUG_DEATH({ b.DecodeUInt8(); }, "1 vs. 0");
371 }
372
373 // Make sure that DecodeBuffer detects decode beyond end, in debug mode.
374 TEST(DecodeBufferDeathTest, DecodeUInt16OverEnd) {
375 const char data[] = {0x12, 0x23, 0x34};
376 DecodeBuffer b(data, sizeof data);
377 EXPECT_EQ(3u, b.FullSize());
378 EXPECT_EQ(0x1223, b.DecodeUInt16());
379 EXPECT_DEBUG_DEATH({ b.DecodeUInt16(); }, "2 vs. 1");
380 }
381
382 // Make sure that DecodeBuffer doesn't agree with having two subsets.
383 TEST(DecodeBufferSubsetDeathTest, TwoSubsets) {
384 const char data[] = "abc";
385 DecodeBuffer base(data, 3);
386 DecodeBufferSubset subset1(&base, 1);
387 EXPECT_DEBUG_DEATH({ DecodeBufferSubset subset2(&base, 1); },
388 "There is already a subset");
389 }
390
391 // Make sure that DecodeBufferSubset notices when the base's cursor has moved.
392 TEST(DecodeBufferSubsetDeathTest, BaseCursorAdvanced) {
393 const char data[] = "abc";
394 DecodeBuffer base(data, 3);
395 base.AdvanceCursor(1);
396 EXPECT_DEBUG_DEATH(
397 {
398 DecodeBufferSubset subset1(&base, 2);
399 base.AdvanceCursor(1);
400 },
401 "Access via subset only when present");
402 }
403 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
404
405 } // namespace test
406 } // namespace net
OLDNEW
« no previous file with comments | « net/http2/decoder/decode_buffer.cc ('k') | net/http2/decoder/decode_http2_structures.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698