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