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