Chromium Code Reviews| 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. | 221 // Ensure high-bit is set. |
|
James Synge
2017/01/05 21:39:06
Remove comment, it is on the next line.
Bence
2017/01/06 01:42:40
Done.
| |
| 249 ts.f5 = 0x80000000 | random_.Rand32(); // Ensure high-bit is set. | 222 ts.f5 = 0x80000000 | random_.Rand32(); // Ensure high-bit is set. |
| 250 ts.f6 = static_cast<TestEnumClass32>(random_.Rand32()); | 223 ts.f6 = static_cast<TestEnumClass32>(random_.Rand32()); |
| 251 ts.f7 = static_cast<TestEnumClass8>(random_.Rand8()); | 224 ts.f7 = static_cast<TestEnumClass8>(random_.Rand8()); |
| 252 ts.f8 = static_cast<TestEnum8>(random_.Rand8()); | 225 ts.f8 = static_cast<TestEnum8>(random_.Rand8()); |
| 253 SlowDecodeTestStruct(input, &ts); | 226 SlowDecodeTestStruct(input, &ts); |
| 254 ASSERT_EQ(0x12u, ts.f1); | 227 ASSERT_EQ(0x12u, ts.f1); |
| 255 ASSERT_EQ(0x2334u, ts.f2); | 228 ASSERT_EQ(0x2334u, ts.f2); |
| 256 ASSERT_EQ(0x455667u, ts.f3); | 229 ASSERT_EQ(0x455667u, ts.f3); |
| 257 ASSERT_EQ(0x78899AABu, ts.f4); | 230 ASSERT_EQ(0x78899AABu, ts.f4); |
| 258 ASSERT_EQ(0x7EEDDCCBu, ts.f5); | 231 ASSERT_EQ(0x7EEDDCCBu, ts.f5); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 397 { | 370 { |
| 398 DecodeBufferSubset subset1(&base, 2); | 371 DecodeBufferSubset subset1(&base, 2); |
| 399 base.AdvanceCursor(1); | 372 base.AdvanceCursor(1); |
| 400 }, | 373 }, |
| 401 "Access via subset only when present"); | 374 "Access via subset only when present"); |
| 402 } | 375 } |
| 403 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | 376 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) |
| 404 | 377 |
| 405 } // namespace test | 378 } // namespace test |
| 406 } // namespace net | 379 } // namespace net |
| OLD | NEW |