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