1 #include "quiche/http2/test_tools/random_decoder_test_base.h"
2 
3 #include <stddef.h>
4 
5 #include <functional>
6 #include <set>
7 #include <type_traits>
8 
9 #include "quiche/http2/decoder/decode_buffer.h"
10 #include "quiche/http2/decoder/decode_status.h"
11 #include "quiche/http2/test_tools/http2_random.h"
12 #include "quiche/common/platform/api/quiche_logging.h"
13 #include "quiche/common/platform/api/quiche_test.h"
14 #include "quiche/common/quiche_callbacks.h"
15 
16 namespace http2 {
17 namespace test {
18 namespace {
19 const char kData[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
20 const bool kReturnNonZeroOnFirst = true;
21 const bool kMayReturnZeroOnFirst = false;
22 
23 // Confirm the behavior of various parts of RandomDecoderTest.
24 class RandomDecoderTestTest : public RandomDecoderTest {
25  public:
RandomDecoderTestTest()26   RandomDecoderTestTest() : data_db_(kData) {
27     QUICHE_CHECK_EQ(sizeof kData, 8u);
28   }
29 
30  protected:
31   typedef quiche::MultiUseCallback<DecodeStatus(DecodeBuffer* db)> DecodingFn;
32 
StartDecoding(DecodeBuffer * db)33   DecodeStatus StartDecoding(DecodeBuffer* db) override {
34     ++start_decoding_calls_;
35     if (start_decoding_fn_) {
36       return start_decoding_fn_(db);
37     }
38     return DecodeStatus::kDecodeError;
39   }
40 
ResumeDecoding(DecodeBuffer * db)41   DecodeStatus ResumeDecoding(DecodeBuffer* db) override {
42     ++resume_decoding_calls_;
43     if (resume_decoding_fn_) {
44       return resume_decoding_fn_(db);
45     }
46     return DecodeStatus::kDecodeError;
47   }
48 
StopDecodeOnDone()49   bool StopDecodeOnDone() override {
50     ++stop_decode_on_done_calls_;
51     if (override_stop_decode_on_done_) {
52       return sub_stop_decode_on_done_;
53     }
54     return RandomDecoderTest::StopDecodeOnDone();
55   }
56 
57   size_t start_decoding_calls_ = 0;
58   size_t resume_decoding_calls_ = 0;
59   size_t stop_decode_on_done_calls_ = 0;
60 
61   DecodingFn start_decoding_fn_;
62   DecodingFn resume_decoding_fn_;
63 
64   DecodeBuffer data_db_;
65 
66   bool sub_stop_decode_on_done_ = true;
67   bool override_stop_decode_on_done_ = true;
68 };
69 
70 // Decode a single byte on the StartDecoding call, then stop.
TEST_F(RandomDecoderTestTest,StopOnStartPartiallyDone)71 TEST_F(RandomDecoderTestTest, StopOnStartPartiallyDone) {
72   start_decoding_fn_ = [this](DecodeBuffer* db) {
73     EXPECT_EQ(1u, start_decoding_calls_);
74     // Make sure the correct buffer is being used.
75     EXPECT_EQ(kData, db->cursor());
76     EXPECT_EQ(sizeof kData, db->Remaining());
77     db->DecodeUInt8();
78     return DecodeStatus::kDecodeDone;
79   };
80 
81   EXPECT_EQ(DecodeStatus::kDecodeDone,
82             DecodeSegments(&data_db_, SelectRemaining()));
83   EXPECT_EQ(1u, data_db_.Offset());
84   // StartDecoding should only be called once from each call to DecodeSegments.
85   EXPECT_EQ(1u, start_decoding_calls_);
86   EXPECT_EQ(0u, resume_decoding_calls_);
87   EXPECT_EQ(1u, stop_decode_on_done_calls_);
88 }
89 
90 // Stop decoding upon return from the first ResumeDecoding call.
TEST_F(RandomDecoderTestTest,StopOnResumePartiallyDone)91 TEST_F(RandomDecoderTestTest, StopOnResumePartiallyDone) {
92   start_decoding_fn_ = [this](DecodeBuffer* db) {
93     EXPECT_EQ(1u, start_decoding_calls_);
94     db->DecodeUInt8();
95     return DecodeStatus::kDecodeInProgress;
96   };
97   resume_decoding_fn_ = [this](DecodeBuffer* db) {
98     EXPECT_EQ(1u, resume_decoding_calls_);
99     // Make sure the correct buffer is being used.
100     EXPECT_EQ(data_db_.cursor(), db->cursor());
101     db->DecodeUInt16();
102     return DecodeStatus::kDecodeDone;
103   };
104 
105   // Check that the base class honors it's member variable stop_decode_on_done_.
106   override_stop_decode_on_done_ = false;
107   stop_decode_on_done_ = true;
108 
109   EXPECT_EQ(DecodeStatus::kDecodeDone,
110             DecodeSegments(&data_db_, SelectRemaining()));
111   EXPECT_EQ(3u, data_db_.Offset());
112   EXPECT_EQ(1u, start_decoding_calls_);
113   EXPECT_EQ(1u, resume_decoding_calls_);
114   EXPECT_EQ(1u, stop_decode_on_done_calls_);
115 }
116 
117 // Decode a random sized chunks, always reporting back kDecodeInProgress.
TEST_F(RandomDecoderTestTest,InProgressWhenEmpty)118 TEST_F(RandomDecoderTestTest, InProgressWhenEmpty) {
119   start_decoding_fn_ = [this](DecodeBuffer* db) {
120     EXPECT_EQ(1u, start_decoding_calls_);
121     // Consume up to 2 bytes.
122     if (db->HasData()) {
123       db->DecodeUInt8();
124       if (db->HasData()) {
125         db->DecodeUInt8();
126       }
127     }
128     return DecodeStatus::kDecodeInProgress;
129   };
130   resume_decoding_fn_ = [](DecodeBuffer* db) {
131     // Consume all available bytes.
132     if (db->HasData()) {
133       db->AdvanceCursor(db->Remaining());
134     }
135     return DecodeStatus::kDecodeInProgress;
136   };
137 
138   EXPECT_EQ(DecodeStatus::kDecodeInProgress,
139             DecodeSegments(&data_db_, SelectRandom(kMayReturnZeroOnFirst)));
140   EXPECT_TRUE(data_db_.Empty());
141   EXPECT_EQ(1u, start_decoding_calls_);
142   EXPECT_LE(1u, resume_decoding_calls_);
143   EXPECT_EQ(0u, stop_decode_on_done_calls_);
144 }
145 
TEST_F(RandomDecoderTestTest,DoneExactlyAtEnd)146 TEST_F(RandomDecoderTestTest, DoneExactlyAtEnd) {
147   start_decoding_fn_ = [this](DecodeBuffer* db) {
148     EXPECT_EQ(1u, start_decoding_calls_);
149     EXPECT_EQ(1u, db->Remaining());
150     EXPECT_EQ(1u, db->FullSize());
151     db->DecodeUInt8();
152     return DecodeStatus::kDecodeInProgress;
153   };
154   resume_decoding_fn_ = [this](DecodeBuffer* db) {
155     EXPECT_EQ(1u, db->Remaining());
156     EXPECT_EQ(1u, db->FullSize());
157     db->DecodeUInt8();
158     if (data_db_.Remaining() == 1) {
159       return DecodeStatus::kDecodeDone;
160     }
161     return DecodeStatus::kDecodeInProgress;
162   };
163   override_stop_decode_on_done_ = true;
164   sub_stop_decode_on_done_ = true;
165 
166   EXPECT_EQ(DecodeStatus::kDecodeDone, DecodeSegments(&data_db_, SelectOne()));
167   EXPECT_EQ(0u, data_db_.Remaining());
168   EXPECT_EQ(1u, start_decoding_calls_);
169   EXPECT_EQ((sizeof kData) - 1, resume_decoding_calls_);
170   // Didn't need to call StopDecodeOnDone because we didn't finish early.
171   EXPECT_EQ(0u, stop_decode_on_done_calls_);
172 }
173 
TEST_F(RandomDecoderTestTest,DecodeSeveralWaysToEnd)174 TEST_F(RandomDecoderTestTest, DecodeSeveralWaysToEnd) {
175   // Each call to StartDecoding or ResumeDecoding will consume all that is
176   // available. When all the data has been consumed, returns kDecodeDone.
177   size_t decoded_since_start = 0;
178   auto shared_fn = [&decoded_since_start, this](DecodeBuffer* db) {
179     decoded_since_start += db->Remaining();
180     db->AdvanceCursor(db->Remaining());
181     EXPECT_EQ(0u, db->Remaining());
182     if (decoded_since_start == data_db_.FullSize()) {
183       return DecodeStatus::kDecodeDone;
184     }
185     return DecodeStatus::kDecodeInProgress;
186   };
187 
188   start_decoding_fn_ = [&decoded_since_start, shared_fn](DecodeBuffer* db) {
189     decoded_since_start = 0;
190     return shared_fn(db);
191   };
192   resume_decoding_fn_ = shared_fn;
193 
194   Validator validator = ValidateDoneAndEmpty();
195 
196   EXPECT_TRUE(DecodeAndValidateSeveralWays(&data_db_, kMayReturnZeroOnFirst,
197                                            validator));
198 
199   // We should have reached the end.
200   EXPECT_EQ(0u, data_db_.Remaining());
201 
202   // We currently have 4 ways of decoding; update this if that changes.
203   EXPECT_EQ(4u, start_decoding_calls_);
204 
205   // Didn't need to call StopDecodeOnDone because we didn't finish early.
206   EXPECT_EQ(0u, stop_decode_on_done_calls_);
207 }
208 
TEST_F(RandomDecoderTestTest,DecodeTwoWaysAndStopEarly)209 TEST_F(RandomDecoderTestTest, DecodeTwoWaysAndStopEarly) {
210   // On the second decode, return kDecodeDone before finishing.
211   size_t decoded_since_start = 0;
212   auto shared_fn = [&decoded_since_start, this](DecodeBuffer* db) {
213     uint32_t amount = db->Remaining();
214     if (start_decoding_calls_ == 2 && amount > 1) {
215       amount = 1;
216     }
217     decoded_since_start += amount;
218     db->AdvanceCursor(amount);
219     if (decoded_since_start == data_db_.FullSize()) {
220       return DecodeStatus::kDecodeDone;
221     }
222     if (decoded_since_start > 1 && start_decoding_calls_ == 2) {
223       return DecodeStatus::kDecodeDone;
224     }
225     return DecodeStatus::kDecodeInProgress;
226   };
227 
228   start_decoding_fn_ = [&decoded_since_start, shared_fn](DecodeBuffer* db) {
229     decoded_since_start = 0;
230     return shared_fn(db);
231   };
232   resume_decoding_fn_ = shared_fn;
233 
234   // We expect the first and second to succeed, but the second to end at a
235   // different offset, which DecodeAndValidateSeveralWays should complain about.
236   Validator validator = [this](const DecodeBuffer& /*input*/,
237                                DecodeStatus status) -> AssertionResult {
238     if (start_decoding_calls_ <= 2 && status != DecodeStatus::kDecodeDone) {
239       return ::testing::AssertionFailure()
240              << "Expected DecodeStatus::kDecodeDone, not " << status;
241     }
242     if (start_decoding_calls_ > 2) {
243       return ::testing::AssertionFailure()
244              << "How did we get to pass " << start_decoding_calls_;
245     }
246     return ::testing::AssertionSuccess();
247   };
248 
249   EXPECT_FALSE(DecodeAndValidateSeveralWays(&data_db_, kMayReturnZeroOnFirst,
250                                             validator));
251   EXPECT_EQ(2u, start_decoding_calls_);
252   EXPECT_EQ(1u, stop_decode_on_done_calls_);
253 }
254 
TEST_F(RandomDecoderTestTest,DecodeThreeWaysAndError)255 TEST_F(RandomDecoderTestTest, DecodeThreeWaysAndError) {
256   // Return kDecodeError from ResumeDecoding on the third decoding pass.
257   size_t decoded_since_start = 0;
258   auto shared_fn = [&decoded_since_start, this](DecodeBuffer* db) {
259     if (start_decoding_calls_ == 3 && decoded_since_start > 0) {
260       return DecodeStatus::kDecodeError;
261     }
262     uint32_t amount = db->Remaining();
263     if (start_decoding_calls_ == 3 && amount > 1) {
264       amount = 1;
265     }
266     decoded_since_start += amount;
267     db->AdvanceCursor(amount);
268     if (decoded_since_start == data_db_.FullSize()) {
269       return DecodeStatus::kDecodeDone;
270     }
271     return DecodeStatus::kDecodeInProgress;
272   };
273 
274   start_decoding_fn_ = [&decoded_since_start, shared_fn](DecodeBuffer* db) {
275     decoded_since_start = 0;
276     return shared_fn(db);
277   };
278   resume_decoding_fn_ = shared_fn;
279 
280   Validator validator = ValidateDoneAndEmpty();
281   EXPECT_FALSE(DecodeAndValidateSeveralWays(&data_db_, kReturnNonZeroOnFirst,
282                                             validator));
283   EXPECT_EQ(3u, start_decoding_calls_);
284   EXPECT_EQ(0u, stop_decode_on_done_calls_);
285 }
286 
287 // CorruptEnum should produce lots of different values. On the assumption that
288 // the enum gets at least a byte of storage, we should be able to produce
289 // 256 distinct values.
TEST(CorruptEnumTest,ManyValues)290 TEST(CorruptEnumTest, ManyValues) {
291   std::set<uint64_t> values;
292   DecodeStatus status;
293   QUICHE_LOG(INFO) << "sizeof status = " << sizeof status;
294   Http2Random rng;
295   for (int ndx = 0; ndx < 256; ++ndx) {
296     CorruptEnum(&status, &rng);
297     values.insert(static_cast<uint64_t>(status));
298   }
299 }
300 
301 // In practice the underlying type is an int, and currently that is 4 bytes.
302 typedef typename std::underlying_type<DecodeStatus>::type DecodeStatusUT;
303 
304 struct CorruptEnumTestStruct {
305   DecodeStatusUT filler1;
306   DecodeStatus status;
307   DecodeStatusUT filler2;
308 };
309 
310 // CorruptEnum should only overwrite the enum, not any adjacent storage.
TEST(CorruptEnumTest,CorruptsOnlyEnum)311 TEST(CorruptEnumTest, CorruptsOnlyEnum) {
312   Http2Random rng;
313   for (const DecodeStatusUT filler : {DecodeStatusUT(), ~DecodeStatusUT()}) {
314     QUICHE_LOG(INFO) << "filler=0x" << std::hex << filler;
315     CorruptEnumTestStruct s;
316     s.filler1 = filler;
317     s.filler2 = filler;
318     for (int ndx = 0; ndx < 256; ++ndx) {
319       CorruptEnum(&s.status, &rng);
320       EXPECT_EQ(s.filler1, filler);
321       EXPECT_EQ(s.filler2, filler);
322     }
323   }
324 }
325 
326 }  // namespace
327 }  // namespace test
328 }  // namespace http2
329