1 // Copyright 2021 The Chromium Authors
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/spdy/alps_decoder.h"
6
7 #include "base/test/metrics/histogram_tester.h"
8 #include "base/test/scoped_feature_list.h"
9 #include "net/base/features.h"
10 #include "net/base/hex_utils.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 using ::spdy::AcceptChOriginValuePair;
15 using ::testing::ElementsAre;
16 using ::testing::IsEmpty;
17 using ::testing::Pair;
18
19 namespace net {
20 namespace {
21
TEST(AlpsDecoderTest,EmptyInput)22 TEST(AlpsDecoderTest, EmptyInput) {
23 AlpsDecoder decoder;
24 EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
25 EXPECT_THAT(decoder.GetSettings(), IsEmpty());
26 EXPECT_EQ(0, decoder.settings_frame_count());
27
28 AlpsDecoder::Error error = decoder.Decode({});
29 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
30
31 EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
32 EXPECT_THAT(decoder.GetSettings(), IsEmpty());
33 EXPECT_EQ(0, decoder.settings_frame_count());
34 }
35
TEST(AlpsDecoderTest,EmptyAcceptChFrame)36 TEST(AlpsDecoderTest, EmptyAcceptChFrame) {
37 AlpsDecoder decoder;
38 AlpsDecoder::Error error =
39 decoder.Decode(HexDecode("000000" // length
40 "89" // type ACCEPT_CH
41 "00" // flags
42 "00000000")); // stream ID
43
44 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
45 EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
46 EXPECT_THAT(decoder.GetSettings(), IsEmpty());
47 EXPECT_EQ(0, decoder.settings_frame_count());
48 }
49
TEST(AlpsDecoderTest,EmptySettingsFrame)50 TEST(AlpsDecoderTest, EmptySettingsFrame) {
51 AlpsDecoder decoder;
52 AlpsDecoder::Error error =
53 decoder.Decode(HexDecode("000000" // length
54 "04" // type SETTINGS
55 "00" // flags
56 "00000000")); // stream ID
57
58 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
59 EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
60 EXPECT_THAT(decoder.GetSettings(), IsEmpty());
61 EXPECT_EQ(1, decoder.settings_frame_count());
62 }
63
TEST(AlpsDecoderTest,ParseSettingsAndAcceptChFrames)64 TEST(AlpsDecoderTest, ParseSettingsAndAcceptChFrames) {
65 AlpsDecoder decoder;
66 AlpsDecoder::Error error = decoder.Decode(HexDecode(
67 // ACCEPT_CH frame
68 "00003d" // length
69 "89" // type ACCEPT_CH
70 "00" // flags
71 "00000000" // stream ID
72 "0017" // origin length
73 "68747470733a2f2f7777772e" //
74 "6578616d706c652e636f6d" // origin "https://www.example.com"
75 "0003" // value length
76 "666f6f" // value "foo"
77 "0018" // origin length
78 "68747470733a2f2f6d61696c" //
79 "2e6578616d706c652e636f6d" // origin "https://mail.example.com"
80 "0003" // value length
81 "626172" // value "bar"
82 // SETTINGS frame
83 "00000c" // length
84 "04" // type
85 "00" // flags
86 "00000000" // stream ID
87 "0dab" // identifier
88 "01020304" // value
89 "1234" // identifier
90 "fedcba98")); // value
91
92 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
93 EXPECT_THAT(
94 decoder.GetAcceptCh(),
95 ElementsAre(AcceptChOriginValuePair{"https://www.example.com", "foo"},
96 AcceptChOriginValuePair{"https://mail.example.com", "bar"}));
97 EXPECT_THAT(decoder.GetSettings(),
98 ElementsAre(Pair(0x0dab, 0x01020304), Pair(0x1234, 0xfedcba98)));
99 EXPECT_EQ(1, decoder.settings_frame_count());
100 }
101
TEST(AlpsDecoderTest,ParseLargeAcceptChFrame)102 TEST(AlpsDecoderTest, ParseLargeAcceptChFrame) {
103 std::string frame = HexDecode(
104 // ACCEPT_CH frame
105 "0001ab" // length: 427 total bytes
106 "89" // type ACCEPT_CH
107 "00" // flags
108 "00000000" // stream ID
109 "0017" // origin length
110 "68747470733a2f2f7777772e" //
111 "6578616d706c652e636f6d" // origin "https://www.example.com"
112 "0190" // value length (400 in hex)
113 );
114
115 // The Accept-CH tokens payload is a string of 400 'x' characters.
116 const std::string accept_ch_tokens(400, 'x');
117 // Append the value bytes to the frame.
118 frame += accept_ch_tokens;
119
120 AlpsDecoder decoder;
121 AlpsDecoder::Error error = decoder.Decode(frame);
122
123 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
124 EXPECT_THAT(decoder.GetAcceptCh(),
125 ElementsAre(AcceptChOriginValuePair{"https://www.example.com",
126 accept_ch_tokens}));
127 }
128
TEST(AlpsDecoderTest,DisableAlpsParsing)129 TEST(AlpsDecoderTest, DisableAlpsParsing) {
130 base::test::ScopedFeatureList feature_list;
131 feature_list.InitAndDisableFeature(features::kAlpsParsing);
132 AlpsDecoder decoder;
133 AlpsDecoder::Error error = decoder.Decode(HexDecode(
134 // ACCEPT_CH frame
135 "00003d" // length
136 "89" // type ACCEPT_CH
137 "00" // flags
138 "00000000" // stream ID
139 "0017" // origin length
140 "68747470733a2f2f7777772e" //
141 "6578616d706c652e636f6d" // origin "https://www.example.com"
142 "0003" // value length
143 "666f6f" // value "foo"
144 "0018" // origin length
145 "68747470733a2f2f6d61696c" //
146 "2e6578616d706c652e636f6d" // origin "https://mail.example.com"
147 "0003" // value length
148 "626172" // value "bar"
149 ));
150
151 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
152 EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
153 }
154
TEST(AlpsDecoderTest,DisableAlpsClientHintParsing)155 TEST(AlpsDecoderTest, DisableAlpsClientHintParsing) {
156 base::test::ScopedFeatureList feature_list;
157 feature_list.InitAndDisableFeature(features::kAlpsClientHintParsing);
158 AlpsDecoder decoder;
159 AlpsDecoder::Error error = decoder.Decode(HexDecode(
160 // ACCEPT_CH frame
161 "00003d" // length
162 "89" // type ACCEPT_CH
163 "00" // flags
164 "00000000" // stream ID
165 "0017" // origin length
166 "68747470733a2f2f7777772e" //
167 "6578616d706c652e636f6d" // origin "https://www.example.com"
168 "0003" // value length
169 "666f6f" // value "foo"
170 "0018" // origin length
171 "68747470733a2f2f6d61696c" //
172 "2e6578616d706c652e636f6d" // origin "https://mail.example.com"
173 "0003" // value length
174 "626172" // value "bar"
175 ));
176
177 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
178 EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
179 }
180
TEST(AlpsDecoderTest,IncompleteFrame)181 TEST(AlpsDecoderTest, IncompleteFrame) {
182 AlpsDecoder decoder;
183 AlpsDecoder::Error error =
184 decoder.Decode(HexDecode("00000c" // length
185 "04" // type
186 "00" // flags
187 "00000000" // stream ID
188 "0dab" // identifier
189 "01")); // first byte of value
190
191 EXPECT_EQ(AlpsDecoder::Error::kNotOnFrameBoundary, error);
192 }
193
TEST(AlpsDecoderTest,TwoSettingsFrames)194 TEST(AlpsDecoderTest, TwoSettingsFrames) {
195 AlpsDecoder decoder;
196 AlpsDecoder::Error error =
197 decoder.Decode(HexDecode("000006" // length
198 "04" // type SETTINGS
199 "00" // flags
200 "00000000" // stream ID
201 "0dab" // identifier
202 "01020304" // value
203 "000006" // length
204 "04" // type SETTINGS
205 "00" // flags
206 "00000000" // stream ID
207 "1234" // identifier
208 "fedcba98")); // value
209
210 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
211 EXPECT_EQ(2, decoder.settings_frame_count());
212 EXPECT_THAT(decoder.GetSettings(),
213 ElementsAre(Pair(0x0dab, 0x01020304), Pair(0x1234, 0xfedcba98)));
214 }
215
TEST(AlpsDecoderTest,AcceptChOnInvalidStream)216 TEST(AlpsDecoderTest, AcceptChOnInvalidStream) {
217 AlpsDecoder decoder;
218 AlpsDecoder::Error error = decoder.Decode(
219 HexDecode("00001e" // length
220 "89" // type ACCEPT_CH
221 "00" // flags
222 "00000001" // invalid stream ID: should be zero
223 "0017" // origin length
224 "68747470733a2f2f7777772e" //
225 "6578616d706c652e636f6d" // origin "https://www.example.com"
226 "0003" // value length
227 "666f6f")); // value "foo"
228
229 EXPECT_EQ(AlpsDecoder::Error::kAcceptChInvalidStream, error);
230 }
231
232 // According to
233 // https://davidben.github.io/http-client-hint-reliability/ \
234 // draft-davidben-http-client-hint-reliability.html#name-http-2-accept_ch-frame
235 // "If a user agent receives an ACCEPT_CH frame whose stream [...] flags
236 // field is non-zero, it MUST respond with a connection error [...]."
TEST(AlpsDecoderTest,AcceptChWithInvalidFlags)237 TEST(AlpsDecoderTest, AcceptChWithInvalidFlags) {
238 AlpsDecoder decoder;
239 AlpsDecoder::Error error = decoder.Decode(
240 HexDecode("00001e" // length
241 "89" // type ACCEPT_CH
242 "02" // invalid flags: should be zero
243 "00000000" // stream ID
244 "0017" // origin length
245 "68747470733a2f2f7777772e" //
246 "6578616d706c652e636f6d" // origin "https://www.example.com"
247 "0003" // value length
248 "666f6f")); // value "foo"
249
250 EXPECT_EQ(AlpsDecoder::Error::kAcceptChWithFlags, error);
251 }
252
TEST(AlpsDecoderTest,SettingsOnInvalidStream)253 TEST(AlpsDecoderTest, SettingsOnInvalidStream) {
254 AlpsDecoder decoder;
255 AlpsDecoder::Error error =
256 decoder.Decode(HexDecode("000006" // length
257 "04" // type SETTINGS
258 "00" // flags
259 "00000001" // invalid stream ID: should be zero
260 "1234" // identifier
261 "fedcba98")); // value
262
263 EXPECT_EQ(AlpsDecoder::Error::kFramingError, error);
264 }
265
TEST(AlpsDecoderTest,SettingsAck)266 TEST(AlpsDecoderTest, SettingsAck) {
267 AlpsDecoder decoder;
268 AlpsDecoder::Error error =
269 decoder.Decode(HexDecode("000000" // length
270 "04" // type SETTINGS
271 "01" // ACK flag
272 "00000000")); // stream ID
273
274 EXPECT_EQ(AlpsDecoder::Error::kSettingsWithAck, error);
275 }
276
277 // According to https://httpwg.org/specs/rfc7540.html#FrameHeader:
278 // "Flags that have no defined semantics for a particular frame type MUST be
279 // ignored [...]"
TEST(AlpsDecoderTest,SettingsWithInvalidFlags)280 TEST(AlpsDecoderTest, SettingsWithInvalidFlags) {
281 AlpsDecoder decoder;
282 AlpsDecoder::Error error =
283 decoder.Decode(HexDecode("000006" // length
284 "04" // type SETTINGS
285 "02" // invalid flag
286 "00000000" // stream ID
287 "1234" // identifier
288 "fedcba98")); // value
289
290 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
291 }
292
TEST(AlpsDecoderTest,ForbiddenFrame)293 TEST(AlpsDecoderTest, ForbiddenFrame) {
294 AlpsDecoder decoder;
295 AlpsDecoder::Error error =
296 decoder.Decode(HexDecode("000003" // length
297 "00" // frame type DATA
298 "01" // flags END_STREAM
299 "00000001" // stream ID
300 "666f6f")); // payload "foo"
301
302 EXPECT_EQ(AlpsDecoder::Error::kForbiddenFrame, error);
303 }
304
TEST(AlpsDecoderTest,UnknownFrame)305 TEST(AlpsDecoderTest, UnknownFrame) {
306 AlpsDecoder decoder;
307 AlpsDecoder::Error error =
308 decoder.Decode(HexDecode("000003" // length
309 "2a" // unknown frame type
310 "ff" // flags
311 "00000008" // stream ID
312 "666f6f")); // payload "foo"
313
314 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
315 EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
316 EXPECT_THAT(decoder.GetSettings(), IsEmpty());
317 EXPECT_EQ(0, decoder.settings_frame_count());
318 }
319
320 class AlpsDecoderTestWithFeature : public ::testing::TestWithParam<bool> {
321 public:
ShouldKillSessionOnAcceptChMalformed()322 bool ShouldKillSessionOnAcceptChMalformed() { return GetParam(); }
323
324 private:
SetUp()325 void SetUp() override {
326 feature_list_.InitWithFeatureState(
327 features::kShouldKillSessionOnAcceptChMalformed,
328 ShouldKillSessionOnAcceptChMalformed());
329 }
330
331 base::test::ScopedFeatureList feature_list_;
332 };
333
334 INSTANTIATE_TEST_SUITE_P(All, AlpsDecoderTestWithFeature, testing::Bool());
335
TEST_P(AlpsDecoderTestWithFeature,MalformedAcceptChFrame)336 TEST_P(AlpsDecoderTestWithFeature, MalformedAcceptChFrame) {
337 // Correct, complete payload.
338 std::string payload = HexDecode(
339 "0017" // origin length
340 "68747470733a2f2f7777772e"
341 "6578616d706c652e636f6d" // origin "https://www.example.com"
342 "0003" // value length
343 "666f6f"); // value "foo"
344
345 for (uint8_t payload_length = 1; payload_length < payload.length();
346 payload_length++) {
347 base::HistogramTester histogram_tester;
348 // First two bytes of length.
349 std::string frame = HexDecode("0000");
350 // Last byte of length.
351 frame.push_back(static_cast<char>(payload_length));
352
353 frame.append(
354 HexDecode("89" // type ACCEPT_CH
355 "00" // flags
356 "00000000")); // stream ID
357 // Incomplete, malformed payload.
358 frame.append(payload.data(), payload_length);
359
360 AlpsDecoder decoder;
361 AlpsDecoder::Error error = decoder.Decode(frame);
362 if (ShouldKillSessionOnAcceptChMalformed()) {
363 EXPECT_EQ(AlpsDecoder::Error::kAcceptChMalformed, error);
364 histogram_tester.ExpectUniqueSample(
365 "Net.SpdySession.AlpsDecoderStatus.Bypassed",
366 static_cast<int>(AlpsDecoder::Error::kNoError), 1);
367 } else {
368 EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
369 histogram_tester.ExpectUniqueSample(
370 "Net.SpdySession.AlpsDecoderStatus.Bypassed",
371 static_cast<int>(AlpsDecoder::Error::kAcceptChMalformed), 1);
372 }
373 }
374 }
375
376 } // namespace
377 } // namespace net
378