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/tools/random_decoder_test.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <algorithm> | |
10 #include <memory> | |
11 | |
12 #include "base/logging.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/strings/string_piece.h" | |
15 #include "net/http2/decoder/decode_buffer.h" | |
16 #include "net/http2/decoder/decode_status.h" | |
17 #include "net/http2/http2_constants.h" | |
18 #include "net/http2/tools/failure.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 // It's rather time consuming to decode large buffers one at a time, | |
22 // especially with the log level cranked up. So, by default we don't do | |
23 // that unless explicitly requested. | |
24 | |
25 using ::testing::AssertionFailure; | |
26 using ::testing::AssertionResult; | |
27 using ::testing::AssertionSuccess; | |
28 using base::StringPiece; | |
29 | |
30 namespace net { | |
31 namespace test { | |
32 | |
33 std::string HexEncode(StringPiece s) { | |
34 return base::HexEncode(s.data(), s.size()); | |
35 } | |
36 | |
37 RandomDecoderTest::RandomDecoderTest() {} | |
38 | |
39 bool RandomDecoderTest::StopDecodeOnDone() { | |
40 return stop_decode_on_done_; | |
41 } | |
42 | |
43 DecodeStatus RandomDecoderTest::DecodeSegments(DecodeBuffer* original, | |
44 const SelectSize& select_size) { | |
45 DecodeStatus status = DecodeStatus::kDecodeInProgress; | |
46 bool first = true; | |
47 VLOG(2) << "DecodeSegments: input size=" << original->Remaining(); | |
48 while (first || original->HasData()) { | |
49 size_t remaining = original->Remaining(); | |
50 size_t size = std::min( | |
51 remaining, select_size.Run(first, original->Offset(), remaining)); | |
52 DecodeBuffer db(original->cursor(), size); | |
53 VLOG(2) << "Decoding " << size << " bytes of " << remaining << " remaining"; | |
54 if (first) { | |
55 first = false; | |
56 status = StartDecoding(&db); | |
57 } else { | |
58 status = ResumeDecoding(&db); | |
59 } | |
60 // A decoder MUST consume some input (if any is available), else we could | |
61 // get stuck in infinite loops. | |
62 if (db.Offset() == 0 && db.HasData() && | |
63 status != DecodeStatus::kDecodeError) { | |
64 ADD_FAILURE() << "Decoder didn't make any progress; db.FullSize=" | |
65 << db.FullSize() | |
66 << " original.Offset=" << original->Offset(); | |
67 return DecodeStatus::kDecodeError; | |
68 } | |
69 original->AdvanceCursor(db.Offset()); | |
70 switch (status) { | |
71 case DecodeStatus::kDecodeDone: | |
72 if (original->Empty() || StopDecodeOnDone()) { | |
73 return DecodeStatus::kDecodeDone; | |
74 } | |
75 continue; | |
76 case DecodeStatus::kDecodeInProgress: | |
77 continue; | |
78 case DecodeStatus::kDecodeError: | |
79 return DecodeStatus::kDecodeError; | |
80 } | |
81 } | |
82 return status; | |
83 } | |
84 | |
85 // Decode |original| multiple times, with different segmentations, validating | |
86 // after each decode, returning on the first failure. | |
87 AssertionResult RandomDecoderTest::DecodeAndValidateSeveralWays( | |
88 DecodeBuffer* original, | |
89 bool return_non_zero_on_first, | |
90 const Validator& validator) { | |
91 const uint32_t original_remaining = original->Remaining(); | |
92 VLOG(1) << "DecodeAndValidateSeveralWays - Start, remaining = " | |
93 << original_remaining; | |
94 uint32_t first_consumed; | |
95 { | |
96 // Fast decode (no stopping unless decoder does so). | |
97 DecodeBuffer input(original->cursor(), original_remaining); | |
98 VLOG(2) << "DecodeSegmentsAndValidate with SelectRemaining"; | |
99 VERIFY_SUCCESS(DecodeSegmentsAndValidate( | |
100 &input, base::Bind(&SelectRemaining), validator)) | |
101 << "\nFailed with SelectRemaining; input.Offset=" << input.Offset() | |
102 << "; input.Remaining=" << input.Remaining(); | |
103 first_consumed = input.Offset(); | |
104 } | |
105 if (original_remaining <= 30) { | |
106 // Decode again, one byte at a time. | |
107 DecodeBuffer input(original->cursor(), original_remaining); | |
108 VLOG(2) << "DecodeSegmentsAndValidate with SelectOne"; | |
109 VERIFY_SUCCESS( | |
110 DecodeSegmentsAndValidate(&input, base::Bind(&SelectOne), validator)) | |
111 << "\nFailed with SelectOne; input.Offset=" << input.Offset() | |
112 << "; input.Remaining=" << input.Remaining(); | |
113 VERIFY_EQ(first_consumed, input.Offset()) << "\nFailed with SelectOne"; | |
114 } | |
115 if (original_remaining <= 20) { | |
116 // Decode again, one or zero bytes at a time. | |
117 DecodeBuffer input(original->cursor(), original_remaining); | |
118 VLOG(2) << "DecodeSegmentsAndValidate with SelectZeroAndOne"; | |
119 bool zero_next = !return_non_zero_on_first; | |
120 VERIFY_SUCCESS(DecodeSegmentsAndValidate( | |
121 &input, base::Bind(&SelectZeroAndOne, &zero_next), validator)) | |
122 << "\nFailed with SelectZeroAndOne"; | |
123 VERIFY_EQ(first_consumed, input.Offset()) | |
124 << "\nFailed with SelectZeroAndOne; input.Offset=" << input.Offset() | |
125 << "; input.Remaining=" << input.Remaining(); | |
126 } | |
127 { | |
128 // Decode again, with randomly selected segment sizes. | |
129 DecodeBuffer input(original->cursor(), original_remaining); | |
130 VLOG(2) << "DecodeSegmentsAndValidate with SelectRandom"; | |
131 VERIFY_SUCCESS(DecodeSegmentsAndValidate( | |
132 &input, base::Bind(&RandomDecoderTest::SelectRandom, | |
133 base::Unretained(this), return_non_zero_on_first), | |
134 validator)) | |
135 << "\nFailed with SelectRandom; input.Offset=" << input.Offset() | |
136 << "; input.Remaining=" << input.Remaining(); | |
137 VERIFY_EQ(first_consumed, input.Offset()) << "\nFailed with SelectRandom"; | |
138 } | |
139 VERIFY_EQ(original_remaining, original->Remaining()); | |
140 original->AdvanceCursor(first_consumed); | |
141 VLOG(1) << "DecodeAndValidateSeveralWays - SUCCESS"; | |
142 return ::testing::AssertionSuccess(); | |
143 } | |
144 | |
145 // static | |
146 size_t RandomDecoderTest::SelectZeroAndOne(bool* zero_next, | |
147 bool first, | |
148 size_t offset, | |
149 size_t remaining) { | |
150 if (*zero_next) { | |
151 *zero_next = false; | |
152 return 0; | |
153 } else { | |
154 *zero_next = true; | |
155 return 1; | |
156 } | |
157 } | |
158 | |
159 size_t RandomDecoderTest::SelectRandom(bool return_non_zero_on_first, | |
160 bool first, | |
161 size_t offset, | |
162 size_t remaining) { | |
163 uint32_t r = random_.Rand32(); | |
164 if (first && return_non_zero_on_first) { | |
165 CHECK_LT(0u, remaining); | |
166 if (remaining == 1) { | |
167 return 1; | |
168 } | |
169 return 1 + (r % remaining); // size in range [1, remaining). | |
170 } | |
171 return r % (remaining + 1); // size in range [0, remaining]. | |
172 } | |
173 | |
174 uint32_t RandomDecoderTest::RandStreamId() { | |
175 return random_.Rand32() & StreamIdMask(); | |
176 } | |
177 | |
178 } // namespace test | |
179 } // namespace net | |
OLD | NEW |