OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http2/decoder/decode_buffer.h" | 5 #include "net/http2/decoder/decode_buffer.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/callback.h" | |
12 #include "base/logging.h" | 9 #include "base/logging.h" |
13 #include "base/strings/string_piece.h" | 10 #include "base/strings/string_piece.h" |
14 #include "net/http2/tools/http2_random.h" | 11 #include "net/http2/tools/http2_random.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
16 | 13 |
17 using base::StringPiece; | 14 using base::StringPiece; |
18 using std::string; | 15 using std::string; |
19 | 16 |
20 namespace net { | 17 namespace net { |
21 namespace test { | 18 namespace test { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 class DecodeBufferTest : public ::testing::Test { | 58 class DecodeBufferTest : public ::testing::Test { |
62 public: | 59 public: |
63 DecodeBufferTest() {} | 60 DecodeBufferTest() {} |
64 | 61 |
65 protected: | 62 protected: |
66 // Double checks the call fn(f). | 63 // Double checks the call fn(f). |
67 template <typename T> | 64 template <typename T> |
68 bool SlowDecodeField(DecodeBuffer* b, | 65 bool SlowDecodeField(DecodeBuffer* b, |
69 size_t field_size, | 66 size_t field_size, |
70 size_t field_offset, | 67 size_t field_offset, |
71 const base::Callback<bool(DecodeBuffer*)>& fn, | 68 std::function<bool(DecodeBuffer*)> fn, |
72 T* f) { | 69 T* f) { |
73 VLOG(2) << "Remaining: " << b->Remaining(); | 70 VLOG(2) << "Remaining: " << b->Remaining(); |
74 VLOG(2) << "field_size: " << field_size; | 71 VLOG(2) << "field_size: " << field_size; |
75 VLOG(2) << "field_offset: " << field_offset; | 72 VLOG(2) << "field_offset: " << field_offset; |
76 VLOG(2) << "decode_offset_: " << decode_offset_; | 73 VLOG(2) << "decode_offset_: " << decode_offset_; |
77 EXPECT_GE(decode_offset_, field_offset); | 74 EXPECT_GE(decode_offset_, field_offset); |
78 bool had_data = b->HasData(); | 75 bool had_data = b->HasData(); |
79 VLOG(2) << "had_data: " << had_data; | 76 VLOG(2) << "had_data: " << had_data; |
80 uint32_t old = static_cast<uint32_t>(*f); | 77 uint32_t old = static_cast<uint32_t>(*f); |
81 VLOG(2) << "old: " << old; | 78 VLOG(2) << "old: " << old; |
82 size_t old_decode_offset = decode_offset_; | 79 size_t old_decode_offset = decode_offset_; |
83 bool done = fn.Run(b); | 80 bool done = fn(b); |
84 VLOG(2) << "done: " << done; | 81 VLOG(2) << "done: " << done; |
85 if (old_decode_offset == decode_offset_) { | 82 if (old_decode_offset == decode_offset_) { |
86 // Didn't do any decoding (may have no input, or may have already | 83 // Didn't do any decoding (may have no input, or may have already |
87 // decoded this field). | 84 // decoded this field). |
88 if (done) { | 85 if (done) { |
89 EXPECT_LE(field_offset + field_size, decode_offset_); | 86 EXPECT_LE(field_offset + field_size, decode_offset_); |
90 // Shouldn't have modified already decoded field. | 87 // Shouldn't have modified already decoded field. |
91 EXPECT_EQ(old, static_cast<uint32_t>(*f)); | 88 EXPECT_EQ(old, static_cast<uint32_t>(*f)); |
92 } else { | 89 } else { |
93 EXPECT_TRUE(!had_data); | 90 EXPECT_TRUE(!had_data); |
94 } | 91 } |
95 } else { | 92 } else { |
96 // Did some decoding. | 93 // Did some decoding. |
97 EXPECT_TRUE(had_data); | 94 EXPECT_TRUE(had_data); |
98 EXPECT_LT(old_decode_offset, decode_offset_); | 95 EXPECT_LT(old_decode_offset, decode_offset_); |
99 if (done) { | 96 if (done) { |
100 EXPECT_EQ(field_offset + field_size, decode_offset_); | 97 EXPECT_EQ(field_offset + field_size, decode_offset_); |
101 } else { | 98 } else { |
102 EXPECT_GT(field_offset + field_size, decode_offset_); | 99 EXPECT_GT(field_offset + field_size, decode_offset_); |
103 } | 100 } |
104 } | 101 } |
105 VLOG(2) << "---------------------------------------"; | 102 VLOG(2) << "---------------------------------------"; |
106 return done; | 103 return done; |
107 } | 104 } |
108 | 105 |
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 | 106 |
134 void SlowDecodeTestStruct(StringPiece input, TestStruct* p) { | 107 void SlowDecodeTestStruct(StringPiece input, TestStruct* p) { |
135 VLOG(2) << "############################################################"; | 108 VLOG(2) << "############################################################"; |
136 EXPECT_LE(10u, input.size()); | 109 EXPECT_LE(10u, input.size()); |
137 decode_offset_ = 0; | 110 decode_offset_ = 0; |
| 111 auto decode_f1 = [this, p](DecodeBuffer* db) { |
| 112 return db->SlowDecodeUInt8(kF1Offset, &decode_offset_, &p->f1); |
| 113 }; |
| 114 auto decode_f2 = [this, p](DecodeBuffer* db) { |
| 115 return db->SlowDecodeUInt16(kF2Offset, &decode_offset_, &p->f2); |
| 116 }; |
| 117 auto decode_f3 = [this, p](DecodeBuffer* db) { |
| 118 return db->SlowDecodeUInt24(kF3Offset, &decode_offset_, &p->f3); |
| 119 }; |
| 120 auto decode_f4 = [this, p](DecodeBuffer* db) { |
| 121 return db->SlowDecodeUInt32(kF4Offset, &decode_offset_, &p->f4); |
| 122 }; |
| 123 auto decode_f5 = [this, p](DecodeBuffer* db) { |
| 124 return db->SlowDecodeUInt31(kF5Offset, &decode_offset_, &p->f5); |
| 125 }; |
| 126 auto decode_f6 = [this, p](DecodeBuffer* db) { |
| 127 return db->SlowDecodeEnum(4, kF6Offset, &decode_offset_, &p->f6); |
| 128 }; |
| 129 auto decode_f7 = [this, p](DecodeBuffer* db) { |
| 130 return db->SlowDecodeEnum(1, kF7Offset, &decode_offset_, &p->f7); |
| 131 }; |
| 132 auto decode_f8 = [this, p](DecodeBuffer* db) { |
| 133 return db->SlowDecodeEnum(1, kF8Offset, &decode_offset_, &p->f8); |
| 134 }; |
138 while (input.size() > 0) { | 135 while (input.size() > 0) { |
139 size_t size = input.size(); | 136 size_t size = input.size(); |
140 // Sometimes check that zero length input is OK. | 137 // Sometimes check that zero length input is OK. |
141 auto r = random_.Next(); | 138 auto r = random_.Next(); |
142 if (r % 100 == 0) { | 139 if (r % 100 == 0) { |
143 size = 0; | 140 size = 0; |
144 } else if (size > 1) { | 141 } else if (size > 1) { |
145 auto r = random_.Next(); | 142 auto r = random_.Next(); |
146 size = (r % size) + 1; | 143 size = (r % size) + 1; |
147 } | 144 } |
148 VLOG(2) << "================= input size " << size; | 145 VLOG(2) << "================= input size " << size; |
149 DecodeBuffer b(input.data(), size); | 146 DecodeBuffer b(input.data(), size); |
150 size_t old_decode_offset = decode_offset_; | 147 size_t old_decode_offset = decode_offset_; |
151 if (SlowDecodeField(&b, 1, kF1Offset, | 148 if (SlowDecodeField(&b, 1, kF1Offset, decode_f1, &p->f1) && |
152 base::Bind(&DecodeBufferTest::decode_f1, | 149 SlowDecodeField(&b, 2, kF2Offset, decode_f2, &p->f2) && |
153 base::Unretained(this), p), | 150 SlowDecodeField(&b, 3, kF3Offset, decode_f3, &p->f3) && |
154 &p->f1) && | 151 SlowDecodeField(&b, 4, kF4Offset, decode_f4, &p->f4) && |
155 SlowDecodeField(&b, 2, kF2Offset, | 152 SlowDecodeField(&b, 4, kF5Offset, decode_f5, &p->f5) && |
156 base::Bind(&DecodeBufferTest::decode_f2, | 153 SlowDecodeField(&b, 4, kF6Offset, decode_f6, &p->f6) && |
157 base::Unretained(this), p), | 154 SlowDecodeField(&b, 1, kF7Offset, decode_f7, &p->f7) && |
158 &p->f2) && | 155 SlowDecodeField(&b, 1, kF8Offset, decode_f8, &p->f8)) { |
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()); | 156 EXPECT_TRUE(b.Empty()); |
184 EXPECT_EQ(size, input.size()); | 157 EXPECT_EQ(size, input.size()); |
185 EXPECT_EQ(input.size(), b.Offset()); // All input consumed. | 158 EXPECT_EQ(input.size(), b.Offset()); // All input consumed. |
186 return; | 159 return; |
187 } | 160 } |
188 EXPECT_EQ(old_decode_offset + size, decode_offset_); | 161 EXPECT_EQ(old_decode_offset + size, decode_offset_); |
189 EXPECT_TRUE(b.Empty()); | 162 EXPECT_TRUE(b.Empty()); |
190 EXPECT_EQ(size, b.Offset()); // All input consumed. | 163 EXPECT_EQ(size, b.Offset()); // All input consumed. |
191 EXPECT_LT(size, input.size()); // More remains. | 164 EXPECT_LT(size, input.size()); // More remains. |
192 input = StringPiece(input.data() + size, input.size() - size); | 165 input = StringPiece(input.data() + size, input.size() - size); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 }; | 211 }; |
239 // clang-format on | 212 // clang-format on |
240 StringPiece input(data, sizeof data); | 213 StringPiece input(data, sizeof data); |
241 for (int i = 0; i < 200; ++i) { | 214 for (int i = 0; i < 200; ++i) { |
242 TestStruct ts; | 215 TestStruct ts; |
243 // Init the struct to random garbage. | 216 // Init the struct to random garbage. |
244 ts.f1 = random_.Rand8(); | 217 ts.f1 = random_.Rand8(); |
245 ts.f2 = random_.Rand16(); | 218 ts.f2 = random_.Rand16(); |
246 ts.f3 = random_.Rand32(); | 219 ts.f3 = random_.Rand32(); |
247 ts.f4 = random_.Rand32(); | 220 ts.f4 = random_.Rand32(); |
248 // Ensure high-bit is set. | |
249 ts.f5 = 0x80000000 | random_.Rand32(); // Ensure high-bit is set. | 221 ts.f5 = 0x80000000 | random_.Rand32(); // Ensure high-bit is set. |
250 ts.f6 = static_cast<TestEnumClass32>(random_.Rand32()); | 222 ts.f6 = static_cast<TestEnumClass32>(random_.Rand32()); |
251 ts.f7 = static_cast<TestEnumClass8>(random_.Rand8()); | 223 ts.f7 = static_cast<TestEnumClass8>(random_.Rand8()); |
252 ts.f8 = static_cast<TestEnum8>(random_.Rand8()); | 224 ts.f8 = static_cast<TestEnum8>(random_.Rand8()); |
253 SlowDecodeTestStruct(input, &ts); | 225 SlowDecodeTestStruct(input, &ts); |
254 ASSERT_EQ(0x12u, ts.f1); | 226 ASSERT_EQ(0x12u, ts.f1); |
255 ASSERT_EQ(0x2334u, ts.f2); | 227 ASSERT_EQ(0x2334u, ts.f2); |
256 ASSERT_EQ(0x455667u, ts.f3); | 228 ASSERT_EQ(0x455667u, ts.f3); |
257 ASSERT_EQ(0x78899AABu, ts.f4); | 229 ASSERT_EQ(0x78899AABu, ts.f4); |
258 ASSERT_EQ(0x7EEDDCCBu, ts.f5); | 230 ASSERT_EQ(0x7EEDDCCBu, ts.f5); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 { | 369 { |
398 DecodeBufferSubset subset1(&base, 2); | 370 DecodeBufferSubset subset1(&base, 2); |
399 base.AdvanceCursor(1); | 371 base.AdvanceCursor(1); |
400 }, | 372 }, |
401 "Access via subset only when present"); | 373 "Access via subset only when present"); |
402 } | 374 } |
403 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | 375 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) |
404 | 376 |
405 } // namespace test | 377 } // namespace test |
406 } // namespace net | 378 } // namespace net |
OLD | NEW |