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/decoder/payload_decoders/headers_payload_decoder.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <string> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/logging.h" | |
13 #include "net/http2/decoder/frame_parts.h" | |
14 #include "net/http2/decoder/frame_parts_collector.h" | |
15 #include "net/http2/decoder/http2_frame_decoder_listener.h" | |
16 #include "net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h" | |
17 #include "net/http2/http2_constants.h" | |
18 #include "net/http2/http2_structures_test_util.h" | |
19 #include "net/http2/tools/http2_frame_builder.h" | |
20 #include "net/http2/tools/http2_random.h" | |
21 #include "net/http2/tools/random_decoder_test.h" | |
22 #include "testing/gtest/include/gtest/gtest.h" | |
23 | |
24 using std::string; | |
25 | |
26 namespace net { | |
27 namespace test { | |
28 | |
29 class HeadersPayloadDecoderPeer { | |
30 public: | |
31 static constexpr Http2FrameType FrameType() { | |
32 return Http2FrameType::HEADERS; | |
33 } | |
34 | |
35 // Returns the mask of flags that affect the decoding of the payload (i.e. | |
36 // flags that that indicate the presence of certain fields or padding). | |
37 static constexpr uint8_t FlagsAffectingPayloadDecoding() { | |
38 return Http2FrameFlag::FLAG_PADDED | Http2FrameFlag::FLAG_PRIORITY; | |
39 } | |
40 | |
41 static void Randomize(HeadersPayloadDecoder* p, RandomBase* rng) { | |
42 CorruptEnum(&p->payload_state_, rng); | |
43 test::Randomize(&p->priority_fields_, rng); | |
44 VLOG(1) << "HeadersPayloadDecoderPeer::Randomize priority_fields_: " | |
45 << p->priority_fields_; | |
46 } | |
47 }; | |
48 | |
49 namespace { | |
50 | |
51 // Listener handles all On* methods that are expected to be called. If any other | |
52 // On* methods of Http2FrameDecoderListener is called then the test fails; this | |
53 // is achieved by way of FailingHttp2FrameDecoderListener, the base class of | |
54 // FramePartsCollector. | |
55 // These On* methods make use of StartFrame, EndFrame, etc. of the base class | |
56 // to create and access to FrameParts instance(s) that will record the details. | |
57 // After decoding, the test validation code can access the FramePart instance(s) | |
58 // via the public methods of FramePartsCollector. | |
59 struct Listener : public FramePartsCollector { | |
60 void OnHeadersStart(const Http2FrameHeader& header) override { | |
61 VLOG(1) << "OnHeadersStart: " << header; | |
62 StartFrame(header)->OnHeadersStart(header); | |
63 } | |
64 | |
65 void OnHeadersPriority(const Http2PriorityFields& priority) override { | |
66 VLOG(1) << "OnHeadersPriority: " << priority; | |
67 CurrentFrame()->OnHeadersPriority(priority); | |
68 } | |
69 | |
70 void OnHpackFragment(const char* data, size_t len) override { | |
71 VLOG(1) << "OnHpackFragment: len=" << len; | |
72 CurrentFrame()->OnHpackFragment(data, len); | |
73 } | |
74 | |
75 void OnHeadersEnd() override { | |
76 VLOG(1) << "OnHeadersEnd"; | |
77 EndFrame()->OnHeadersEnd(); | |
78 } | |
79 | |
80 void OnPadLength(size_t pad_length) override { | |
81 VLOG(1) << "OnPadLength: " << pad_length; | |
82 CurrentFrame()->OnPadLength(pad_length); | |
83 } | |
84 | |
85 void OnPadding(const char* padding, size_t skipped_length) override { | |
86 VLOG(1) << "OnPadding: " << skipped_length; | |
87 CurrentFrame()->OnPadding(padding, skipped_length); | |
88 } | |
89 | |
90 void OnPaddingTooLong(const Http2FrameHeader& header, | |
91 size_t missing_length) override { | |
92 VLOG(1) << "OnPaddingTooLong: " << header | |
93 << "; missing_length: " << missing_length; | |
94 FrameError(header)->OnPaddingTooLong(header, missing_length); | |
95 } | |
96 | |
97 void OnFrameSizeError(const Http2FrameHeader& header) override { | |
98 VLOG(1) << "OnFrameSizeError: " << header; | |
99 FrameError(header)->OnFrameSizeError(header); | |
100 } | |
101 }; | |
102 | |
103 class HeadersPayloadDecoderTest | |
104 : public AbstractPaddablePayloadDecoderTest<HeadersPayloadDecoder, | |
105 HeadersPayloadDecoderPeer, | |
106 Listener> { | |
107 public: | |
108 static bool ApproveSizeForTruncated(size_t size) { | |
109 return size != Http2PriorityFields::EncodedSize(); | |
110 } | |
111 }; | |
112 | |
113 INSTANTIATE_TEST_CASE_P(VariousPadLengths, | |
114 HeadersPayloadDecoderTest, | |
115 ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256)); | |
116 | |
117 // Decode various sizes of (fake) HPACK payload, both with and without the | |
118 // PRIORITY flag set. | |
119 TEST_P(HeadersPayloadDecoderTest, VariousHpackPayloadSizes) { | |
120 for (size_t hpack_size : {0, 1, 2, 3, 255, 256, 1024}) { | |
121 LOG(INFO) << "########### hpack_size = " << hpack_size << " ###########"; | |
122 Http2PriorityFields priority(RandStreamId(), 1 + Random().Rand8(), | |
123 Random().OneIn(2)); | |
124 | |
125 for (bool has_priority : {false, true}) { | |
126 Reset(); | |
127 ASSERT_EQ(IsPadded() ? 1u : 0u, frame_builder_.size()); | |
128 uint8_t flags = RandFlags(); | |
129 if (has_priority) { | |
130 flags |= Http2FrameFlag::FLAG_PRIORITY; | |
131 frame_builder_.Append(priority); | |
132 } | |
133 | |
134 string hpack_payload = Random().RandString(hpack_size); | |
135 frame_builder_.Append(hpack_payload); | |
136 | |
137 MaybeAppendTrailingPadding(); | |
138 Http2FrameHeader frame_header(frame_builder_.size(), | |
139 Http2FrameType::HEADERS, flags, | |
140 RandStreamId()); | |
141 set_frame_header(frame_header); | |
142 ScrubFlagsOfHeader(&frame_header); | |
143 FrameParts expected(frame_header, hpack_payload, total_pad_length_); | |
144 if (has_priority) { | |
145 expected.opt_priority = priority; | |
146 } | |
147 EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(frame_builder_.buffer(), | |
148 expected)); | |
149 } | |
150 } | |
151 } | |
152 | |
153 // Confirm we get an error if the PRIORITY flag is set but the payload is | |
154 // not long enough, regardless of the amount of (valid) padding. | |
155 TEST_P(HeadersPayloadDecoderTest, Truncated) { | |
156 Http2FrameBuilder fb; | |
157 fb.Append(Http2PriorityFields(RandStreamId(), 1 + Random().Rand8(), | |
158 Random().OneIn(2))); | |
159 EXPECT_TRUE(VerifyDetectsMultipleFrameSizeErrors( | |
160 Http2FrameFlag::FLAG_PRIORITY, fb.buffer(), | |
161 base::Bind(&HeadersPayloadDecoderTest::ApproveSizeForTruncated), | |
162 total_pad_length_)); | |
163 } | |
164 | |
165 // Confirm we get an error if the PADDED flag is set but the payload is not | |
166 // long enough to hold even the Pad Length amount of padding. | |
167 TEST_P(HeadersPayloadDecoderTest, PaddingTooLong) { | |
168 EXPECT_TRUE(VerifyDetectsPaddingTooLong()); | |
169 } | |
170 | |
171 } // namespace | |
172 } // namespace test | |
173 } // namespace net | |
OLD | NEW |