1 // Copyright 2012 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/spdy/buffered_spdy_framer.h"
11
12 #include <algorithm>
13 #include <string_view>
14 #include <utility>
15
16 #include "base/logging.h"
17 #include "net/log/net_log_with_source.h"
18 #include "net/spdy/spdy_test_util_common.h"
19 #include "net/third_party/quiche/src/quiche/common/http/http_header_block.h"
20 #include "testing/platform_test.h"
21
22 namespace net {
23
24 namespace {
25
26 class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
27 public:
TestBufferedSpdyVisitor()28 TestBufferedSpdyVisitor()
29 : buffered_spdy_framer_(kMaxHeaderListSizeForTest, NetLogWithSource()),
30 header_stream_id_(static_cast<spdy::SpdyStreamId>(-1)),
31 promised_stream_id_(static_cast<spdy::SpdyStreamId>(-1)) {}
32
OnError(http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error)33 void OnError(
34 http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error) override {
35 VLOG(1) << "spdy::SpdyFramer Error: " << spdy_framer_error;
36 error_count_++;
37 }
38
OnStreamError(spdy::SpdyStreamId stream_id,const std::string & description)39 void OnStreamError(spdy::SpdyStreamId stream_id,
40 const std::string& description) override {
41 VLOG(1) << "spdy::SpdyFramer Error on stream: " << stream_id << " "
42 << description;
43 error_count_++;
44 }
45
OnHeaders(spdy::SpdyStreamId stream_id,bool has_priority,int weight,spdy::SpdyStreamId parent_stream_id,bool exclusive,bool fin,quiche::HttpHeaderBlock headers,base::TimeTicks recv_first_byte_time)46 void OnHeaders(spdy::SpdyStreamId stream_id,
47 bool has_priority,
48 int weight,
49 spdy::SpdyStreamId parent_stream_id,
50 bool exclusive,
51 bool fin,
52 quiche::HttpHeaderBlock headers,
53 base::TimeTicks recv_first_byte_time) override {
54 header_stream_id_ = stream_id;
55 headers_frame_count_++;
56 headers_ = std::move(headers);
57 }
58
OnDataFrameHeader(spdy::SpdyStreamId stream_id,size_t length,bool fin)59 void OnDataFrameHeader(spdy::SpdyStreamId stream_id,
60 size_t length,
61 bool fin) override {
62 ADD_FAILURE() << "Unexpected OnDataFrameHeader call.";
63 }
64
OnStreamFrameData(spdy::SpdyStreamId stream_id,const char * data,size_t len)65 void OnStreamFrameData(spdy::SpdyStreamId stream_id,
66 const char* data,
67 size_t len) override {
68 LOG(FATAL) << "Unexpected OnStreamFrameData call.";
69 }
70
OnStreamEnd(spdy::SpdyStreamId stream_id)71 void OnStreamEnd(spdy::SpdyStreamId stream_id) override {
72 LOG(FATAL) << "Unexpected OnStreamEnd call.";
73 }
74
OnStreamPadding(spdy::SpdyStreamId stream_id,size_t len)75 void OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) override {
76 LOG(FATAL) << "Unexpected OnStreamPadding call.";
77 }
78
OnSettings()79 void OnSettings() override {}
80
OnSettingsAck()81 void OnSettingsAck() override {}
82
OnSettingsEnd()83 void OnSettingsEnd() override {}
84
OnSetting(spdy::SpdySettingsId id,uint32_t value)85 void OnSetting(spdy::SpdySettingsId id, uint32_t value) override {
86 setting_count_++;
87 }
88
OnPing(spdy::SpdyPingId unique_id,bool is_ack)89 void OnPing(spdy::SpdyPingId unique_id, bool is_ack) override {}
90
OnRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code)91 void OnRstStream(spdy::SpdyStreamId stream_id,
92 spdy::SpdyErrorCode error_code) override {}
93
OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,spdy::SpdyErrorCode error_code,std::string_view debug_data)94 void OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
95 spdy::SpdyErrorCode error_code,
96 std::string_view debug_data) override {
97 goaway_count_++;
98 goaway_last_accepted_stream_id_ = last_accepted_stream_id;
99 goaway_error_code_ = error_code;
100 goaway_debug_data_.assign(debug_data.data(), debug_data.size());
101 }
102
OnDataFrameHeader(const spdy::SpdySerializedFrame * frame)103 void OnDataFrameHeader(const spdy::SpdySerializedFrame* frame) {
104 LOG(FATAL) << "Unexpected OnDataFrameHeader call.";
105 }
106
OnRstStream(const spdy::SpdySerializedFrame & frame)107 void OnRstStream(const spdy::SpdySerializedFrame& frame) {}
OnGoAway(const spdy::SpdySerializedFrame & frame)108 void OnGoAway(const spdy::SpdySerializedFrame& frame) {}
OnPing(const spdy::SpdySerializedFrame & frame)109 void OnPing(const spdy::SpdySerializedFrame& frame) {}
OnWindowUpdate(spdy::SpdyStreamId stream_id,int delta_window_size)110 void OnWindowUpdate(spdy::SpdyStreamId stream_id,
111 int delta_window_size) override {}
112
OnPushPromise(spdy::SpdyStreamId stream_id,spdy::SpdyStreamId promised_stream_id,quiche::HttpHeaderBlock headers)113 void OnPushPromise(spdy::SpdyStreamId stream_id,
114 spdy::SpdyStreamId promised_stream_id,
115 quiche::HttpHeaderBlock headers) override {
116 header_stream_id_ = stream_id;
117 push_promise_frame_count_++;
118 promised_stream_id_ = promised_stream_id;
119 headers_ = std::move(headers);
120 }
121
OnAltSvc(spdy::SpdyStreamId stream_id,std::string_view origin,const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector & altsvc_vector)122 void OnAltSvc(spdy::SpdyStreamId stream_id,
123 std::string_view origin,
124 const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector&
125 altsvc_vector) override {
126 altsvc_count_++;
127 altsvc_stream_id_ = stream_id;
128 altsvc_origin_.assign(origin.data(), origin.size());
129 altsvc_vector_ = altsvc_vector;
130 }
131
OnUnknownFrame(spdy::SpdyStreamId stream_id,uint8_t frame_type)132 bool OnUnknownFrame(spdy::SpdyStreamId stream_id,
133 uint8_t frame_type) override {
134 return true;
135 }
136
137 // Convenience function which runs a framer simulation with particular input.
SimulateInFramer(const spdy::SpdySerializedFrame & frame)138 void SimulateInFramer(const spdy::SpdySerializedFrame& frame) {
139 const char* input_ptr = frame.data();
140 size_t input_remaining = frame.size();
141 buffered_spdy_framer_.set_visitor(this);
142 while (input_remaining > 0 &&
143 buffered_spdy_framer_.spdy_framer_error() ==
144 http2::Http2DecoderAdapter::SPDY_NO_ERROR) {
145 // To make the tests more interesting, we feed random (amd small) chunks
146 // into the framer. This simulates getting strange-sized reads from
147 // the socket.
148 const size_t kMaxReadSize = 32;
149 size_t bytes_read =
150 (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
151 size_t bytes_processed =
152 buffered_spdy_framer_.ProcessInput(input_ptr, bytes_read);
153 input_remaining -= bytes_processed;
154 input_ptr += bytes_processed;
155 }
156 }
157
158 BufferedSpdyFramer buffered_spdy_framer_;
159
160 // Counters from the visitor callbacks.
161 int error_count_ = 0;
162 int setting_count_ = 0;
163 int headers_frame_count_ = 0;
164 int push_promise_frame_count_ = 0;
165 int goaway_count_ = 0;
166 int altsvc_count_ = 0;
167
168 // Header block streaming state:
169 spdy::SpdyStreamId header_stream_id_;
170 spdy::SpdyStreamId promised_stream_id_;
171
172 // Headers from OnHeaders and OnPushPromise for verification.
173 quiche::HttpHeaderBlock headers_;
174
175 // OnGoAway parameters.
176 spdy::SpdyStreamId goaway_last_accepted_stream_id_;
177 spdy::SpdyErrorCode goaway_error_code_;
178 std::string goaway_debug_data_;
179
180 // OnAltSvc parameters.
181 spdy::SpdyStreamId altsvc_stream_id_;
182 std::string altsvc_origin_;
183 spdy::SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_;
184 };
185
186 } // namespace
187
188 class BufferedSpdyFramerTest : public PlatformTest {};
189
TEST_F(BufferedSpdyFramerTest,OnSetting)190 TEST_F(BufferedSpdyFramerTest, OnSetting) {
191 spdy::SpdyFramer framer(spdy::SpdyFramer::ENABLE_COMPRESSION);
192 spdy::SpdySettingsIR settings_ir;
193 settings_ir.AddSetting(spdy::SETTINGS_INITIAL_WINDOW_SIZE, 2);
194 settings_ir.AddSetting(spdy::SETTINGS_MAX_CONCURRENT_STREAMS, 3);
195 spdy::SpdySerializedFrame control_frame(
196 framer.SerializeSettings(settings_ir));
197 TestBufferedSpdyVisitor visitor;
198
199 visitor.SimulateInFramer(control_frame);
200 EXPECT_EQ(0, visitor.error_count_);
201 EXPECT_EQ(2, visitor.setting_count_);
202 }
203
TEST_F(BufferedSpdyFramerTest,HeaderListTooLarge)204 TEST_F(BufferedSpdyFramerTest, HeaderListTooLarge) {
205 quiche::HttpHeaderBlock headers;
206 std::string long_header_value(256 * 1024, 'x');
207 headers["foo"] = long_header_value;
208 spdy::SpdyHeadersIR headers_ir(/*stream_id=*/1, std::move(headers));
209
210 NetLogWithSource net_log;
211 BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
212 spdy::SpdySerializedFrame control_frame = framer.SerializeFrame(headers_ir);
213
214 TestBufferedSpdyVisitor visitor;
215 visitor.SimulateInFramer(control_frame);
216
217 EXPECT_EQ(1, visitor.error_count_);
218 EXPECT_EQ(0, visitor.headers_frame_count_);
219 EXPECT_EQ(0, visitor.push_promise_frame_count_);
220 EXPECT_EQ(quiche::HttpHeaderBlock(), visitor.headers_);
221 }
222
TEST_F(BufferedSpdyFramerTest,ValidHeadersAfterInvalidHeaders)223 TEST_F(BufferedSpdyFramerTest, ValidHeadersAfterInvalidHeaders) {
224 quiche::HttpHeaderBlock headers;
225 headers["invalid"] = "\r\n\r\n";
226
227 quiche::HttpHeaderBlock headers2;
228 headers["alpha"] = "beta";
229
230 SpdyTestUtil spdy_test_util;
231 spdy::SpdySerializedFrame headers_frame(
232 spdy_test_util.ConstructSpdyReply(1, std::move(headers)));
233 spdy::SpdySerializedFrame headers_frame2(
234 spdy_test_util.ConstructSpdyReply(2, std::move(headers2)));
235
236 TestBufferedSpdyVisitor visitor;
237 visitor.SimulateInFramer(headers_frame);
238 EXPECT_EQ(1, visitor.error_count_);
239 EXPECT_EQ(0, visitor.headers_frame_count_);
240
241 visitor.SimulateInFramer(headers_frame2);
242 EXPECT_EQ(1, visitor.error_count_);
243 EXPECT_EQ(1, visitor.headers_frame_count_);
244 }
245
TEST_F(BufferedSpdyFramerTest,ReadHeadersHeaderBlock)246 TEST_F(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) {
247 quiche::HttpHeaderBlock headers;
248 headers["alpha"] = "beta";
249 headers["gamma"] = "delta";
250 spdy::SpdyHeadersIR headers_ir(/*stream_id=*/1, headers.Clone());
251
252 NetLogWithSource net_log;
253 BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
254 spdy::SpdySerializedFrame control_frame = framer.SerializeFrame(headers_ir);
255
256 TestBufferedSpdyVisitor visitor;
257 visitor.SimulateInFramer(control_frame);
258 EXPECT_EQ(0, visitor.error_count_);
259 EXPECT_EQ(1, visitor.headers_frame_count_);
260 EXPECT_EQ(0, visitor.push_promise_frame_count_);
261 EXPECT_EQ(headers, visitor.headers_);
262 }
263
TEST_F(BufferedSpdyFramerTest,ReadPushPromiseHeaderBlock)264 TEST_F(BufferedSpdyFramerTest, ReadPushPromiseHeaderBlock) {
265 quiche::HttpHeaderBlock headers;
266 headers["alpha"] = "beta";
267 headers["gamma"] = "delta";
268 NetLogWithSource net_log;
269 BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
270 spdy::SpdyPushPromiseIR push_promise_ir(
271 /*stream_id=*/1, /*promised_stream_id=*/2, headers.Clone());
272 spdy::SpdySerializedFrame control_frame =
273 framer.SerializeFrame(push_promise_ir);
274
275 TestBufferedSpdyVisitor visitor;
276 visitor.SimulateInFramer(control_frame);
277 EXPECT_EQ(0, visitor.error_count_);
278 EXPECT_EQ(0, visitor.headers_frame_count_);
279 EXPECT_EQ(1, visitor.push_promise_frame_count_);
280 EXPECT_EQ(headers, visitor.headers_);
281 EXPECT_EQ(1u, visitor.header_stream_id_);
282 EXPECT_EQ(2u, visitor.promised_stream_id_);
283 }
284
TEST_F(BufferedSpdyFramerTest,GoAwayDebugData)285 TEST_F(BufferedSpdyFramerTest, GoAwayDebugData) {
286 spdy::SpdyGoAwayIR go_ir(/*last_good_stream_id=*/2,
287 spdy::ERROR_CODE_FRAME_SIZE_ERROR, "foo");
288 NetLogWithSource net_log;
289 BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
290 spdy::SpdySerializedFrame goaway_frame = framer.SerializeFrame(go_ir);
291
292 TestBufferedSpdyVisitor visitor;
293 visitor.SimulateInFramer(goaway_frame);
294 EXPECT_EQ(0, visitor.error_count_);
295 EXPECT_EQ(1, visitor.goaway_count_);
296 EXPECT_EQ(2u, visitor.goaway_last_accepted_stream_id_);
297 EXPECT_EQ(spdy::ERROR_CODE_FRAME_SIZE_ERROR, visitor.goaway_error_code_);
298 EXPECT_EQ("foo", visitor.goaway_debug_data_);
299 }
300
301 // ALTSVC frame on stream 0 must have an origin.
TEST_F(BufferedSpdyFramerTest,OnAltSvcOnStreamZero)302 TEST_F(BufferedSpdyFramerTest, OnAltSvcOnStreamZero) {
303 const spdy::SpdyStreamId altsvc_stream_id(0);
304 spdy::SpdyAltSvcIR altsvc_ir(altsvc_stream_id);
305 spdy::SpdyAltSvcWireFormat::AlternativeService alternative_service(
306 "quic", "alternative.example.org", 443, 86400,
307 spdy::SpdyAltSvcWireFormat::VersionVector());
308 altsvc_ir.add_altsvc(alternative_service);
309 const char altsvc_origin[] = "https://www.example.org";
310 altsvc_ir.set_origin(altsvc_origin);
311 NetLogWithSource net_log;
312 BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
313 spdy::SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir));
314
315 TestBufferedSpdyVisitor visitor;
316 visitor.SimulateInFramer(altsvc_frame);
317 EXPECT_EQ(0, visitor.error_count_);
318 EXPECT_EQ(1, visitor.altsvc_count_);
319 EXPECT_EQ(altsvc_stream_id, visitor.altsvc_stream_id_);
320 EXPECT_EQ(altsvc_origin, visitor.altsvc_origin_);
321 ASSERT_EQ(1u, visitor.altsvc_vector_.size());
322 EXPECT_EQ(alternative_service, visitor.altsvc_vector_[0]);
323 }
324
325 // ALTSVC frame on a non-zero stream must not have an origin.
TEST_F(BufferedSpdyFramerTest,OnAltSvcOnNonzeroStream)326 TEST_F(BufferedSpdyFramerTest, OnAltSvcOnNonzeroStream) {
327 const spdy::SpdyStreamId altsvc_stream_id(1);
328 spdy::SpdyAltSvcIR altsvc_ir(altsvc_stream_id);
329 spdy::SpdyAltSvcWireFormat::AlternativeService alternative_service(
330 "quic", "alternative.example.org", 443, 86400,
331 spdy::SpdyAltSvcWireFormat::VersionVector());
332 altsvc_ir.add_altsvc(alternative_service);
333 NetLogWithSource net_log;
334 BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
335 spdy::SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir));
336
337 TestBufferedSpdyVisitor visitor;
338 visitor.SimulateInFramer(altsvc_frame);
339 EXPECT_EQ(0, visitor.error_count_);
340 EXPECT_EQ(1, visitor.altsvc_count_);
341 EXPECT_EQ(altsvc_stream_id, visitor.altsvc_stream_id_);
342 EXPECT_TRUE(visitor.altsvc_origin_.empty());
343 ASSERT_EQ(1u, visitor.altsvc_vector_.size());
344 EXPECT_EQ(alternative_service, visitor.altsvc_vector_[0]);
345 }
346
347 } // namespace net
348