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 "net/spdy/spdy_test_util_common.h" | |
8 #include "testing/platform_test.h" | |
9 | |
10 namespace net { | |
11 | |
12 namespace { | |
13 | |
14 class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface { | |
15 public: | |
16 explicit TestBufferedSpdyVisitor(SpdyMajorVersion spdy_version) | |
17 : buffered_spdy_framer_(spdy_version, true), | |
18 error_count_(0), | |
19 setting_count_(0), | |
20 syn_frame_count_(0), | |
21 syn_reply_frame_count_(0), | |
22 headers_frame_count_(0), | |
23 push_promise_frame_count_(0), | |
24 header_stream_id_(static_cast<SpdyStreamId>(-1)), | |
25 promised_stream_id_(static_cast<SpdyStreamId>(-1)) { | |
26 } | |
27 | |
28 void OnError(SpdyFramer::SpdyError error_code) override { | |
29 LOG(INFO) << "SpdyFramer Error: " << error_code; | |
30 error_count_++; | |
31 } | |
32 | |
33 void OnStreamError(SpdyStreamId stream_id, | |
34 const std::string& description) override { | |
35 LOG(INFO) << "SpdyFramer Error on stream: " << stream_id << " " | |
36 << description; | |
37 error_count_++; | |
38 } | |
39 | |
40 void OnSynStream(SpdyStreamId stream_id, | |
41 SpdyStreamId associated_stream_id, | |
42 SpdyPriority priority, | |
43 bool fin, | |
44 bool unidirectional, | |
45 const SpdyHeaderBlock& headers) override { | |
46 header_stream_id_ = stream_id; | |
47 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
48 syn_frame_count_++; | |
49 headers_ = headers; | |
50 } | |
51 | |
52 void OnSynReply(SpdyStreamId stream_id, | |
53 bool fin, | |
54 const SpdyHeaderBlock& headers) override { | |
55 header_stream_id_ = stream_id; | |
56 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
57 syn_reply_frame_count_++; | |
58 headers_ = headers; | |
59 } | |
60 | |
61 void OnHeaders(SpdyStreamId stream_id, | |
62 bool has_priority, | |
63 SpdyPriority priority, | |
64 bool fin, | |
65 const SpdyHeaderBlock& headers) override { | |
66 header_stream_id_ = stream_id; | |
67 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
68 headers_frame_count_++; | |
69 headers_ = headers; | |
70 } | |
71 | |
72 void OnDataFrameHeader(SpdyStreamId stream_id, | |
73 size_t length, | |
74 bool fin) override { | |
75 ADD_FAILURE() << "Unexpected OnDataFrameHeader call."; | |
76 } | |
77 | |
78 void OnStreamFrameData(SpdyStreamId stream_id, | |
79 const char* data, | |
80 size_t len, | |
81 bool fin) override { | |
82 LOG(FATAL) << "Unexpected OnStreamFrameData call."; | |
83 } | |
84 | |
85 void OnSettings(bool clear_persisted) override {} | |
86 | |
87 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override { | |
88 setting_count_++; | |
89 } | |
90 | |
91 void OnPing(SpdyPingId unique_id, bool is_ack) override {} | |
92 | |
93 void OnRstStream(SpdyStreamId stream_id, | |
94 SpdyRstStreamStatus status) override {} | |
95 | |
96 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
97 SpdyGoAwayStatus status) override {} | |
98 | |
99 bool OnCredentialFrameData(const char*, size_t) { | |
100 LOG(FATAL) << "Unexpected OnCredentialFrameData call."; | |
101 return false; | |
102 } | |
103 | |
104 void OnDataFrameHeader(const SpdyFrame* frame) { | |
105 LOG(FATAL) << "Unexpected OnDataFrameHeader call."; | |
106 } | |
107 | |
108 void OnRstStream(const SpdyFrame& frame) {} | |
109 void OnGoAway(const SpdyFrame& frame) {} | |
110 void OnPing(const SpdyFrame& frame) {} | |
111 void OnWindowUpdate(SpdyStreamId stream_id, | |
112 uint32 delta_window_size) override {} | |
113 | |
114 void OnPushPromise(SpdyStreamId stream_id, | |
115 SpdyStreamId promised_stream_id, | |
116 const SpdyHeaderBlock& headers) override { | |
117 header_stream_id_ = stream_id; | |
118 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
119 push_promise_frame_count_++; | |
120 promised_stream_id_ = promised_stream_id; | |
121 EXPECT_NE(promised_stream_id_, SpdyFramer::kInvalidStream); | |
122 headers_ = headers; | |
123 } | |
124 | |
125 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { | |
126 return true; | |
127 } | |
128 | |
129 void OnCredential(const SpdyFrame& frame) {} | |
130 | |
131 // Convenience function which runs a framer simulation with particular input. | |
132 void SimulateInFramer(const unsigned char* input, size_t size) { | |
133 buffered_spdy_framer_.set_visitor(this); | |
134 size_t input_remaining = size; | |
135 const char* input_ptr = reinterpret_cast<const char*>(input); | |
136 while (input_remaining > 0 && | |
137 buffered_spdy_framer_.error_code() == SpdyFramer::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_; | |
155 int setting_count_; | |
156 int syn_frame_count_; | |
157 int syn_reply_frame_count_; | |
158 int headers_frame_count_; | |
159 int push_promise_frame_count_; | |
160 | |
161 // Header block streaming state: | |
162 SpdyStreamId header_stream_id_; | |
163 SpdyStreamId promised_stream_id_; | |
164 | |
165 // Headers from OnSyn, OnSynReply, OnHeaders and OnPushPromise for | |
166 // verification. | |
167 SpdyHeaderBlock headers_; | |
168 }; | |
169 | |
170 } // namespace | |
171 | |
172 class BufferedSpdyFramerTest | |
173 : public PlatformTest, | |
174 public ::testing::WithParamInterface<NextProto> { | |
175 protected: | |
176 // Returns true if the two header blocks have equivalent content. | |
177 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected, | |
178 const SpdyHeaderBlock* actual) { | |
179 if (expected->size() != actual->size()) { | |
180 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got " | |
181 << actual->size() << "."; | |
182 return false; | |
183 } | |
184 for (SpdyHeaderBlock::const_iterator it = expected->begin(); | |
185 it != expected->end(); | |
186 ++it) { | |
187 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first); | |
188 if (it2 == actual->end()) { | |
189 LOG(ERROR) << "Expected header name '" << it->first << "'."; | |
190 return false; | |
191 } | |
192 if (it->second.compare(it2->second) != 0) { | |
193 LOG(ERROR) << "Expected header named '" << it->first | |
194 << "' to have a value of '" << it->second | |
195 << "'. The actual value received was '" << it2->second | |
196 << "'."; | |
197 return false; | |
198 } | |
199 } | |
200 return true; | |
201 } | |
202 | |
203 SpdyMajorVersion spdy_version() { | |
204 return NextProtoToSpdyMajorVersion(GetParam()); | |
205 } | |
206 }; | |
207 | |
208 INSTANTIATE_TEST_CASE_P( | |
209 NextProto, | |
210 BufferedSpdyFramerTest, | |
211 testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); | |
212 | |
213 TEST_P(BufferedSpdyFramerTest, OnSetting) { | |
214 SpdyFramer framer(spdy_version()); | |
215 SpdySettingsIR settings_ir; | |
216 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, false, false, 2); | |
217 settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, false, false, 3); | |
218 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir)); | |
219 TestBufferedSpdyVisitor visitor(spdy_version()); | |
220 | |
221 visitor.SimulateInFramer( | |
222 reinterpret_cast<unsigned char*>(control_frame->data()), | |
223 control_frame->size()); | |
224 EXPECT_EQ(0, visitor.error_count_); | |
225 EXPECT_EQ(2, visitor.setting_count_); | |
226 } | |
227 | |
228 TEST_P(BufferedSpdyFramerTest, ReadSynStreamHeaderBlock) { | |
229 if (spdy_version() > SPDY3) { | |
230 // SYN_STREAM not supported in SPDY>3. | |
231 return; | |
232 } | |
233 SpdyHeaderBlock headers; | |
234 headers["aa"] = "vv"; | |
235 headers["bb"] = "ww"; | |
236 BufferedSpdyFramer framer(spdy_version(), true); | |
237 scoped_ptr<SpdyFrame> control_frame( | |
238 framer.CreateSynStream(1, // stream_id | |
239 0, // associated_stream_id | |
240 1, // priority | |
241 CONTROL_FLAG_NONE, | |
242 &headers)); | |
243 EXPECT_TRUE(control_frame.get() != NULL); | |
244 | |
245 TestBufferedSpdyVisitor visitor(spdy_version()); | |
246 visitor.SimulateInFramer( | |
247 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
248 control_frame.get()->size()); | |
249 EXPECT_EQ(0, visitor.error_count_); | |
250 EXPECT_EQ(1, visitor.syn_frame_count_); | |
251 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
252 EXPECT_EQ(0, visitor.headers_frame_count_); | |
253 EXPECT_EQ(0, visitor.push_promise_frame_count_); | |
254 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
255 } | |
256 | |
257 TEST_P(BufferedSpdyFramerTest, ReadSynReplyHeaderBlock) { | |
258 if (spdy_version() > SPDY3) { | |
259 // SYN_REPLY not supported in SPDY>3. | |
260 return; | |
261 } | |
262 SpdyHeaderBlock headers; | |
263 headers["alpha"] = "beta"; | |
264 headers["gamma"] = "delta"; | |
265 BufferedSpdyFramer framer(spdy_version(), true); | |
266 scoped_ptr<SpdyFrame> control_frame( | |
267 framer.CreateSynReply(1, // stream_id | |
268 CONTROL_FLAG_NONE, | |
269 &headers)); | |
270 EXPECT_TRUE(control_frame.get() != NULL); | |
271 | |
272 TestBufferedSpdyVisitor visitor(spdy_version()); | |
273 visitor.SimulateInFramer( | |
274 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
275 control_frame.get()->size()); | |
276 EXPECT_EQ(0, visitor.error_count_); | |
277 EXPECT_EQ(0, visitor.syn_frame_count_); | |
278 EXPECT_EQ(0, visitor.push_promise_frame_count_); | |
279 if (spdy_version() < SPDY4) { | |
280 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
281 EXPECT_EQ(0, visitor.headers_frame_count_); | |
282 } else { | |
283 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
284 EXPECT_EQ(1, visitor.headers_frame_count_); | |
285 } | |
286 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
287 } | |
288 | |
289 TEST_P(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) { | |
290 SpdyHeaderBlock headers; | |
291 headers["alpha"] = "beta"; | |
292 headers["gamma"] = "delta"; | |
293 BufferedSpdyFramer framer(spdy_version(), true); | |
294 scoped_ptr<SpdyFrame> control_frame( | |
295 framer.CreateHeaders(1, // stream_id | |
296 CONTROL_FLAG_NONE, | |
297 0, // priority | |
298 &headers)); | |
299 EXPECT_TRUE(control_frame.get() != NULL); | |
300 | |
301 TestBufferedSpdyVisitor visitor(spdy_version()); | |
302 visitor.SimulateInFramer( | |
303 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
304 control_frame.get()->size()); | |
305 EXPECT_EQ(0, visitor.error_count_); | |
306 EXPECT_EQ(0, visitor.syn_frame_count_); | |
307 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
308 EXPECT_EQ(1, visitor.headers_frame_count_); | |
309 EXPECT_EQ(0, visitor.push_promise_frame_count_); | |
310 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
311 } | |
312 | |
313 TEST_P(BufferedSpdyFramerTest, ReadPushPromiseHeaderBlock) { | |
314 if (spdy_version() < SPDY4) | |
315 return; | |
316 SpdyHeaderBlock headers; | |
317 headers["alpha"] = "beta"; | |
318 headers["gamma"] = "delta"; | |
319 BufferedSpdyFramer framer(spdy_version(), true); | |
320 scoped_ptr<SpdyFrame> control_frame( | |
321 framer.CreatePushPromise(1, 2, &headers)); | |
322 EXPECT_TRUE(control_frame.get() != NULL); | |
323 | |
324 TestBufferedSpdyVisitor visitor(spdy_version()); | |
325 visitor.SimulateInFramer( | |
326 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
327 control_frame.get()->size()); | |
328 EXPECT_EQ(0, visitor.error_count_); | |
329 EXPECT_EQ(0, visitor.syn_frame_count_); | |
330 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
331 EXPECT_EQ(0, visitor.headers_frame_count_); | |
332 EXPECT_EQ(1, visitor.push_promise_frame_count_); | |
333 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
334 EXPECT_EQ(1u, visitor.header_stream_id_); | |
335 EXPECT_EQ(2u, visitor.promised_stream_id_); | |
336 } | |
337 | |
338 } // namespace net | |
OLD | NEW |