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 <algorithm> | |
6 #include <iostream> | |
7 #include <limits> | |
8 | |
9 #include "base/compiler_specific.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "net/spdy/hpack_output_stream.h" | |
12 #include "net/spdy/mock_spdy_framer_visitor.h" | |
13 #include "net/spdy/spdy_frame_builder.h" | |
14 #include "net/spdy/spdy_frame_reader.h" | |
15 #include "net/spdy/spdy_framer.h" | |
16 #include "net/spdy/spdy_protocol.h" | |
17 #include "net/spdy/spdy_test_utils.h" | |
18 #include "testing/gmock/include/gmock/gmock.h" | |
19 #include "testing/platform_test.h" | |
20 | |
21 using std::string; | |
22 using testing::_; | |
23 | |
24 namespace net { | |
25 | |
26 namespace test { | |
27 | |
28 static const size_t kMaxDecompressedSize = 1024; | |
29 | |
30 class MockDebugVisitor : public SpdyFramerDebugVisitorInterface { | |
31 public: | |
32 MOCK_METHOD4(OnSendCompressedFrame, void(SpdyStreamId stream_id, | |
33 SpdyFrameType type, | |
34 size_t payload_len, | |
35 size_t frame_len)); | |
36 | |
37 MOCK_METHOD3(OnReceiveCompressedFrame, void(SpdyStreamId stream_id, | |
38 SpdyFrameType type, | |
39 size_t frame_len)); | |
40 }; | |
41 | |
42 class SpdyFramerTestUtil { | |
43 public: | |
44 // Decompress a single frame using the decompression context held by | |
45 // the SpdyFramer. The implemention is meant for use only in tests | |
46 // and will CHECK fail if the input is anything other than a single, | |
47 // well-formed compressed frame. | |
48 // | |
49 // Returns a new decompressed SpdyFrame. | |
50 template<class SpdyFrameType> static SpdyFrame* DecompressFrame( | |
51 SpdyFramer* framer, const SpdyFrameType& frame) { | |
52 DecompressionVisitor visitor(framer->protocol_version()); | |
53 framer->set_visitor(&visitor); | |
54 CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size())); | |
55 CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state()); | |
56 framer->set_visitor(NULL); | |
57 | |
58 char* buffer = visitor.ReleaseBuffer(); | |
59 CHECK(buffer != NULL); | |
60 SpdyFrame* decompressed_frame = new SpdyFrame(buffer, visitor.size(), true); | |
61 SetFrameLength(decompressed_frame, | |
62 visitor.size() - framer->GetControlFrameHeaderSize(), | |
63 framer->protocol_version()); | |
64 return decompressed_frame; | |
65 } | |
66 | |
67 class DecompressionVisitor : public SpdyFramerVisitorInterface { | |
68 public: | |
69 explicit DecompressionVisitor(SpdyMajorVersion version) | |
70 : version_(version), size_(0), finished_(false) {} | |
71 | |
72 void ResetBuffer() { | |
73 CHECK(buffer_.get() == NULL); | |
74 CHECK_EQ(0u, size_); | |
75 CHECK(!finished_); | |
76 buffer_.reset(new char[kMaxDecompressedSize]); | |
77 } | |
78 | |
79 void OnError(SpdyFramer* framer) override { LOG(FATAL); } | |
80 void OnDataFrameHeader(SpdyStreamId stream_id, | |
81 size_t length, | |
82 bool fin) override { | |
83 LOG(FATAL) << "Unexpected data frame header"; | |
84 } | |
85 void OnStreamFrameData(SpdyStreamId stream_id, | |
86 const char* data, | |
87 size_t len, | |
88 bool fin) override { | |
89 LOG(FATAL); | |
90 } | |
91 | |
92 bool OnControlFrameHeaderData(SpdyStreamId stream_id, | |
93 const char* header_data, | |
94 size_t len) override { | |
95 CHECK(buffer_.get() != NULL); | |
96 CHECK_GE(kMaxDecompressedSize, size_ + len); | |
97 CHECK(!finished_); | |
98 if (len != 0) { | |
99 memcpy(buffer_.get() + size_, header_data, len); | |
100 size_ += len; | |
101 } else { | |
102 // Done. | |
103 finished_ = true; | |
104 } | |
105 return true; | |
106 } | |
107 | |
108 void OnSynStream(SpdyStreamId stream_id, | |
109 SpdyStreamId associated_stream_id, | |
110 SpdyPriority priority, | |
111 bool fin, | |
112 bool unidirectional) override { | |
113 SpdyFramer framer(version_); | |
114 framer.set_enable_compression(false); | |
115 SpdySynStreamIR syn_stream(stream_id); | |
116 syn_stream.set_associated_to_stream_id(associated_stream_id); | |
117 syn_stream.set_priority(priority); | |
118 syn_stream.set_fin(fin); | |
119 syn_stream.set_unidirectional(unidirectional); | |
120 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); | |
121 ResetBuffer(); | |
122 memcpy(buffer_.get(), frame->data(), framer.GetSynStreamMinimumSize()); | |
123 size_ += framer.GetSynStreamMinimumSize(); | |
124 } | |
125 | |
126 void OnSynReply(SpdyStreamId stream_id, bool fin) override { | |
127 SpdyFramer framer(version_); | |
128 framer.set_enable_compression(false); | |
129 SpdyHeadersIR headers(stream_id); | |
130 headers.set_fin(fin); | |
131 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers)); | |
132 ResetBuffer(); | |
133 memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize()); | |
134 size_ += framer.GetSynStreamMinimumSize(); | |
135 } | |
136 | |
137 void OnRstStream(SpdyStreamId stream_id, | |
138 SpdyRstStreamStatus status) override { | |
139 LOG(FATAL); | |
140 } | |
141 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override { | |
142 LOG(FATAL); | |
143 } | |
144 void OnPing(SpdyPingId unique_id, bool is_ack) override { LOG(FATAL); } | |
145 void OnSettingsEnd() override { LOG(FATAL); } | |
146 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
147 SpdyGoAwayStatus status) override { | |
148 LOG(FATAL); | |
149 } | |
150 | |
151 void OnHeaders(SpdyStreamId stream_id, bool has_priority, | |
152 SpdyPriority priority, bool fin, bool end) override { | |
153 SpdyFramer framer(version_); | |
154 framer.set_enable_compression(false); | |
155 SpdyHeadersIR headers(stream_id); | |
156 headers.set_has_priority(has_priority); | |
157 if (headers.has_priority()) { | |
158 headers.set_priority(priority); | |
159 } | |
160 headers.set_fin(fin); | |
161 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers)); | |
162 ResetBuffer(); | |
163 memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize()); | |
164 size_ += framer.GetHeadersMinimumSize(); | |
165 } | |
166 | |
167 virtual void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) { | |
168 LOG(FATAL); | |
169 } | |
170 | |
171 void OnPushPromise(SpdyStreamId stream_id, | |
172 SpdyStreamId promised_stream_id, | |
173 bool end) override { | |
174 SpdyFramer framer(version_); | |
175 framer.set_enable_compression(false); | |
176 SpdyPushPromiseIR push_promise(stream_id, promised_stream_id); | |
177 scoped_ptr<SpdyFrame> frame(framer.SerializePushPromise(push_promise)); | |
178 ResetBuffer(); | |
179 memcpy(buffer_.get(), frame->data(), framer.GetPushPromiseMinimumSize()); | |
180 size_ += framer.GetPushPromiseMinimumSize(); | |
181 } | |
182 | |
183 void OnContinuation(SpdyStreamId stream_id, bool end) override { | |
184 LOG(FATAL); | |
185 } | |
186 | |
187 void OnPriority(SpdyStreamId stream_id, | |
188 SpdyStreamId parent_stream_id, | |
189 uint8 weight, | |
190 bool exclusive) override { | |
191 // Do nothing. | |
192 } | |
193 | |
194 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { | |
195 LOG(FATAL); | |
196 return false; | |
197 } | |
198 | |
199 char* ReleaseBuffer() { | |
200 CHECK(finished_); | |
201 return buffer_.release(); | |
202 } | |
203 | |
204 void OnWindowUpdate(SpdyStreamId stream_id, | |
205 uint32 delta_window_size) override { | |
206 LOG(FATAL); | |
207 } | |
208 | |
209 size_t size() const { | |
210 CHECK(finished_); | |
211 return size_; | |
212 } | |
213 | |
214 private: | |
215 SpdyMajorVersion version_; | |
216 scoped_ptr<char[]> buffer_; | |
217 size_t size_; | |
218 bool finished_; | |
219 | |
220 DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor); | |
221 }; | |
222 | |
223 private: | |
224 DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil); | |
225 }; | |
226 | |
227 class TestSpdyVisitor : public SpdyFramerVisitorInterface, | |
228 public SpdyFramerDebugVisitorInterface { | |
229 public: | |
230 // This is larger than our max frame size because header blocks that | |
231 // are too long can spill over into CONTINUATION frames. | |
232 static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024; | |
233 | |
234 explicit TestSpdyVisitor(SpdyMajorVersion version) | |
235 : framer_(version), | |
236 use_compression_(false), | |
237 error_count_(0), | |
238 syn_frame_count_(0), | |
239 syn_reply_frame_count_(0), | |
240 headers_frame_count_(0), | |
241 push_promise_frame_count_(0), | |
242 goaway_count_(0), | |
243 setting_count_(0), | |
244 settings_ack_sent_(0), | |
245 settings_ack_received_(0), | |
246 continuation_count_(0), | |
247 altsvc_count_(0), | |
248 priority_count_(0), | |
249 test_altsvc_ir_(0), | |
250 on_unknown_frame_result_(false), | |
251 last_window_update_stream_(0), | |
252 last_window_update_delta_(0), | |
253 last_push_promise_stream_(0), | |
254 last_push_promise_promised_stream_(0), | |
255 data_bytes_(0), | |
256 fin_frame_count_(0), | |
257 fin_opaque_data_(), | |
258 fin_flag_count_(0), | |
259 zero_length_data_frame_count_(0), | |
260 control_frame_header_data_count_(0), | |
261 zero_length_control_frame_header_data_count_(0), | |
262 data_frame_count_(0), | |
263 last_payload_len_(0), | |
264 last_frame_len_(0), | |
265 header_buffer_(new char[kDefaultHeaderBufferSize]), | |
266 header_buffer_length_(0), | |
267 header_buffer_size_(kDefaultHeaderBufferSize), | |
268 header_stream_id_(static_cast<SpdyStreamId>(-1)), | |
269 header_control_type_(DATA), | |
270 header_buffer_valid_(false) {} | |
271 | |
272 void OnError(SpdyFramer* f) override { | |
273 LOG(INFO) << "SpdyFramer Error: " | |
274 << SpdyFramer::ErrorCodeToString(f->error_code()); | |
275 ++error_count_; | |
276 } | |
277 | |
278 void OnDataFrameHeader(SpdyStreamId stream_id, | |
279 size_t length, | |
280 bool fin) override { | |
281 ++data_frame_count_; | |
282 header_stream_id_ = stream_id; | |
283 } | |
284 | |
285 void OnStreamFrameData(SpdyStreamId stream_id, | |
286 const char* data, | |
287 size_t len, | |
288 bool fin) override { | |
289 EXPECT_EQ(header_stream_id_, stream_id); | |
290 if (len == 0) | |
291 ++zero_length_data_frame_count_; | |
292 | |
293 data_bytes_ += len; | |
294 std::cerr << "OnStreamFrameData(" << stream_id << ", \""; | |
295 if (len > 0) { | |
296 for (size_t i = 0 ; i < len; ++i) { | |
297 std::cerr << std::hex << (0xFF & static_cast<unsigned int>(data[i])) | |
298 << std::dec; | |
299 } | |
300 } | |
301 std::cerr << "\", " << len << ")\n"; | |
302 } | |
303 | |
304 bool OnControlFrameHeaderData(SpdyStreamId stream_id, | |
305 const char* header_data, | |
306 size_t len) override { | |
307 ++control_frame_header_data_count_; | |
308 CHECK_EQ(header_stream_id_, stream_id); | |
309 if (len == 0) { | |
310 ++zero_length_control_frame_header_data_count_; | |
311 // Indicates end-of-header-block. | |
312 headers_.clear(); | |
313 CHECK(header_buffer_valid_); | |
314 size_t parsed_length = framer_.ParseHeaderBlockInBuffer( | |
315 header_buffer_.get(), header_buffer_length_, &headers_); | |
316 LOG_IF(DFATAL, header_buffer_length_ != parsed_length) | |
317 << "Check failed: header_buffer_length_ == parsed_length " | |
318 << "(" << header_buffer_length_ << " vs. " << parsed_length << ")"; | |
319 return true; | |
320 } | |
321 const size_t available = header_buffer_size_ - header_buffer_length_; | |
322 if (len > available) { | |
323 header_buffer_valid_ = false; | |
324 return false; | |
325 } | |
326 memcpy(header_buffer_.get() + header_buffer_length_, header_data, len); | |
327 header_buffer_length_ += len; | |
328 return true; | |
329 } | |
330 | |
331 void OnSynStream(SpdyStreamId stream_id, | |
332 SpdyStreamId associated_stream_id, | |
333 SpdyPriority priority, | |
334 bool fin, | |
335 bool unidirectional) override { | |
336 ++syn_frame_count_; | |
337 if (framer_.protocol_version() > SPDY3) { | |
338 InitHeaderStreaming(HEADERS, stream_id); | |
339 } else { | |
340 InitHeaderStreaming(SYN_STREAM, stream_id); | |
341 } | |
342 if (fin) { | |
343 ++fin_flag_count_; | |
344 } | |
345 } | |
346 | |
347 void OnSynReply(SpdyStreamId stream_id, bool fin) override { | |
348 ++syn_reply_frame_count_; | |
349 if (framer_.protocol_version() > SPDY3) { | |
350 InitHeaderStreaming(HEADERS, stream_id); | |
351 } else { | |
352 InitHeaderStreaming(SYN_REPLY, stream_id); | |
353 } | |
354 if (fin) { | |
355 ++fin_flag_count_; | |
356 } | |
357 } | |
358 | |
359 void OnRstStream(SpdyStreamId stream_id, | |
360 SpdyRstStreamStatus status) override { | |
361 ++fin_frame_count_; | |
362 } | |
363 | |
364 bool OnRstStreamFrameData(const char* rst_stream_data, size_t len) override { | |
365 if ((rst_stream_data != NULL) && (len > 0)) { | |
366 fin_opaque_data_ += string(rst_stream_data, len); | |
367 } | |
368 return true; | |
369 } | |
370 | |
371 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override { | |
372 ++setting_count_; | |
373 } | |
374 | |
375 void OnSettingsAck() override { | |
376 DCHECK_LT(SPDY3, framer_.protocol_version()); | |
377 ++settings_ack_received_; | |
378 } | |
379 | |
380 void OnSettingsEnd() override { | |
381 if (framer_.protocol_version() <= SPDY3) { return; } | |
382 ++settings_ack_sent_; | |
383 } | |
384 | |
385 void OnPing(SpdyPingId unique_id, bool is_ack) override { DLOG(FATAL); } | |
386 | |
387 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
388 SpdyGoAwayStatus status) override { | |
389 ++goaway_count_; | |
390 } | |
391 | |
392 void OnHeaders(SpdyStreamId stream_id, bool has_priority, | |
393 SpdyPriority priority, bool fin, bool end) override { | |
394 ++headers_frame_count_; | |
395 InitHeaderStreaming(HEADERS, stream_id); | |
396 if (fin) { | |
397 ++fin_flag_count_; | |
398 } | |
399 } | |
400 | |
401 void OnWindowUpdate(SpdyStreamId stream_id, | |
402 uint32 delta_window_size) override { | |
403 last_window_update_stream_ = stream_id; | |
404 last_window_update_delta_ = delta_window_size; | |
405 } | |
406 | |
407 void OnPushPromise(SpdyStreamId stream_id, | |
408 SpdyStreamId promised_stream_id, | |
409 bool end) override { | |
410 ++push_promise_frame_count_; | |
411 InitHeaderStreaming(PUSH_PROMISE, stream_id); | |
412 last_push_promise_stream_ = stream_id; | |
413 last_push_promise_promised_stream_ = promised_stream_id; | |
414 } | |
415 | |
416 void OnContinuation(SpdyStreamId stream_id, bool end) override { | |
417 ++continuation_count_; | |
418 } | |
419 | |
420 void OnAltSvc(SpdyStreamId stream_id, | |
421 uint32 max_age, | |
422 uint16 port, | |
423 StringPiece protocol_id, | |
424 StringPiece host, | |
425 StringPiece origin) override { | |
426 test_altsvc_ir_.set_stream_id(stream_id); | |
427 test_altsvc_ir_.set_max_age(max_age); | |
428 test_altsvc_ir_.set_port(port); | |
429 test_altsvc_ir_.set_protocol_id(protocol_id.as_string()); | |
430 test_altsvc_ir_.set_host(host.as_string()); | |
431 if (origin.length() > 0) { | |
432 test_altsvc_ir_.set_origin(origin.as_string()); | |
433 } | |
434 ++altsvc_count_; | |
435 } | |
436 | |
437 void OnPriority(SpdyStreamId stream_id, | |
438 SpdyStreamId parent_stream_id, | |
439 uint8 weight, | |
440 bool exclusive) override { | |
441 ++priority_count_; | |
442 } | |
443 | |
444 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { | |
445 DLOG(INFO) << "Unknown frame type " << frame_type; | |
446 return on_unknown_frame_result_; | |
447 } | |
448 | |
449 void OnSendCompressedFrame(SpdyStreamId stream_id, | |
450 SpdyFrameType type, | |
451 size_t payload_len, | |
452 size_t frame_len) override { | |
453 last_payload_len_ = payload_len; | |
454 last_frame_len_ = frame_len; | |
455 } | |
456 | |
457 void OnReceiveCompressedFrame(SpdyStreamId stream_id, | |
458 SpdyFrameType type, | |
459 size_t frame_len) override { | |
460 last_frame_len_ = frame_len; | |
461 } | |
462 | |
463 // Convenience function which runs a framer simulation with particular input. | |
464 void SimulateInFramer(const unsigned char* input, size_t size) { | |
465 framer_.set_enable_compression(use_compression_); | |
466 framer_.set_visitor(this); | |
467 size_t input_remaining = size; | |
468 const char* input_ptr = reinterpret_cast<const char*>(input); | |
469 while (input_remaining > 0 && | |
470 framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) { | |
471 // To make the tests more interesting, we feed random (amd small) chunks | |
472 // into the framer. This simulates getting strange-sized reads from | |
473 // the socket. | |
474 const size_t kMaxReadSize = 32; | |
475 size_t bytes_read = | |
476 (rand() % std::min(input_remaining, kMaxReadSize)) + 1; | |
477 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read); | |
478 input_remaining -= bytes_processed; | |
479 input_ptr += bytes_processed; | |
480 } | |
481 } | |
482 | |
483 void InitHeaderStreaming(SpdyFrameType header_control_type, | |
484 SpdyStreamId stream_id) { | |
485 if (!SpdyConstants::IsValidFrameType(framer_.protocol_version(), | |
486 SpdyConstants::SerializeFrameType(framer_.protocol_version(), | |
487 header_control_type))) { | |
488 DLOG(FATAL) << "Attempted to init header streaming with " | |
489 << "invalid control frame type: " | |
490 << header_control_type; | |
491 } | |
492 memset(header_buffer_.get(), 0, header_buffer_size_); | |
493 header_buffer_length_ = 0; | |
494 header_stream_id_ = stream_id; | |
495 header_control_type_ = header_control_type; | |
496 header_buffer_valid_ = true; | |
497 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
498 } | |
499 | |
500 // Override the default buffer size (16K). Call before using the framer! | |
501 void set_header_buffer_size(size_t header_buffer_size) { | |
502 header_buffer_size_ = header_buffer_size; | |
503 header_buffer_.reset(new char[header_buffer_size]); | |
504 } | |
505 | |
506 // Largest control frame that the SPDY implementation sends, including the | |
507 // size of the header. | |
508 static size_t sent_control_frame_max_size() { | |
509 return SpdyFramer::kMaxControlFrameSize; | |
510 } | |
511 | |
512 static size_t header_data_chunk_max_size() { | |
513 return SpdyFramer::kHeaderDataChunkMaxSize; | |
514 } | |
515 | |
516 SpdyFramer framer_; | |
517 bool use_compression_; | |
518 | |
519 // Counters from the visitor callbacks. | |
520 int error_count_; | |
521 int syn_frame_count_; | |
522 int syn_reply_frame_count_; | |
523 int headers_frame_count_; | |
524 int push_promise_frame_count_; | |
525 int goaway_count_; | |
526 int setting_count_; | |
527 int settings_ack_sent_; | |
528 int settings_ack_received_; | |
529 int continuation_count_; | |
530 int altsvc_count_; | |
531 int priority_count_; | |
532 SpdyAltSvcIR test_altsvc_ir_; | |
533 bool on_unknown_frame_result_; | |
534 SpdyStreamId last_window_update_stream_; | |
535 uint32 last_window_update_delta_; | |
536 SpdyStreamId last_push_promise_stream_; | |
537 SpdyStreamId last_push_promise_promised_stream_; | |
538 int data_bytes_; | |
539 int fin_frame_count_; // The count of RST_STREAM type frames received. | |
540 string fin_opaque_data_; | |
541 int fin_flag_count_; // The count of frames with the FIN flag set. | |
542 int zero_length_data_frame_count_; // The count of zero-length data frames. | |
543 int control_frame_header_data_count_; // The count of chunks received. | |
544 // The count of zero-length control frame header data chunks received. | |
545 int zero_length_control_frame_header_data_count_; | |
546 int data_frame_count_; | |
547 size_t last_payload_len_; | |
548 size_t last_frame_len_; | |
549 | |
550 // Header block streaming state: | |
551 scoped_ptr<char[]> header_buffer_; | |
552 size_t header_buffer_length_; | |
553 size_t header_buffer_size_; | |
554 SpdyStreamId header_stream_id_; | |
555 SpdyFrameType header_control_type_; | |
556 bool header_buffer_valid_; | |
557 SpdyHeaderBlock headers_; | |
558 }; | |
559 | |
560 // Retrieves serialized headers from a HEADERS or SYN_STREAM frame. | |
561 base::StringPiece GetSerializedHeaders(const SpdyFrame* frame, | |
562 const SpdyFramer& framer) { | |
563 SpdyFrameReader reader(frame->data(), frame->size()); | |
564 if (framer.protocol_version() > SPDY3) { | |
565 reader.Seek(3); // Seek past the frame length. | |
566 } else { | |
567 reader.Seek(2); // Seek past the frame length. | |
568 } | |
569 SpdyFrameType frame_type; | |
570 if (framer.protocol_version() > SPDY3) { | |
571 uint8 serialized_type; | |
572 reader.ReadUInt8(&serialized_type); | |
573 frame_type = SpdyConstants::ParseFrameType(framer.protocol_version(), | |
574 serialized_type); | |
575 DCHECK_EQ(HEADERS, frame_type); | |
576 uint8 flags; | |
577 reader.ReadUInt8(&flags); | |
578 if (flags & HEADERS_FLAG_PRIORITY) { | |
579 frame_type = SYN_STREAM; | |
580 } | |
581 } else { | |
582 uint16 serialized_type; | |
583 reader.ReadUInt16(&serialized_type); | |
584 frame_type = SpdyConstants::ParseFrameType(framer.protocol_version(), | |
585 serialized_type); | |
586 DCHECK(frame_type == HEADERS || | |
587 frame_type == SYN_STREAM) << frame_type; | |
588 } | |
589 | |
590 if (frame_type == SYN_STREAM) { | |
591 return StringPiece(frame->data() + framer.GetSynStreamMinimumSize(), | |
592 frame->size() - framer.GetSynStreamMinimumSize()); | |
593 } else { | |
594 return StringPiece(frame->data() + framer.GetHeadersMinimumSize(), | |
595 frame->size() - framer.GetHeadersMinimumSize()); | |
596 } | |
597 } | |
598 | |
599 } // namespace test | |
600 | |
601 } // namespace net | |
602 | |
603 using net::test::SetFrameLength; | |
604 using net::test::SetFrameFlags; | |
605 using net::test::CompareCharArraysWithHexError; | |
606 using net::test::SpdyFramerTestUtil; | |
607 using net::test::TestSpdyVisitor; | |
608 using net::test::GetSerializedHeaders; | |
609 | |
610 namespace net { | |
611 | |
612 class SpdyFramerTest : public ::testing::TestWithParam<SpdyMajorVersion> { | |
613 protected: | |
614 void SetUp() override { | |
615 spdy_version_ = GetParam(); | |
616 spdy_version_ch_ = static_cast<unsigned char>( | |
617 SpdyConstants::SerializeMajorVersion(spdy_version_)); | |
618 } | |
619 | |
620 void CompareFrame(const string& description, | |
621 const SpdyFrame& actual_frame, | |
622 const unsigned char* expected, | |
623 const int expected_len) { | |
624 const unsigned char* actual = | |
625 reinterpret_cast<const unsigned char*>(actual_frame.data()); | |
626 CompareCharArraysWithHexError( | |
627 description, actual, actual_frame.size(), expected, expected_len); | |
628 } | |
629 | |
630 void CompareFrames(const string& description, | |
631 const SpdyFrame& expected_frame, | |
632 const SpdyFrame& actual_frame) { | |
633 CompareCharArraysWithHexError( | |
634 description, | |
635 reinterpret_cast<const unsigned char*>(expected_frame.data()), | |
636 expected_frame.size(), | |
637 reinterpret_cast<const unsigned char*>(actual_frame.data()), | |
638 actual_frame.size()); | |
639 } | |
640 | |
641 // Returns true if the two header blocks have equivalent content. | |
642 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected, | |
643 const SpdyHeaderBlock* actual) { | |
644 if (expected->size() != actual->size()) { | |
645 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got " | |
646 << actual->size() << "."; | |
647 return false; | |
648 } | |
649 for (SpdyHeaderBlock::const_iterator it = expected->begin(); | |
650 it != expected->end(); | |
651 ++it) { | |
652 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first); | |
653 if (it2 == actual->end()) { | |
654 LOG(ERROR) << "Expected header name '" << it->first << "'."; | |
655 return false; | |
656 } | |
657 if (it->second.compare(it2->second) != 0) { | |
658 LOG(ERROR) << "Expected header named '" << it->first | |
659 << "' to have a value of '" << it->second | |
660 << "'. The actual value received was '" << it2->second | |
661 << "'."; | |
662 return false; | |
663 } | |
664 } | |
665 return true; | |
666 } | |
667 | |
668 bool IsSpdy2() { return spdy_version_ == SPDY2; } | |
669 bool IsSpdy3() { return spdy_version_ == SPDY3; } | |
670 bool IsSpdy4() { return spdy_version_ == SPDY4; } | |
671 | |
672 // Version of SPDY protocol to be used. | |
673 SpdyMajorVersion spdy_version_; | |
674 unsigned char spdy_version_ch_; | |
675 }; | |
676 | |
677 // All tests are run with 3 different SPDY versions: SPDY/2, SPDY/3, SPDY/4. | |
678 INSTANTIATE_TEST_CASE_P(SpdyFramerTests, | |
679 SpdyFramerTest, | |
680 ::testing::Values(SPDY2, SPDY3, SPDY4)); | |
681 | |
682 // Test that we ignore cookie where both name and value are empty. | |
683 TEST_P(SpdyFramerTest, HeaderBlockWithEmptyCookie) { | |
684 if (spdy_version_ > SPDY3) { | |
685 // Not implemented for hpack. | |
686 return; | |
687 } | |
688 | |
689 SpdyFramer framer(spdy_version_); | |
690 framer.set_enable_compression(true); | |
691 SpdyHeadersIR headers(1); | |
692 headers.set_priority(1); | |
693 headers.SetHeader("cookie", | |
694 "=; key=value; ; = ; foo; bar=; ; = ; k2=v2 ; ="); | |
695 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers)); | |
696 EXPECT_TRUE(frame.get() != NULL); | |
697 | |
698 TestSpdyVisitor visitor(spdy_version_); | |
699 visitor.use_compression_ = true; | |
700 visitor.SimulateInFramer( | |
701 reinterpret_cast<unsigned char*>(frame->data()), | |
702 frame->size()); | |
703 | |
704 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
705 EXPECT_FALSE(CompareHeaderBlocks(&headers.name_value_block(), | |
706 &visitor.headers_)); | |
707 EXPECT_EQ(1u, visitor.headers_.size()); | |
708 EXPECT_EQ("key=value; foo; bar=; k2=v2 ", visitor.headers_["cookie"]); | |
709 } | |
710 | |
711 // Test that we can encode and decode a SpdyHeaderBlock in serialized form. | |
712 TEST_P(SpdyFramerTest, HeaderBlockInBuffer) { | |
713 SpdyFramer framer(spdy_version_); | |
714 framer.set_enable_compression(false); | |
715 | |
716 // Encode the header block into a Headers frame. | |
717 SpdyHeadersIR headers(1); | |
718 headers.set_priority(1); | |
719 headers.SetHeader("alpha", "beta"); | |
720 headers.SetHeader("gamma", "charlie"); | |
721 headers.SetHeader("cookie", "key1=value1; key2=value2"); | |
722 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers)); | |
723 EXPECT_TRUE(frame.get() != NULL); | |
724 | |
725 TestSpdyVisitor visitor(spdy_version_); | |
726 visitor.use_compression_ = false; | |
727 visitor.SimulateInFramer( | |
728 reinterpret_cast<unsigned char*>(frame->data()), | |
729 frame->size()); | |
730 | |
731 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
732 EXPECT_TRUE(CompareHeaderBlocks(&headers.name_value_block(), | |
733 &visitor.headers_)); | |
734 } | |
735 | |
736 // Test that if there's not a full frame, we fail to parse it. | |
737 TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) { | |
738 SpdyFramer framer(spdy_version_); | |
739 framer.set_enable_compression(false); | |
740 | |
741 // Encode the header block into a Headers frame. | |
742 SpdyHeadersIR headers(1); | |
743 headers.set_priority(1); | |
744 headers.SetHeader("alpha", "beta"); | |
745 headers.SetHeader("gamma", "charlie"); | |
746 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers)); | |
747 EXPECT_TRUE(frame.get() != NULL); | |
748 | |
749 TestSpdyVisitor visitor(spdy_version_); | |
750 visitor.use_compression_ = false; | |
751 visitor.SimulateInFramer( | |
752 reinterpret_cast<unsigned char*>(frame->data()), | |
753 frame->size() - 2); | |
754 | |
755 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
756 EXPECT_EQ(0u, visitor.headers_.size()); | |
757 } | |
758 | |
759 // Test that if we receive a SYN_REPLY with stream ID zero, we signal an error | |
760 // (but don't crash). | |
761 TEST_P(SpdyFramerTest, SynReplyWithStreamIdZero) { | |
762 if (spdy_version_ > SPDY3) { | |
763 return; | |
764 } | |
765 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
766 SpdyFramer framer(spdy_version_); | |
767 framer.set_visitor(&visitor); | |
768 | |
769 SpdySynReplyIR syn_reply(0); | |
770 syn_reply.SetHeader("alpha", "beta"); | |
771 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeSynReply(syn_reply)); | |
772 ASSERT_TRUE(frame.get() != NULL); | |
773 | |
774 // We shouldn't have to read the whole frame before we signal an error. | |
775 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
776 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); | |
777 EXPECT_TRUE(framer.HasError()); | |
778 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) | |
779 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
780 } | |
781 | |
782 // Test that if we receive a HEADERS with stream ID zero, we signal an error | |
783 // (but don't crash). | |
784 TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) { | |
785 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
786 SpdyFramer framer(spdy_version_); | |
787 framer.set_visitor(&visitor); | |
788 | |
789 SpdyHeadersIR headers_ir(0); | |
790 headers_ir.SetHeader("alpha", "beta"); | |
791 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeHeaders(headers_ir)); | |
792 ASSERT_TRUE(frame.get() != NULL); | |
793 | |
794 // We shouldn't have to read the whole frame before we signal an error. | |
795 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
796 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); | |
797 EXPECT_TRUE(framer.HasError()); | |
798 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) | |
799 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
800 } | |
801 | |
802 // Test that if we receive a PUSH_PROMISE with stream ID zero, we signal an | |
803 // error (but don't crash). | |
804 TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) { | |
805 if (spdy_version_ <= SPDY3) { | |
806 return; | |
807 } | |
808 | |
809 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
810 SpdyFramer framer(spdy_version_); | |
811 framer.set_visitor(&visitor); | |
812 | |
813 SpdyPushPromiseIR push_promise(0, 4); | |
814 push_promise.SetHeader("alpha", "beta"); | |
815 scoped_ptr<SpdySerializedFrame> frame( | |
816 framer.SerializePushPromise(push_promise)); | |
817 ASSERT_TRUE(frame.get() != NULL); | |
818 | |
819 // We shouldn't have to read the whole frame before we signal an error. | |
820 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
821 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); | |
822 EXPECT_TRUE(framer.HasError()); | |
823 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) | |
824 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
825 } | |
826 | |
827 // Test that if we receive a PUSH_PROMISE with promised stream ID zero, we | |
828 // signal an error (but don't crash). | |
829 TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) { | |
830 if (spdy_version_ <= SPDY3) { | |
831 return; | |
832 } | |
833 | |
834 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
835 SpdyFramer framer(spdy_version_); | |
836 framer.set_visitor(&visitor); | |
837 | |
838 SpdyPushPromiseIR push_promise(3, 0); | |
839 push_promise.SetHeader("alpha", "beta"); | |
840 scoped_ptr<SpdySerializedFrame> frame( | |
841 framer.SerializePushPromise(push_promise)); | |
842 ASSERT_TRUE(frame.get() != NULL); | |
843 | |
844 // We shouldn't have to read the whole frame before we signal an error. | |
845 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
846 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); | |
847 EXPECT_TRUE(framer.HasError()); | |
848 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) | |
849 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
850 } | |
851 | |
852 TEST_P(SpdyFramerTest, DuplicateHeader) { | |
853 if (spdy_version_ > SPDY3) { | |
854 // TODO(jgraettinger): Punting on this because we haven't determined | |
855 // whether duplicate HPACK headers other than Cookie are an error. | |
856 // If they are, this will need to be updated to use HpackOutputStream. | |
857 return; | |
858 } | |
859 SpdyFramer framer(spdy_version_); | |
860 // Frame builder with plentiful buffer size. | |
861 SpdyFrameBuilder frame(1024, spdy_version_); | |
862 if (spdy_version_ <= SPDY3) { | |
863 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE); | |
864 frame.WriteUInt32(3); // stream_id | |
865 frame.WriteUInt32(0); // associated stream id | |
866 frame.WriteUInt16(0); // Priority. | |
867 } else { | |
868 frame.BeginNewFrame(framer, HEADERS, HEADERS_FLAG_PRIORITY, 3); | |
869 frame.WriteUInt32(framer.GetHighestPriority()); | |
870 } | |
871 | |
872 if (IsSpdy2()) { | |
873 frame.WriteUInt16(2); // Number of headers. | |
874 frame.WriteString("name"); | |
875 frame.WriteString("value1"); | |
876 frame.WriteString("name"); | |
877 frame.WriteString("value2"); | |
878 } else { | |
879 frame.WriteUInt32(2); // Number of headers. | |
880 frame.WriteStringPiece32("name"); | |
881 frame.WriteStringPiece32("value1"); | |
882 frame.WriteStringPiece32("name"); | |
883 frame.WriteStringPiece32("value2"); | |
884 } | |
885 // write the length | |
886 frame.RewriteLength(framer); | |
887 | |
888 SpdyHeaderBlock new_headers; | |
889 framer.set_enable_compression(false); | |
890 scoped_ptr<SpdyFrame> control_frame(frame.take()); | |
891 base::StringPiece serialized_headers = | |
892 GetSerializedHeaders(control_frame.get(), framer); | |
893 // This should fail because duplicate headers are verboten by the spec. | |
894 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(), | |
895 serialized_headers.size(), | |
896 &new_headers)); | |
897 } | |
898 | |
899 TEST_P(SpdyFramerTest, MultiValueHeader) { | |
900 SpdyFramer framer(spdy_version_); | |
901 // Frame builder with plentiful buffer size. | |
902 SpdyFrameBuilder frame(1024, spdy_version_); | |
903 if (spdy_version_ <= SPDY3) { | |
904 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE); | |
905 frame.WriteUInt32(3); // stream_id | |
906 frame.WriteUInt32(0); // associated stream id | |
907 frame.WriteUInt16(0); // Priority. | |
908 } else { | |
909 frame.BeginNewFrame(framer, | |
910 HEADERS, | |
911 HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS, | |
912 3); | |
913 frame.WriteUInt32(0); // Priority exclusivity and dependent stream. | |
914 frame.WriteUInt8(255); // Priority weight. | |
915 } | |
916 | |
917 string value("value1\0value2", 13); | |
918 if (IsSpdy2()) { | |
919 frame.WriteUInt16(1); // Number of headers. | |
920 frame.WriteString("name"); | |
921 frame.WriteString(value); | |
922 } else if (spdy_version_ > SPDY3) { | |
923 // TODO(jgraettinger): If this pattern appears again, move to test class. | |
924 std::map<string, string> header_set; | |
925 header_set["name"] = value; | |
926 string buffer; | |
927 HpackEncoder encoder(ObtainHpackHuffmanTable()); | |
928 encoder.EncodeHeaderSetWithoutCompression(header_set, &buffer); | |
929 frame.WriteBytes(&buffer[0], buffer.size()); | |
930 } else { | |
931 frame.WriteUInt32(1); // Number of headers. | |
932 frame.WriteStringPiece32("name"); | |
933 frame.WriteStringPiece32(value); | |
934 } | |
935 // write the length | |
936 frame.RewriteLength(framer); | |
937 | |
938 framer.set_enable_compression(false); | |
939 scoped_ptr<SpdyFrame> control_frame(frame.take()); | |
940 | |
941 TestSpdyVisitor visitor(spdy_version_); | |
942 visitor.use_compression_ = false; | |
943 visitor.SimulateInFramer( | |
944 reinterpret_cast<unsigned char*>(control_frame->data()), | |
945 control_frame->size()); | |
946 | |
947 EXPECT_THAT(visitor.headers_, | |
948 testing::ElementsAre(testing::Pair("name", value))); | |
949 } | |
950 | |
951 TEST_P(SpdyFramerTest, BasicCompression) { | |
952 if (spdy_version_ > SPDY3) { | |
953 // Deflate compression doesn't apply to HPACK. | |
954 return; | |
955 } | |
956 scoped_ptr<TestSpdyVisitor> visitor(new TestSpdyVisitor(spdy_version_)); | |
957 SpdyFramer framer(spdy_version_); | |
958 framer.set_debug_visitor(visitor.get()); | |
959 SpdySynStreamIR syn_stream(1); | |
960 syn_stream.set_priority(1); | |
961 syn_stream.SetHeader("server", "SpdyServer 1.0"); | |
962 syn_stream.SetHeader("date", "Mon 12 Jan 2009 12:12:12 PST"); | |
963 syn_stream.SetHeader("status", "200"); | |
964 syn_stream.SetHeader("version", "HTTP/1.1"); | |
965 syn_stream.SetHeader("content-type", "text/html"); | |
966 syn_stream.SetHeader("content-length", "12"); | |
967 scoped_ptr<SpdyFrame> frame1(framer.SerializeSynStream(syn_stream)); | |
968 size_t uncompressed_size1 = visitor->last_payload_len_; | |
969 size_t compressed_size1 = | |
970 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize(); | |
971 if (IsSpdy2()) { | |
972 EXPECT_EQ(139u, uncompressed_size1); | |
973 #if defined(USE_SYSTEM_ZLIB) | |
974 EXPECT_EQ(155u, compressed_size1); | |
975 #else // !defined(USE_SYSTEM_ZLIB) | |
976 EXPECT_EQ(135u, compressed_size1); | |
977 #endif // !defined(USE_SYSTEM_ZLIB) | |
978 } else { | |
979 EXPECT_EQ(165u, uncompressed_size1); | |
980 #if defined(USE_SYSTEM_ZLIB) | |
981 EXPECT_EQ(181u, compressed_size1); | |
982 #else // !defined(USE_SYSTEM_ZLIB) | |
983 EXPECT_EQ(117u, compressed_size1); | |
984 #endif // !defined(USE_SYSTEM_ZLIB) | |
985 } | |
986 scoped_ptr<SpdyFrame> frame2(framer.SerializeSynStream(syn_stream)); | |
987 size_t uncompressed_size2 = visitor->last_payload_len_; | |
988 size_t compressed_size2 = | |
989 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize(); | |
990 | |
991 // Expect the second frame to be more compact than the first. | |
992 EXPECT_LE(frame2->size(), frame1->size()); | |
993 | |
994 // Decompress the first frame | |
995 scoped_ptr<SpdyFrame> frame3( | |
996 SpdyFramerTestUtil::DecompressFrame(&framer, *frame1)); | |
997 | |
998 // Decompress the second frame | |
999 visitor.reset(new TestSpdyVisitor(spdy_version_)); | |
1000 framer.set_debug_visitor(visitor.get()); | |
1001 scoped_ptr<SpdyFrame> frame4( | |
1002 SpdyFramerTestUtil::DecompressFrame(&framer, *frame2)); | |
1003 size_t uncompressed_size4 = | |
1004 frame4->size() - framer.GetSynStreamMinimumSize(); | |
1005 size_t compressed_size4 = | |
1006 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize(); | |
1007 if (IsSpdy2()) { | |
1008 EXPECT_EQ(139u, uncompressed_size4); | |
1009 #if defined(USE_SYSTEM_ZLIB) | |
1010 EXPECT_EQ(149u, compressed_size4); | |
1011 #else // !defined(USE_SYSTEM_ZLIB) | |
1012 EXPECT_EQ(101u, compressed_size4); | |
1013 #endif // !defined(USE_SYSTEM_ZLIB) | |
1014 } else { | |
1015 EXPECT_EQ(165u, uncompressed_size4); | |
1016 #if defined(USE_SYSTEM_ZLIB) | |
1017 EXPECT_EQ(175u, compressed_size4); | |
1018 #else // !defined(USE_SYSTEM_ZLIB) | |
1019 EXPECT_EQ(102u, compressed_size4); | |
1020 #endif // !defined(USE_SYSTEM_ZLIB) | |
1021 } | |
1022 | |
1023 EXPECT_EQ(uncompressed_size1, uncompressed_size2); | |
1024 EXPECT_EQ(uncompressed_size1, uncompressed_size4); | |
1025 EXPECT_EQ(compressed_size2, compressed_size4); | |
1026 | |
1027 // Expect frames 3 & 4 to be the same. | |
1028 CompareFrames("Uncompressed SYN_STREAM", *frame3, *frame4); | |
1029 | |
1030 // Expect frames 3 to be the same as a uncompressed frame created | |
1031 // from scratch. | |
1032 framer.set_enable_compression(false); | |
1033 scoped_ptr<SpdyFrame> uncompressed_frame( | |
1034 framer.SerializeSynStream(syn_stream)); | |
1035 CompareFrames("Uncompressed SYN_STREAM", *frame3, *uncompressed_frame); | |
1036 } | |
1037 | |
1038 TEST_P(SpdyFramerTest, CompressEmptyHeaders) { | |
1039 // See crbug.com/172383 | |
1040 SpdyHeadersIR headers(1); | |
1041 headers.SetHeader("server", "SpdyServer 1.0"); | |
1042 headers.SetHeader("date", "Mon 12 Jan 2009 12:12:12 PST"); | |
1043 headers.SetHeader("status", "200"); | |
1044 headers.SetHeader("version", "HTTP/1.1"); | |
1045 headers.SetHeader("content-type", "text/html"); | |
1046 headers.SetHeader("content-length", "12"); | |
1047 headers.SetHeader("x-empty-header", ""); | |
1048 | |
1049 SpdyFramer framer(spdy_version_); | |
1050 framer.set_enable_compression(true); | |
1051 scoped_ptr<SpdyFrame> frame1(framer.SerializeHeaders(headers)); | |
1052 } | |
1053 | |
1054 TEST_P(SpdyFramerTest, Basic) { | |
1055 const unsigned char kV2Input[] = { | |
1056 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 | |
1057 0x00, 0x00, 0x00, 0x14, | |
1058 0x00, 0x00, 0x00, 0x01, | |
1059 0x00, 0x00, 0x00, 0x00, | |
1060 0x00, 0x00, 0x00, 0x01, | |
1061 0x00, 0x02, 'h', 'h', | |
1062 0x00, 0x02, 'v', 'v', | |
1063 | |
1064 0x80, spdy_version_ch_, 0x00, 0x08, // HEADERS on Stream #1 | |
1065 0x00, 0x00, 0x00, 0x18, | |
1066 0x00, 0x00, 0x00, 0x01, | |
1067 0x00, 0x00, 0x00, 0x02, | |
1068 0x00, 0x02, 'h', '2', | |
1069 0x00, 0x02, 'v', '2', | |
1070 0x00, 0x02, 'h', '3', | |
1071 0x00, 0x02, 'v', '3', | |
1072 | |
1073 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
1074 0x00, 0x00, 0x00, 0x0c, | |
1075 0xde, 0xad, 0xbe, 0xef, | |
1076 0xde, 0xad, 0xbe, 0xef, | |
1077 0xde, 0xad, 0xbe, 0xef, | |
1078 | |
1079 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #3 | |
1080 0x00, 0x00, 0x00, 0x0c, | |
1081 0x00, 0x00, 0x00, 0x03, | |
1082 0x00, 0x00, 0x00, 0x00, | |
1083 0x00, 0x00, 0x00, 0x00, | |
1084 | |
1085 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
1086 0x00, 0x00, 0x00, 0x08, | |
1087 0xde, 0xad, 0xbe, 0xef, | |
1088 0xde, 0xad, 0xbe, 0xef, | |
1089 | |
1090 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
1091 0x00, 0x00, 0x00, 0x04, | |
1092 0xde, 0xad, 0xbe, 0xef, | |
1093 | |
1094 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #1 | |
1095 0x00, 0x00, 0x00, 0x08, | |
1096 0x00, 0x00, 0x00, 0x01, | |
1097 0x00, 0x00, 0x00, 0x05, // RST_STREAM_CANCEL | |
1098 | |
1099 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
1100 0x00, 0x00, 0x00, 0x00, | |
1101 | |
1102 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #3 | |
1103 0x00, 0x00, 0x00, 0x08, | |
1104 0x00, 0x00, 0x00, 0x03, | |
1105 0x00, 0x00, 0x00, 0x05, // RST_STREAM_CANCEL | |
1106 }; | |
1107 | |
1108 const unsigned char kV3Input[] = { | |
1109 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 | |
1110 0x00, 0x00, 0x00, 0x1a, | |
1111 0x00, 0x00, 0x00, 0x01, | |
1112 0x00, 0x00, 0x00, 0x00, | |
1113 0x00, 0x00, 0x00, 0x00, | |
1114 0x00, 0x01, 0x00, 0x00, | |
1115 0x00, 0x02, 'h', 'h', | |
1116 0x00, 0x00, 0x00, 0x02, | |
1117 'v', 'v', | |
1118 | |
1119 0x80, spdy_version_ch_, 0x00, 0x08, // HEADERS on Stream #1 | |
1120 0x00, 0x00, 0x00, 0x20, | |
1121 0x00, 0x00, 0x00, 0x01, | |
1122 0x00, 0x00, 0x00, 0x02, | |
1123 0x00, 0x00, 0x00, 0x02, | |
1124 'h', '2', | |
1125 0x00, 0x00, 0x00, 0x02, | |
1126 'v', '2', 0x00, 0x00, | |
1127 0x00, 0x02, 'h', '3', | |
1128 0x00, 0x00, 0x00, 0x02, | |
1129 'v', '3', | |
1130 | |
1131 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
1132 0x00, 0x00, 0x00, 0x0c, | |
1133 0xde, 0xad, 0xbe, 0xef, | |
1134 0xde, 0xad, 0xbe, 0xef, | |
1135 0xde, 0xad, 0xbe, 0xef, | |
1136 | |
1137 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #3 | |
1138 0x00, 0x00, 0x00, 0x0e, | |
1139 0x00, 0x00, 0x00, 0x03, | |
1140 0x00, 0x00, 0x00, 0x00, | |
1141 0x00, 0x00, 0x00, 0x00, | |
1142 0x00, 0x00, | |
1143 | |
1144 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
1145 0x00, 0x00, 0x00, 0x08, | |
1146 0xde, 0xad, 0xbe, 0xef, | |
1147 0xde, 0xad, 0xbe, 0xef, | |
1148 | |
1149 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
1150 0x00, 0x00, 0x00, 0x04, | |
1151 0xde, 0xad, 0xbe, 0xef, | |
1152 | |
1153 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #1 | |
1154 0x00, 0x00, 0x00, 0x08, | |
1155 0x00, 0x00, 0x00, 0x01, | |
1156 0x00, 0x00, 0x00, 0x05, // RST_STREAM_CANCEL | |
1157 | |
1158 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
1159 0x00, 0x00, 0x00, 0x00, | |
1160 | |
1161 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #3 | |
1162 0x00, 0x00, 0x00, 0x08, | |
1163 0x00, 0x00, 0x00, 0x03, | |
1164 0x00, 0x00, 0x00, 0x05, // RST_STREAM_CANCEL | |
1165 }; | |
1166 | |
1167 // SYN_STREAM doesn't exist in SPDY4, so instead we send | |
1168 // HEADERS frames with PRIORITY and END_HEADERS set. | |
1169 const unsigned char kV4Input[] = { | |
1170 0x00, 0x00, 0x05, 0x01, // HEADERS: PRIORITY | END_HEADERS | |
1171 0x24, 0x00, 0x00, 0x00, | |
1172 0x01, 0x00, 0x00, 0x00, // Stream 1, Priority 0 | |
1173 0x00, 0x82, // :method: GET | |
1174 | |
1175 0x00, 0x00, 0x01, 0x01, // HEADERS: END_HEADERS | |
1176 0x04, 0x00, 0x00, 0x00, // Stream 1 | |
1177 0x01, 0x8c, // :status: 200 | |
1178 | |
1179 0x00, 0x00, 0x0c, 0x00, // DATA on Stream #1 | |
1180 0x00, 0x00, 0x00, 0x00, | |
1181 0x01, 0xde, 0xad, 0xbe, | |
1182 0xef, 0xde, 0xad, 0xbe, | |
1183 0xef, 0xde, 0xad, 0xbe, | |
1184 0xef, | |
1185 | |
1186 0x00, 0x00, 0x05, 0x01, // HEADERS: PRIORITY | END_HEADERS | |
1187 0x24, 0x00, 0x00, 0x00, | |
1188 0x03, 0x00, 0x00, 0x00, // Stream 3, Priority 0 | |
1189 0x00, 0x82, // :method: GET | |
1190 | |
1191 0x00, 0x00, 0x08, 0x00, // DATA on Stream #3 | |
1192 0x00, 0x00, 0x00, 0x00, | |
1193 0x03, 0xde, 0xad, 0xbe, | |
1194 0xef, 0xde, 0xad, 0xbe, | |
1195 0xef, | |
1196 | |
1197 0x00, 0x00, 0x04, 0x00, // DATA on Stream #1 | |
1198 0x00, 0x00, 0x00, 0x00, | |
1199 0x01, 0xde, 0xad, 0xbe, | |
1200 0xef, | |
1201 | |
1202 0x00, 0x00, 0x04, 0x03, // RST_STREAM on Stream #1 | |
1203 0x00, 0x00, 0x00, 0x00, | |
1204 0x01, 0x00, 0x00, 0x00, | |
1205 0x08, // RST_STREAM_CANCEL | |
1206 | |
1207 0x00, 0x00, 0x00, 0x00, // DATA on Stream #3 | |
1208 0x00, 0x00, 0x00, 0x00, | |
1209 0x03, | |
1210 | |
1211 0x00, 0x00, 0x0f, 0x03, // RST_STREAM on Stream #3 | |
1212 0x00, 0x00, 0x00, 0x00, | |
1213 0x03, 0x00, 0x00, 0x00, // RST_STREAM_CANCEL | |
1214 0x08, 0x52, 0x45, 0x53, // opaque data | |
1215 0x45, 0x54, 0x53, 0x54, | |
1216 0x52, 0x45, 0x41, 0x4d, | |
1217 }; | |
1218 | |
1219 TestSpdyVisitor visitor(spdy_version_); | |
1220 if (IsSpdy2()) { | |
1221 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); | |
1222 } else if (IsSpdy3()) { | |
1223 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); | |
1224 } else { | |
1225 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input)); | |
1226 } | |
1227 | |
1228 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
1229 EXPECT_EQ(24, visitor.data_bytes_); | |
1230 EXPECT_EQ(0, visitor.error_count_); | |
1231 EXPECT_EQ(2, visitor.fin_frame_count_); | |
1232 | |
1233 if (IsSpdy4()) { | |
1234 EXPECT_EQ(3, visitor.headers_frame_count_); | |
1235 EXPECT_EQ(0, visitor.syn_frame_count_); | |
1236 base::StringPiece reset_stream = "RESETSTREAM"; | |
1237 EXPECT_EQ(reset_stream, visitor.fin_opaque_data_); | |
1238 } else { | |
1239 EXPECT_EQ(1, visitor.headers_frame_count_); | |
1240 EXPECT_EQ(2, visitor.syn_frame_count_); | |
1241 EXPECT_TRUE(visitor.fin_opaque_data_.empty()); | |
1242 } | |
1243 | |
1244 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1245 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); | |
1246 EXPECT_EQ(4, visitor.data_frame_count_); | |
1247 visitor.fin_opaque_data_.clear(); | |
1248 } | |
1249 | |
1250 // Test that the FIN flag on a data frame signifies EOF. | |
1251 TEST_P(SpdyFramerTest, FinOnDataFrame) { | |
1252 const unsigned char kV2Input[] = { | |
1253 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 | |
1254 0x00, 0x00, 0x00, 0x14, | |
1255 0x00, 0x00, 0x00, 0x01, | |
1256 0x00, 0x00, 0x00, 0x00, | |
1257 0x00, 0x00, 0x00, 0x01, | |
1258 0x00, 0x02, 'h', 'h', | |
1259 0x00, 0x02, 'v', 'v', | |
1260 | |
1261 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1 | |
1262 0x00, 0x00, 0x00, 0x10, | |
1263 0x00, 0x00, 0x00, 0x01, | |
1264 0x00, 0x00, 0x00, 0x01, | |
1265 0x00, 0x02, 'a', 'a', | |
1266 0x00, 0x02, 'b', 'b', | |
1267 | |
1268 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
1269 0x00, 0x00, 0x00, 0x0c, | |
1270 0xde, 0xad, 0xbe, 0xef, | |
1271 0xde, 0xad, 0xbe, 0xef, | |
1272 0xde, 0xad, 0xbe, 0xef, | |
1273 | |
1274 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF | |
1275 0x01, 0x00, 0x00, 0x04, | |
1276 0xde, 0xad, 0xbe, 0xef, | |
1277 }; | |
1278 const unsigned char kV3Input[] = { | |
1279 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 | |
1280 0x00, 0x00, 0x00, 0x1a, | |
1281 0x00, 0x00, 0x00, 0x01, | |
1282 0x00, 0x00, 0x00, 0x00, | |
1283 0x00, 0x00, 0x00, 0x00, | |
1284 0x00, 0x01, 0x00, 0x00, | |
1285 0x00, 0x02, 'h', 'h', | |
1286 0x00, 0x00, 0x00, 0x02, | |
1287 'v', 'v', | |
1288 | |
1289 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1 | |
1290 0x00, 0x00, 0x00, 0x14, | |
1291 0x00, 0x00, 0x00, 0x01, | |
1292 0x00, 0x00, 0x00, 0x01, | |
1293 0x00, 0x00, 0x00, 0x02, | |
1294 'a', 'a', 0x00, 0x00, | |
1295 0x00, 0x02, 'b', 'b', | |
1296 | |
1297 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
1298 0x00, 0x00, 0x00, 0x0c, | |
1299 0xde, 0xad, 0xbe, 0xef, | |
1300 0xde, 0xad, 0xbe, 0xef, | |
1301 0xde, 0xad, 0xbe, 0xef, | |
1302 | |
1303 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF | |
1304 0x01, 0x00, 0x00, 0x04, | |
1305 0xde, 0xad, 0xbe, 0xef, | |
1306 }; | |
1307 | |
1308 // SYN_STREAM and SYN_REPLY don't exist in SPDY4, so instead we send | |
1309 // HEADERS frames with PRIORITY(SYN_STREAM only) and END_HEADERS set. | |
1310 const unsigned char kV4Input[] = { | |
1311 0x00, 0x00, 0x05, 0x01, // HEADERS: PRIORITY | END_HEADERS | |
1312 0x24, 0x00, 0x00, 0x00, // Stream 1 | |
1313 0x01, 0x00, 0x00, 0x00, // Priority 0 | |
1314 0x00, 0x82, // :method: GET | |
1315 | |
1316 0x00, 0x00, 0x01, 0x01, // HEADERS: END_HEADERS | |
1317 0x04, 0x00, 0x00, 0x00, // Stream 1 | |
1318 0x01, 0x8c, // :status: 200 | |
1319 | |
1320 0x00, 0x00, 0x0c, 0x00, // DATA on Stream #1 | |
1321 0x00, 0x00, 0x00, 0x00, | |
1322 0x01, 0xde, 0xad, 0xbe, | |
1323 0xef, 0xde, 0xad, 0xbe, | |
1324 0xef, 0xde, 0xad, 0xbe, | |
1325 0xef, | |
1326 | |
1327 0x00, 0x00, 0x04, 0x00, // DATA on Stream #1, with FIN | |
1328 0x01, 0x00, 0x00, 0x00, | |
1329 0x01, 0xde, 0xad, 0xbe, | |
1330 0xef, | |
1331 }; | |
1332 | |
1333 TestSpdyVisitor visitor(spdy_version_); | |
1334 if (IsSpdy2()) { | |
1335 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); | |
1336 } else if (IsSpdy3()) { | |
1337 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); | |
1338 } else { | |
1339 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input)); | |
1340 } | |
1341 | |
1342 EXPECT_EQ(0, visitor.error_count_); | |
1343 if (IsSpdy4()) { | |
1344 EXPECT_EQ(0, visitor.syn_frame_count_); | |
1345 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
1346 EXPECT_EQ(2, visitor.headers_frame_count_); | |
1347 } else { | |
1348 EXPECT_EQ(1, visitor.syn_frame_count_); | |
1349 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
1350 EXPECT_EQ(0, visitor.headers_frame_count_); | |
1351 } | |
1352 EXPECT_EQ(16, visitor.data_bytes_); | |
1353 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1354 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1355 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
1356 EXPECT_EQ(2, visitor.data_frame_count_); | |
1357 } | |
1358 | |
1359 // Test that the FIN flag on a SYN reply frame signifies EOF. | |
1360 TEST_P(SpdyFramerTest, FinOnSynReplyFrame) { | |
1361 const unsigned char kV2Input[] = { | |
1362 0x80, spdy_version_ch_, 0x00, // SYN Stream #1 | |
1363 0x01, 0x00, 0x00, 0x00, | |
1364 0x14, 0x00, 0x00, 0x00, | |
1365 0x01, 0x00, 0x00, 0x00, | |
1366 0x00, 0x00, 0x00, 0x00, | |
1367 0x01, 0x00, 0x02, 'h', | |
1368 'h', 0x00, 0x02, 'v', | |
1369 'v', | |
1370 | |
1371 0x80, spdy_version_ch_, 0x00, // SYN REPLY Stream #1 | |
1372 0x02, 0x01, 0x00, 0x00, | |
1373 0x10, 0x00, 0x00, 0x00, | |
1374 0x01, 0x00, 0x00, 0x00, | |
1375 0x01, 0x00, 0x02, 'a', | |
1376 'a', 0x00, 0x02, 'b', | |
1377 'b', | |
1378 }; | |
1379 const unsigned char kV3Input[] = { | |
1380 0x80, spdy_version_ch_, 0x00, // SYN Stream #1 | |
1381 0x01, 0x00, 0x00, 0x00, | |
1382 0x1a, 0x00, 0x00, 0x00, | |
1383 0x01, 0x00, 0x00, 0x00, | |
1384 0x00, 0x00, 0x00, 0x00, | |
1385 0x00, 0x00, 0x01, 0x00, | |
1386 0x00, 0x00, 0x02, 'h', | |
1387 'h', 0x00, 0x00, 0x00, | |
1388 0x02, 'v', 'v', | |
1389 | |
1390 0x80, spdy_version_ch_, 0x00, // SYN REPLY Stream #1 | |
1391 0x02, 0x01, 0x00, 0x00, | |
1392 0x14, 0x00, 0x00, 0x00, | |
1393 0x01, 0x00, 0x00, 0x00, | |
1394 0x01, 0x00, 0x00, 0x00, | |
1395 0x02, 'a', 'a', 0x00, | |
1396 0x00, 0x00, 0x02, 'b', | |
1397 'b', | |
1398 }; | |
1399 | |
1400 // SYN_STREAM and SYN_REPLY don't exist in SPDY4, so instead we send | |
1401 // HEADERS frames with PRIORITY(SYN_STREAM only) and END_HEADERS set. | |
1402 const unsigned char kV4Input[] = { | |
1403 0x00, 0x00, 0x05, 0x01, // HEADERS: PRIORITY | END_HEADERS | |
1404 0x24, 0x00, 0x00, 0x00, | |
1405 0x01, 0x00, 0x00, 0x00, // Stream 1, Priority 0 | |
1406 0x00, 0x82, // :method: GET | |
1407 | |
1408 0x00, 0x00, 0x01, 0x01, // HEADERS: FIN | END_HEADERS | |
1409 0x05, 0x00, 0x00, 0x00, | |
1410 0x01, 0x8c, // Stream 1, :status: 200 | |
1411 }; | |
1412 | |
1413 TestSpdyVisitor visitor(spdy_version_); | |
1414 if (IsSpdy2()) { | |
1415 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); | |
1416 } else if (IsSpdy3()) { | |
1417 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); | |
1418 } else { | |
1419 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input)); | |
1420 } | |
1421 | |
1422 EXPECT_EQ(0, visitor.error_count_); | |
1423 if (IsSpdy4()) { | |
1424 EXPECT_EQ(0, visitor.syn_frame_count_); | |
1425 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
1426 EXPECT_EQ(2, visitor.headers_frame_count_); | |
1427 } else { | |
1428 EXPECT_EQ(1, visitor.syn_frame_count_); | |
1429 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
1430 EXPECT_EQ(0, visitor.headers_frame_count_); | |
1431 } | |
1432 EXPECT_EQ(0, visitor.data_bytes_); | |
1433 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1434 EXPECT_EQ(1, visitor.fin_flag_count_); | |
1435 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
1436 EXPECT_EQ(0, visitor.data_frame_count_); | |
1437 } | |
1438 | |
1439 TEST_P(SpdyFramerTest, HeaderCompression) { | |
1440 if (spdy_version_ > SPDY3) { | |
1441 // Deflate compression doesn't apply to HPACK. | |
1442 return; | |
1443 } | |
1444 SpdyFramer send_framer(spdy_version_); | |
1445 SpdyFramer recv_framer(spdy_version_); | |
1446 | |
1447 send_framer.set_enable_compression(true); | |
1448 recv_framer.set_enable_compression(true); | |
1449 | |
1450 const char kHeader1[] = "header1"; | |
1451 const char kHeader2[] = "header2"; | |
1452 const char kHeader3[] = "header3"; | |
1453 const char kValue1[] = "value1"; | |
1454 const char kValue2[] = "value2"; | |
1455 const char kValue3[] = "value3"; | |
1456 | |
1457 // SYN_STREAM #1 | |
1458 SpdyHeaderBlock block; | |
1459 block[kHeader1] = kValue1; | |
1460 block[kHeader2] = kValue2; | |
1461 SpdySynStreamIR syn_ir_1(1); | |
1462 syn_ir_1.set_name_value_block(block); | |
1463 scoped_ptr<SpdyFrame> syn_frame_1(send_framer.SerializeFrame(syn_ir_1)); | |
1464 EXPECT_TRUE(syn_frame_1.get() != NULL); | |
1465 | |
1466 // SYN_STREAM #2 | |
1467 block[kHeader3] = kValue3; | |
1468 SpdySynStreamIR syn_stream(3); | |
1469 syn_stream.set_name_value_block(block); | |
1470 scoped_ptr<SpdyFrame> syn_frame_2(send_framer.SerializeSynStream(syn_stream)); | |
1471 EXPECT_TRUE(syn_frame_2.get() != NULL); | |
1472 | |
1473 // Now start decompressing | |
1474 scoped_ptr<SpdyFrame> decompressed; | |
1475 scoped_ptr<SpdyFrame> uncompressed; | |
1476 base::StringPiece serialized_headers; | |
1477 SpdyHeaderBlock decompressed_headers; | |
1478 | |
1479 // Decompress SYN_STREAM #1 | |
1480 decompressed.reset( | |
1481 SpdyFramerTestUtil::DecompressFrame(&recv_framer, *syn_frame_1)); | |
1482 EXPECT_TRUE(decompressed.get() != NULL); | |
1483 serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer); | |
1484 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(), | |
1485 serialized_headers.size(), | |
1486 &decompressed_headers)); | |
1487 EXPECT_EQ(2u, decompressed_headers.size()); | |
1488 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); | |
1489 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); | |
1490 | |
1491 // Decompress SYN_STREAM #2 | |
1492 decompressed.reset( | |
1493 SpdyFramerTestUtil::DecompressFrame(&recv_framer, *syn_frame_2)); | |
1494 EXPECT_TRUE(decompressed.get() != NULL); | |
1495 serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer); | |
1496 decompressed_headers.clear(); | |
1497 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(), | |
1498 serialized_headers.size(), | |
1499 &decompressed_headers)); | |
1500 EXPECT_EQ(3u, decompressed_headers.size()); | |
1501 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); | |
1502 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); | |
1503 EXPECT_EQ(kValue3, decompressed_headers[kHeader3]); | |
1504 } | |
1505 | |
1506 // Verify we can decompress the stream even if handed over to the | |
1507 // framer 1 byte at a time. | |
1508 TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) { | |
1509 SpdyFramer send_framer(spdy_version_); | |
1510 | |
1511 send_framer.set_enable_compression(true); | |
1512 | |
1513 const char kHeader1[] = "header1"; | |
1514 const char kHeader2[] = "header2"; | |
1515 const char kValue1[] = "value1"; | |
1516 const char kValue2[] = "value2"; | |
1517 | |
1518 SpdyHeadersIR headers(1); | |
1519 headers.SetHeader(kHeader1, kValue1); | |
1520 headers.SetHeader(kHeader2, kValue2); | |
1521 scoped_ptr<SpdyFrame> headers_frame(send_framer.SerializeHeaders(headers)); | |
1522 EXPECT_TRUE(headers_frame.get() != NULL); | |
1523 | |
1524 const char bytes[] = "this is a test test test test test!"; | |
1525 SpdyDataIR data_ir(1, StringPiece(bytes, arraysize(bytes))); | |
1526 data_ir.set_fin(true); | |
1527 scoped_ptr<SpdyFrame> send_frame(send_framer.SerializeData(data_ir)); | |
1528 EXPECT_TRUE(send_frame.get() != NULL); | |
1529 | |
1530 // Run the inputs through the framer. | |
1531 TestSpdyVisitor visitor(spdy_version_); | |
1532 visitor.use_compression_ = true; | |
1533 const unsigned char* data; | |
1534 data = reinterpret_cast<const unsigned char*>(headers_frame->data()); | |
1535 for (size_t idx = 0; idx < headers_frame->size(); ++idx) { | |
1536 visitor.SimulateInFramer(data + idx, 1); | |
1537 ASSERT_EQ(0, visitor.error_count_); | |
1538 } | |
1539 data = reinterpret_cast<const unsigned char*>(send_frame->data()); | |
1540 for (size_t idx = 0; idx < send_frame->size(); ++idx) { | |
1541 visitor.SimulateInFramer(data + idx, 1); | |
1542 ASSERT_EQ(0, visitor.error_count_); | |
1543 } | |
1544 | |
1545 EXPECT_EQ(0, visitor.error_count_); | |
1546 EXPECT_EQ(0, visitor.syn_frame_count_); | |
1547 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
1548 EXPECT_EQ(1, visitor.headers_frame_count_); | |
1549 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); | |
1550 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1551 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1552 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
1553 EXPECT_EQ(1, visitor.data_frame_count_); | |
1554 } | |
1555 | |
1556 TEST_P(SpdyFramerTest, WindowUpdateFrame) { | |
1557 SpdyFramer framer(spdy_version_); | |
1558 scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate( | |
1559 SpdyWindowUpdateIR(1, 0x12345678))); | |
1560 | |
1561 const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678"; | |
1562 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1563 0x80, spdy_version_ch_, 0x00, 0x09, | |
1564 0x00, 0x00, 0x00, 0x08, | |
1565 0x00, 0x00, 0x00, 0x01, | |
1566 0x12, 0x34, 0x56, 0x78 | |
1567 }; | |
1568 const unsigned char kV4FrameData[] = { | |
1569 0x00, 0x00, 0x04, 0x08, | |
1570 0x00, 0x00, 0x00, 0x00, | |
1571 0x01, 0x12, 0x34, 0x56, | |
1572 0x78 | |
1573 }; | |
1574 | |
1575 if (IsSpdy4()) { | |
1576 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1577 } else { | |
1578 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1579 } | |
1580 } | |
1581 | |
1582 TEST_P(SpdyFramerTest, CreateDataFrame) { | |
1583 SpdyFramer framer(spdy_version_); | |
1584 | |
1585 { | |
1586 const char kDescription[] = "'hello' data frame, no FIN"; | |
1587 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1588 0x00, 0x00, 0x00, 0x01, | |
1589 0x00, 0x00, 0x00, 0x05, | |
1590 'h', 'e', 'l', 'l', | |
1591 'o' | |
1592 }; | |
1593 const unsigned char kV4FrameData[] = { | |
1594 0x00, 0x00, 0x05, 0x00, | |
1595 0x00, 0x00, 0x00, 0x00, | |
1596 0x01, 'h', 'e', 'l', | |
1597 'l', 'o' | |
1598 }; | |
1599 const char bytes[] = "hello"; | |
1600 | |
1601 SpdyDataIR data_ir(1, StringPiece(bytes, strlen(bytes))); | |
1602 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1603 if (IsSpdy4()) { | |
1604 CompareFrame( | |
1605 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1606 } else { | |
1607 CompareFrame( | |
1608 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1609 } | |
1610 | |
1611 SpdyDataIR data_header_ir(1); | |
1612 data_header_ir.SetDataShallow(base::StringPiece(bytes, strlen(bytes))); | |
1613 frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField( | |
1614 data_header_ir)); | |
1615 CompareCharArraysWithHexError( | |
1616 kDescription, | |
1617 reinterpret_cast<const unsigned char*>(frame->data()), | |
1618 framer.GetDataFrameMinimumSize(), | |
1619 IsSpdy4() ? kV4FrameData : kV3FrameData, | |
1620 framer.GetDataFrameMinimumSize()); | |
1621 } | |
1622 | |
1623 { | |
1624 const char kDescription[] = "'hello' data frame with more padding, no FIN"; | |
1625 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1626 0x00, 0x00, 0x00, 0x01, | |
1627 0x00, 0x00, 0x00, 0x05, | |
1628 'h', 'e', 'l', 'l', | |
1629 'o' | |
1630 }; | |
1631 | |
1632 const unsigned char kV4FrameData[] = { | |
1633 0x00, 0x00, 0xfd, 0x00, // Length = 253. PADDED set. | |
1634 0x08, 0x00, 0x00, 0x00, | |
1635 0x01, 0xf7, // Pad length field. | |
1636 'h', 'e', 'l', 'l', // Data | |
1637 'o', | |
1638 // Padding of 247 0x00(s). | |
1639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1640 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1649 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1651 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1660 }; | |
1661 const char bytes[] = "hello"; | |
1662 | |
1663 SpdyDataIR data_ir(1, StringPiece(bytes, strlen(bytes))); | |
1664 // 247 zeros and the pad length field make the overall padding to be 248 | |
1665 // bytes. | |
1666 data_ir.set_padding_len(248); | |
1667 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1668 if (IsSpdy4()) { | |
1669 CompareFrame( | |
1670 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1671 } else { | |
1672 CompareFrame( | |
1673 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1674 } | |
1675 | |
1676 frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir)); | |
1677 CompareCharArraysWithHexError( | |
1678 kDescription, | |
1679 reinterpret_cast<const unsigned char*>(frame->data()), | |
1680 framer.GetDataFrameMinimumSize(), | |
1681 IsSpdy4() ? kV4FrameData : kV3FrameData, | |
1682 framer.GetDataFrameMinimumSize()); | |
1683 } | |
1684 | |
1685 { | |
1686 const char kDescription[] = "'hello' data frame with few padding, no FIN"; | |
1687 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1688 0x00, 0x00, 0x00, 0x01, | |
1689 0x00, 0x00, 0x00, 0x05, | |
1690 'h', 'e', 'l', 'l', | |
1691 'o' | |
1692 }; | |
1693 | |
1694 const unsigned char kV4FrameData[] = { | |
1695 0x00, 0x00, 0x0d, 0x00, // Length = 13. PADDED set. | |
1696 0x08, 0x00, 0x00, 0x00, | |
1697 0x01, 0x07, // Pad length field. | |
1698 'h', 'e', 'l', 'l', // Data | |
1699 'o', | |
1700 0x00, 0x00, 0x00, 0x00, // Padding | |
1701 0x00, 0x00, 0x00 | |
1702 }; | |
1703 const char bytes[] = "hello"; | |
1704 | |
1705 SpdyDataIR data_ir(1, StringPiece(bytes, strlen(bytes))); | |
1706 // 7 zeros and the pad length field make the overall padding to be 8 bytes. | |
1707 data_ir.set_padding_len(8); | |
1708 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1709 if (IsSpdy4()) { | |
1710 CompareFrame( | |
1711 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1712 } else { | |
1713 CompareFrame( | |
1714 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1715 } | |
1716 } | |
1717 | |
1718 { | |
1719 const char kDescription[] = | |
1720 "'hello' data frame with 1 byte padding, no FIN"; | |
1721 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1722 0x00, 0x00, 0x00, 0x01, | |
1723 0x00, 0x00, 0x00, 0x05, | |
1724 'h', 'e', 'l', 'l', | |
1725 'o' | |
1726 }; | |
1727 | |
1728 const unsigned char kV4FrameData[] = { | |
1729 0x00, 0x00, 0x06, 0x00, // Length = 6. PADDED set. | |
1730 0x08, 0x00, 0x00, 0x00, | |
1731 0x01, 0x00, // Pad length field. | |
1732 'h', 'e', 'l', 'l', // Data | |
1733 'o', | |
1734 }; | |
1735 const char bytes[] = "hello"; | |
1736 | |
1737 SpdyDataIR data_ir(1, StringPiece(bytes, strlen(bytes))); | |
1738 // The pad length field itself is used for the 1-byte padding and no padding | |
1739 // payload is needed. | |
1740 data_ir.set_padding_len(1); | |
1741 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1742 if (IsSpdy4()) { | |
1743 CompareFrame( | |
1744 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1745 } else { | |
1746 CompareFrame( | |
1747 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1748 } | |
1749 | |
1750 frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir)); | |
1751 CompareCharArraysWithHexError( | |
1752 kDescription, | |
1753 reinterpret_cast<const unsigned char*>(frame->data()), | |
1754 framer.GetDataFrameMinimumSize(), | |
1755 IsSpdy4() ? kV4FrameData : kV3FrameData, | |
1756 framer.GetDataFrameMinimumSize()); | |
1757 } | |
1758 | |
1759 { | |
1760 const char kDescription[] = "Data frame with negative data byte, no FIN"; | |
1761 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1762 0x00, 0x00, 0x00, 0x01, | |
1763 0x00, 0x00, 0x00, 0x01, | |
1764 0xff | |
1765 }; | |
1766 const unsigned char kV4FrameData[] = { | |
1767 0x00, 0x00, 0x01, 0x00, 0x00, | |
1768 0x00, 0x00, 0x00, 0x01, | |
1769 0xff | |
1770 }; | |
1771 SpdyDataIR data_ir(1, StringPiece("\xff", 1)); | |
1772 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1773 if (IsSpdy4()) { | |
1774 CompareFrame( | |
1775 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1776 } else { | |
1777 CompareFrame( | |
1778 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1779 } | |
1780 } | |
1781 | |
1782 { | |
1783 const char kDescription[] = "'hello' data frame, with FIN"; | |
1784 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1785 0x00, 0x00, 0x00, 0x01, | |
1786 0x01, 0x00, 0x00, 0x05, | |
1787 'h', 'e', 'l', 'l', | |
1788 'o' | |
1789 }; | |
1790 const unsigned char kV4FrameData[] = { | |
1791 0x00, 0x00, 0x05, 0x00, | |
1792 0x01, 0x00, 0x00, 0x00, | |
1793 0x01, 'h', 'e', 'l', | |
1794 'l', 'o' | |
1795 }; | |
1796 SpdyDataIR data_ir(1, StringPiece("hello", 5)); | |
1797 data_ir.set_fin(true); | |
1798 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1799 if (IsSpdy4()) { | |
1800 CompareFrame( | |
1801 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1802 } else { | |
1803 CompareFrame( | |
1804 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1805 } | |
1806 } | |
1807 | |
1808 { | |
1809 const char kDescription[] = "Empty data frame"; | |
1810 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1811 0x00, 0x00, 0x00, 0x01, | |
1812 0x00, 0x00, 0x00, 0x00, | |
1813 }; | |
1814 const unsigned char kV4FrameData[] = { | |
1815 0x00, 0x00, 0x00, 0x00, | |
1816 0x00, 0x00, 0x00, 0x00, | |
1817 0x01, | |
1818 }; | |
1819 SpdyDataIR data_ir(1, StringPiece()); | |
1820 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1821 if (IsSpdy4()) { | |
1822 CompareFrame( | |
1823 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1824 } else { | |
1825 CompareFrame( | |
1826 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1827 } | |
1828 | |
1829 frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir)); | |
1830 CompareCharArraysWithHexError( | |
1831 kDescription, | |
1832 reinterpret_cast<const unsigned char*>(frame->data()), | |
1833 framer.GetDataFrameMinimumSize(), | |
1834 IsSpdy4() ? kV4FrameData : kV3FrameData, | |
1835 framer.GetDataFrameMinimumSize()); | |
1836 } | |
1837 | |
1838 { | |
1839 const char kDescription[] = "Data frame with max stream ID"; | |
1840 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
1841 0x7f, 0xff, 0xff, 0xff, | |
1842 0x01, 0x00, 0x00, 0x05, | |
1843 'h', 'e', 'l', 'l', | |
1844 'o' | |
1845 }; | |
1846 const unsigned char kV4FrameData[] = { | |
1847 0x00, 0x00, 0x05, 0x00, | |
1848 0x01, 0x7f, 0xff, 0xff, | |
1849 0xff, 'h', 'e', 'l', | |
1850 'l', 'o' | |
1851 }; | |
1852 SpdyDataIR data_ir(0x7fffffff, "hello"); | |
1853 data_ir.set_fin(true); | |
1854 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1855 if (IsSpdy4()) { | |
1856 CompareFrame( | |
1857 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
1858 } else { | |
1859 CompareFrame( | |
1860 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1861 } | |
1862 } | |
1863 | |
1864 if (!IsSpdy4()) { | |
1865 // This test does not apply to SPDY 4 because the max frame size is smaller | |
1866 // than 4MB. | |
1867 const char kDescription[] = "Large data frame"; | |
1868 const int kDataSize = 4 * 1024 * 1024; // 4 MB | |
1869 const string kData(kDataSize, 'A'); | |
1870 const unsigned char kFrameHeader[] = { | |
1871 0x00, 0x00, 0x00, 0x01, | |
1872 0x01, 0x40, 0x00, 0x00, | |
1873 }; | |
1874 | |
1875 const int kFrameSize = arraysize(kFrameHeader) + kDataSize; | |
1876 scoped_ptr<unsigned char[]> expected_frame_data( | |
1877 new unsigned char[kFrameSize]); | |
1878 memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader)); | |
1879 memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize); | |
1880 | |
1881 SpdyDataIR data_ir(1, StringPiece(kData.data(), kData.size())); | |
1882 data_ir.set_fin(true); | |
1883 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
1884 CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize); | |
1885 } | |
1886 } | |
1887 | |
1888 TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) { | |
1889 if (!IsSpdy2() && !IsSpdy3()) { | |
1890 // SYN_STREAM unsupported in SPDY>3 | |
1891 return; | |
1892 } | |
1893 SpdyFramer framer(spdy_version_); | |
1894 framer.set_enable_compression(false); | |
1895 | |
1896 { | |
1897 const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN"; | |
1898 | |
1899 const unsigned char kPri = IsSpdy2() ? 0xC0 : 0xE0; | |
1900 const unsigned char kV2FrameData[] = { | |
1901 0x80, spdy_version_ch_, 0x00, 0x01, | |
1902 0x00, 0x00, 0x00, 0x20, | |
1903 0x00, 0x00, 0x00, 0x01, | |
1904 0x00, 0x00, 0x00, 0x00, | |
1905 kPri, 0x00, 0x00, 0x02, | |
1906 0x00, 0x03, 'b', 'a', | |
1907 'r', 0x00, 0x03, 'f', | |
1908 'o', 'o', 0x00, 0x03, | |
1909 'f', 'o', 'o', 0x00, | |
1910 0x03, 'b', 'a', 'r' | |
1911 }; | |
1912 const unsigned char kV3FrameData[] = { | |
1913 0x80, spdy_version_ch_, 0x00, 0x01, | |
1914 0x00, 0x00, 0x00, 0x2a, | |
1915 0x00, 0x00, 0x00, 0x01, | |
1916 0x00, 0x00, 0x00, 0x00, | |
1917 kPri, 0x00, 0x00, 0x00, | |
1918 0x00, 0x02, 0x00, 0x00, | |
1919 0x00, 0x03, 'b', 'a', | |
1920 'r', 0x00, 0x00, 0x00, | |
1921 0x03, 'f', 'o', 'o', | |
1922 0x00, 0x00, 0x00, 0x03, | |
1923 'f', 'o', 'o', 0x00, | |
1924 0x00, 0x00, 0x03, 'b', | |
1925 'a', 'r' | |
1926 }; | |
1927 SpdySynStreamIR syn_stream(1); | |
1928 syn_stream.set_priority(framer.GetLowestPriority()); | |
1929 syn_stream.SetHeader("bar", "foo"); | |
1930 syn_stream.SetHeader("foo", "bar"); | |
1931 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); | |
1932 if (IsSpdy2()) { | |
1933 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
1934 } else if (IsSpdy3()) { | |
1935 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1936 } else { | |
1937 LOG(FATAL) << "Unsupported version in test."; | |
1938 } | |
1939 } | |
1940 | |
1941 { | |
1942 const char kDescription[] = | |
1943 "SYN_STREAM frame with a 0-length header name, highest pri, FIN, " | |
1944 "max stream ID"; | |
1945 | |
1946 const unsigned char kV2FrameData[] = { | |
1947 0x80, spdy_version_ch_, 0x00, 0x01, | |
1948 0x01, 0x00, 0x00, 0x1D, | |
1949 0x7f, 0xff, 0xff, 0xff, | |
1950 0x7f, 0xff, 0xff, 0xff, | |
1951 0x00, 0x00, 0x00, 0x02, | |
1952 0x00, 0x00, 0x00, 0x03, | |
1953 'f', 'o', 'o', 0x00, | |
1954 0x03, 'f', 'o', 'o', | |
1955 0x00, 0x03, 'b', 'a', | |
1956 'r' | |
1957 }; | |
1958 const unsigned char kV3FrameData[] = { | |
1959 0x80, spdy_version_ch_, 0x00, 0x01, | |
1960 0x01, 0x00, 0x00, 0x27, | |
1961 0x7f, 0xff, 0xff, 0xff, | |
1962 0x7f, 0xff, 0xff, 0xff, | |
1963 0x00, 0x00, 0x00, 0x00, | |
1964 0x00, 0x02, 0x00, 0x00, | |
1965 0x00, 0x00, 0x00, 0x00, | |
1966 0x00, 0x03, 'f', 'o', | |
1967 'o', 0x00, 0x00, 0x00, | |
1968 0x03, 'f', 'o', 'o', | |
1969 0x00, 0x00, 0x00, 0x03, | |
1970 'b', 'a', 'r' | |
1971 }; | |
1972 SpdySynStreamIR syn_stream(0x7fffffff); | |
1973 syn_stream.set_associated_to_stream_id(0x7fffffff); | |
1974 syn_stream.set_priority(framer.GetHighestPriority()); | |
1975 syn_stream.set_fin(true); | |
1976 syn_stream.SetHeader("", "foo"); | |
1977 syn_stream.SetHeader("foo", "bar"); | |
1978 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); | |
1979 if (IsSpdy2()) { | |
1980 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
1981 } else if (IsSpdy3()) { | |
1982 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
1983 } else { | |
1984 LOG(FATAL) << "Unsupported version in test."; | |
1985 } | |
1986 } | |
1987 | |
1988 { | |
1989 const char kDescription[] = | |
1990 "SYN_STREAM frame with a 0-length header val, high pri, FIN, " | |
1991 "max stream ID"; | |
1992 | |
1993 const unsigned char kPri = IsSpdy2() ? 0x40 : 0x20; | |
1994 const unsigned char kV2FrameData[] = { | |
1995 0x80, spdy_version_ch_, 0x00, 0x01, | |
1996 0x01, 0x00, 0x00, 0x1D, | |
1997 0x7f, 0xff, 0xff, 0xff, | |
1998 0x7f, 0xff, 0xff, 0xff, | |
1999 kPri, 0x00, 0x00, 0x02, | |
2000 0x00, 0x03, 'b', 'a', | |
2001 'r', 0x00, 0x03, 'f', | |
2002 'o', 'o', 0x00, 0x03, | |
2003 'f', 'o', 'o', 0x00, | |
2004 0x00 | |
2005 }; | |
2006 const unsigned char kV3FrameData[] = { | |
2007 0x80, spdy_version_ch_, 0x00, 0x01, | |
2008 0x01, 0x00, 0x00, 0x27, | |
2009 0x7f, 0xff, 0xff, 0xff, | |
2010 0x7f, 0xff, 0xff, 0xff, | |
2011 kPri, 0x00, 0x00, 0x00, | |
2012 0x00, 0x02, 0x00, 0x00, | |
2013 0x00, 0x03, 'b', 'a', | |
2014 'r', 0x00, 0x00, 0x00, | |
2015 0x03, 'f', 'o', 'o', | |
2016 0x00, 0x00, 0x00, 0x03, | |
2017 'f', 'o', 'o', 0x00, | |
2018 0x00, 0x00, 0x00 | |
2019 }; | |
2020 SpdySynStreamIR syn_stream(0x7fffffff); | |
2021 syn_stream.set_associated_to_stream_id(0x7fffffff); | |
2022 syn_stream.set_priority(1); | |
2023 syn_stream.set_fin(true); | |
2024 syn_stream.SetHeader("bar", "foo"); | |
2025 syn_stream.SetHeader("foo", ""); | |
2026 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); | |
2027 if (IsSpdy2()) { | |
2028 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2029 } else if (IsSpdy3()) { | |
2030 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2031 } else { | |
2032 LOG(FATAL) << "Unsupported version in test."; | |
2033 } | |
2034 } | |
2035 } | |
2036 | |
2037 // TODO(phajdan.jr): Clean up after we no longer need | |
2038 // to workaround http://crbug.com/139744. | |
2039 #if !defined(USE_SYSTEM_ZLIB) | |
2040 TEST_P(SpdyFramerTest, CreateSynStreamCompressed) { | |
2041 if (!IsSpdy2() && !IsSpdy3()) { | |
2042 // SYN_STREAM not supported for SPDY>3 | |
2043 return; | |
2044 } | |
2045 SpdyFramer framer(spdy_version_); | |
2046 framer.set_enable_compression(true); | |
2047 | |
2048 { | |
2049 const char kDescription[] = | |
2050 "SYN_STREAM frame, low pri, no FIN"; | |
2051 const SpdyPriority priority = IsSpdy2() ? 2 : 4; | |
2052 | |
2053 const unsigned char kV2FrameData[] = { | |
2054 0x80, spdy_version_ch_, 0x00, 0x01, | |
2055 0x00, 0x00, 0x00, 0x36, | |
2056 0x00, 0x00, 0x00, 0x01, | |
2057 0x00, 0x00, 0x00, 0x00, | |
2058 0x80, 0x00, 0x38, 0xea, | |
2059 0xdf, 0xa2, 0x51, 0xb2, | |
2060 0x62, 0x60, 0x62, 0x60, | |
2061 0x4e, 0x4a, 0x2c, 0x62, | |
2062 0x60, 0x06, 0x08, 0xa0, | |
2063 0xb4, 0xfc, 0x7c, 0x80, | |
2064 0x00, 0x62, 0x60, 0x4e, | |
2065 0xcb, 0xcf, 0x67, 0x60, | |
2066 0x06, 0x08, 0xa0, 0xa4, | |
2067 0xc4, 0x22, 0x80, 0x00, | |
2068 0x02, 0x00, 0x00, 0x00, | |
2069 0xff, 0xff, | |
2070 }; | |
2071 const unsigned char kV3FrameData[] = { | |
2072 0x80, spdy_version_ch_, 0x00, 0x01, | |
2073 0x00, 0x00, 0x00, 0x37, | |
2074 0x00, 0x00, 0x00, 0x01, | |
2075 0x00, 0x00, 0x00, 0x00, | |
2076 0x80, 0x00, 0x38, 0xEA, | |
2077 0xE3, 0xC6, 0xA7, 0xC2, | |
2078 0x02, 0xE5, 0x0E, 0x50, | |
2079 0xC2, 0x4B, 0x4A, 0x04, | |
2080 0xE5, 0x0B, 0x66, 0x80, | |
2081 0x00, 0x4A, 0xCB, 0xCF, | |
2082 0x07, 0x08, 0x20, 0x10, | |
2083 0x95, 0x96, 0x9F, 0x0F, | |
2084 0xA2, 0x00, 0x02, 0x28, | |
2085 0x29, 0xB1, 0x08, 0x20, | |
2086 0x80, 0x00, 0x00, 0x00, | |
2087 0x00, 0xFF, 0xFF, | |
2088 }; | |
2089 const unsigned char kV2SIMDFrameData[] = { | |
2090 0x80, spdy_version_ch_, 0x00, 0x01, | |
2091 0x00, 0x00, 0x00, 0x33, | |
2092 0x00, 0x00, 0x00, 0x01, | |
2093 0x00, 0x00, 0x00, 0x00, | |
2094 0x80, 0x00, 0x38, 0xea, | |
2095 0xdf, 0xa2, 0x51, 0xb2, | |
2096 0x62, 0x60, 0x62, 0x60, | |
2097 0x4e, 0x4a, 0x2c, 0x62, | |
2098 0x60, 0x06, 0x08, 0xa0, | |
2099 0xb4, 0xfc, 0x7c, 0x80, | |
2100 0x00, 0x62, 0x60, 0x06, | |
2101 0x13, 0x00, 0x01, 0x94, | |
2102 0x94, 0x58, 0x04, 0x10, | |
2103 0x40, 0x00, 0x00, 0x00, | |
2104 0x00, 0xff, 0xff, | |
2105 }; | |
2106 const unsigned char kV3SIMDFrameData[] = { | |
2107 0x80, spdy_version_ch_, 0x00, 0x01, | |
2108 0x00, 0x00, 0x00, 0x32, | |
2109 0x00, 0x00, 0x00, 0x01, | |
2110 0x00, 0x00, 0x00, 0x00, | |
2111 0x80, 0x00, 0x38, 0xea, | |
2112 0xe3, 0xc6, 0xa7, 0xc2, | |
2113 0x02, 0xe5, 0x0e, 0x50, | |
2114 0xc2, 0x4b, 0x4a, 0x04, | |
2115 0xe5, 0x0b, 0x66, 0x80, | |
2116 0x00, 0x4a, 0xcb, 0xcf, | |
2117 0x07, 0x08, 0x20, 0x24, | |
2118 0x0a, 0x20, 0x80, 0x92, | |
2119 0x12, 0x8b, 0x00, 0x02, | |
2120 0x08, 0x00, 0x00, 0x00, | |
2121 0xff, 0xff, | |
2122 }; | |
2123 | |
2124 SpdySynStreamIR syn_stream(1); | |
2125 syn_stream.set_priority(priority); | |
2126 syn_stream.SetHeader("bar", "foo"); | |
2127 syn_stream.SetHeader("foo", "bar"); | |
2128 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); | |
2129 const unsigned char* frame_data = | |
2130 reinterpret_cast<const unsigned char*>(frame->data()); | |
2131 if (IsSpdy2()) { | |
2132 // Try comparing with SIMD version, if that fails, do a failing check | |
2133 // with pretty printing against non-SIMD version | |
2134 if (memcmp(frame_data, | |
2135 kV2SIMDFrameData, | |
2136 std::min(arraysize(kV2SIMDFrameData), frame->size())) != 0) { | |
2137 CompareCharArraysWithHexError(kDescription, | |
2138 frame_data, | |
2139 frame->size(), | |
2140 kV2FrameData, | |
2141 arraysize(kV2FrameData)); | |
2142 } | |
2143 } else if (IsSpdy3()) { | |
2144 if (memcmp(frame_data, | |
2145 kV3SIMDFrameData, | |
2146 std::min(arraysize(kV3SIMDFrameData), frame->size())) != 0) { | |
2147 CompareCharArraysWithHexError(kDescription, | |
2148 frame_data, | |
2149 frame->size(), | |
2150 kV3FrameData, | |
2151 arraysize(kV3FrameData)); | |
2152 } | |
2153 } else { | |
2154 LOG(FATAL) << "Unsupported version in test."; | |
2155 } | |
2156 } | |
2157 } | |
2158 #endif // !defined(USE_SYSTEM_ZLIB) | |
2159 | |
2160 TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) { | |
2161 if (spdy_version_ > SPDY3) { | |
2162 // SYN_REPLY unsupported in SPDY>3 | |
2163 return; | |
2164 } | |
2165 SpdyFramer framer(spdy_version_); | |
2166 framer.set_enable_compression(false); | |
2167 | |
2168 { | |
2169 const char kDescription[] = "SYN_REPLY frame, no FIN"; | |
2170 | |
2171 const unsigned char kV2FrameData[] = { | |
2172 0x80, spdy_version_ch_, 0x00, 0x02, | |
2173 0x00, 0x00, 0x00, 0x1C, | |
2174 0x00, 0x00, 0x00, 0x01, | |
2175 0x00, 0x00, 0x00, 0x02, | |
2176 0x00, 0x03, 'b', 'a', | |
2177 'r', 0x00, 0x03, 'f', | |
2178 'o', 'o', 0x00, 0x03, | |
2179 'f', 'o', 'o', 0x00, | |
2180 0x03, 'b', 'a', 'r' | |
2181 }; | |
2182 const unsigned char kV3FrameData[] = { | |
2183 0x80, spdy_version_ch_, 0x00, 0x02, | |
2184 0x00, 0x00, 0x00, 0x24, | |
2185 0x00, 0x00, 0x00, 0x01, | |
2186 0x00, 0x00, 0x00, 0x02, | |
2187 0x00, 0x00, 0x00, 0x03, | |
2188 'b', 'a', 'r', 0x00, | |
2189 0x00, 0x00, 0x03, 'f', | |
2190 'o', 'o', 0x00, 0x00, | |
2191 0x00, 0x03, 'f', 'o', | |
2192 'o', 0x00, 0x00, 0x00, | |
2193 0x03, 'b', 'a', 'r' | |
2194 }; | |
2195 SpdySynReplyIR syn_reply(1); | |
2196 syn_reply.SetHeader("bar", "foo"); | |
2197 syn_reply.SetHeader("foo", "bar"); | |
2198 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply)); | |
2199 if (IsSpdy2()) { | |
2200 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2201 } else if (IsSpdy3()) { | |
2202 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2203 } else { | |
2204 LOG(FATAL) << "Unsupported version in test."; | |
2205 } | |
2206 } | |
2207 | |
2208 { | |
2209 const char kDescription[] = | |
2210 "SYN_REPLY frame with a 0-length header name, FIN, max stream ID"; | |
2211 | |
2212 const unsigned char kV2FrameData[] = { | |
2213 0x80, spdy_version_ch_, 0x00, 0x02, | |
2214 0x01, 0x00, 0x00, 0x19, | |
2215 0x7f, 0xff, 0xff, 0xff, | |
2216 0x00, 0x00, 0x00, 0x02, | |
2217 0x00, 0x00, 0x00, 0x03, | |
2218 'f', 'o', 'o', 0x00, | |
2219 0x03, 'f', 'o', 'o', | |
2220 0x00, 0x03, 'b', 'a', | |
2221 'r' | |
2222 }; | |
2223 const unsigned char kV3FrameData[] = { | |
2224 0x80, spdy_version_ch_, 0x00, 0x02, | |
2225 0x01, 0x00, 0x00, 0x21, | |
2226 0x7f, 0xff, 0xff, 0xff, | |
2227 0x00, 0x00, 0x00, 0x02, | |
2228 0x00, 0x00, 0x00, 0x00, | |
2229 0x00, 0x00, 0x00, 0x03, | |
2230 'f', 'o', 'o', 0x00, | |
2231 0x00, 0x00, 0x03, 'f', | |
2232 'o', 'o', 0x00, 0x00, | |
2233 0x00, 0x03, 'b', 'a', | |
2234 'r' | |
2235 }; | |
2236 SpdySynReplyIR syn_reply(0x7fffffff); | |
2237 syn_reply.set_fin(true); | |
2238 syn_reply.SetHeader("", "foo"); | |
2239 syn_reply.SetHeader("foo", "bar"); | |
2240 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply)); | |
2241 if (IsSpdy2()) { | |
2242 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2243 } else if (IsSpdy3()) { | |
2244 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2245 } else { | |
2246 LOG(FATAL) << "Unsupported version in test."; | |
2247 } | |
2248 } | |
2249 | |
2250 { | |
2251 const char kDescription[] = | |
2252 "SYN_REPLY frame with a 0-length header val, FIN, max stream ID"; | |
2253 | |
2254 const unsigned char kV2FrameData[] = { | |
2255 0x80, spdy_version_ch_, 0x00, 0x02, | |
2256 0x01, 0x00, 0x00, 0x19, | |
2257 0x7f, 0xff, 0xff, 0xff, | |
2258 0x00, 0x00, 0x00, 0x02, | |
2259 0x00, 0x03, 'b', 'a', | |
2260 'r', 0x00, 0x03, 'f', | |
2261 'o', 'o', 0x00, 0x03, | |
2262 'f', 'o', 'o', 0x00, | |
2263 0x00 | |
2264 }; | |
2265 const unsigned char kV3FrameData[] = { | |
2266 0x80, spdy_version_ch_, 0x00, 0x02, | |
2267 0x01, 0x00, 0x00, 0x21, | |
2268 0x7f, 0xff, 0xff, 0xff, | |
2269 0x00, 0x00, 0x00, 0x02, | |
2270 0x00, 0x00, 0x00, 0x03, | |
2271 'b', 'a', 'r', 0x00, | |
2272 0x00, 0x00, 0x03, 'f', | |
2273 'o', 'o', 0x00, 0x00, | |
2274 0x00, 0x03, 'f', 'o', | |
2275 'o', 0x00, 0x00, 0x00, | |
2276 0x00 | |
2277 }; | |
2278 SpdySynReplyIR syn_reply(0x7fffffff); | |
2279 syn_reply.set_fin(true); | |
2280 syn_reply.SetHeader("bar", "foo"); | |
2281 syn_reply.SetHeader("foo", ""); | |
2282 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply)); | |
2283 if (IsSpdy2()) { | |
2284 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2285 } else if (IsSpdy3()) { | |
2286 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2287 } else { | |
2288 LOG(FATAL) << "Unsupported version in test."; | |
2289 } | |
2290 } | |
2291 } | |
2292 | |
2293 // TODO(phajdan.jr): Clean up after we no longer need | |
2294 // to workaround http://crbug.com/139744. | |
2295 #if !defined(USE_SYSTEM_ZLIB) | |
2296 TEST_P(SpdyFramerTest, CreateSynReplyCompressed) { | |
2297 if (spdy_version_ > SPDY3) { | |
2298 // SYN_REPLY unsupported in SPDY>3 | |
2299 return; | |
2300 } | |
2301 SpdyFramer framer(spdy_version_); | |
2302 framer.set_enable_compression(true); | |
2303 | |
2304 { | |
2305 const char kDescription[] = "SYN_REPLY frame, no FIN"; | |
2306 | |
2307 const unsigned char kV2FrameData[] = { | |
2308 0x80, spdy_version_ch_, 0x00, 0x02, | |
2309 0x00, 0x00, 0x00, 0x32, | |
2310 0x00, 0x00, 0x00, 0x01, | |
2311 0x00, 0x00, 0x38, 0xea, | |
2312 0xdf, 0xa2, 0x51, 0xb2, | |
2313 0x62, 0x60, 0x62, 0x60, | |
2314 0x4e, 0x4a, 0x2c, 0x62, | |
2315 0x60, 0x06, 0x08, 0xa0, | |
2316 0xb4, 0xfc, 0x7c, 0x80, | |
2317 0x00, 0x62, 0x60, 0x4e, | |
2318 0xcb, 0xcf, 0x67, 0x60, | |
2319 0x06, 0x08, 0xa0, 0xa4, | |
2320 0xc4, 0x22, 0x80, 0x00, | |
2321 0x02, 0x00, 0x00, 0x00, | |
2322 0xff, 0xff, | |
2323 }; | |
2324 const unsigned char kV3FrameData[] = { | |
2325 0x80, spdy_version_ch_, 0x00, 0x02, | |
2326 0x00, 0x00, 0x00, 0x31, | |
2327 0x00, 0x00, 0x00, 0x01, | |
2328 0x38, 0xea, 0xe3, 0xc6, | |
2329 0xa7, 0xc2, 0x02, 0xe5, | |
2330 0x0e, 0x50, 0xc2, 0x4b, | |
2331 0x4a, 0x04, 0xe5, 0x0b, | |
2332 0x66, 0x80, 0x00, 0x4a, | |
2333 0xcb, 0xcf, 0x07, 0x08, | |
2334 0x20, 0x10, 0x95, 0x96, | |
2335 0x9f, 0x0f, 0xa2, 0x00, | |
2336 0x02, 0x28, 0x29, 0xb1, | |
2337 0x08, 0x20, 0x80, 0x00, | |
2338 0x00, 0x00, 0x00, 0xff, | |
2339 0xff, | |
2340 }; | |
2341 const unsigned char kV2SIMDFrameData[] = { | |
2342 0x80, spdy_version_ch_, 0x00, 0x02, | |
2343 0x00, 0x00, 0x00, 0x2f, | |
2344 0x00, 0x00, 0x00, 0x01, | |
2345 0x00, 0x00, 0x38, 0xea, | |
2346 0xdf, 0xa2, 0x51, 0xb2, | |
2347 0x62, 0x60, 0x62, 0x60, | |
2348 0x4e, 0x4a, 0x2c, 0x62, | |
2349 0x60, 0x06, 0x08, 0xa0, | |
2350 0xb4, 0xfc, 0x7c, 0x80, | |
2351 0x00, 0x62, 0x60, 0x06, | |
2352 0x13, 0x00, 0x01, 0x94, | |
2353 0x94, 0x58, 0x04, 0x10, | |
2354 0x40, 0x00, 0x00, 0x00, | |
2355 0x00, 0xff, 0xff, | |
2356 }; | |
2357 const unsigned char kV3SIMDFrameData[] = { | |
2358 0x80, spdy_version_ch_, 0x00, 0x02, | |
2359 0x00, 0x00, 0x00, 0x2c, | |
2360 0x00, 0x00, 0x00, 0x01, | |
2361 0x38, 0xea, 0xe3, 0xc6, | |
2362 0xa7, 0xc2, 0x02, 0xe5, | |
2363 0x0e, 0x50, 0xc2, 0x4b, | |
2364 0x4a, 0x04, 0xe5, 0x0b, | |
2365 0x66, 0x80, 0x00, 0x4a, | |
2366 0xcb, 0xcf, 0x07, 0x08, | |
2367 0x20, 0x24, 0x0a, 0x20, | |
2368 0x80, 0x92, 0x12, 0x8b, | |
2369 0x00, 0x02, 0x08, 0x00, | |
2370 0x00, 0x00, 0xff, 0xff, | |
2371 }; | |
2372 | |
2373 SpdySynReplyIR syn_reply(1); | |
2374 syn_reply.SetHeader("bar", "foo"); | |
2375 syn_reply.SetHeader("foo", "bar"); | |
2376 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply)); | |
2377 const unsigned char* frame_data = | |
2378 reinterpret_cast<const unsigned char*>(frame->data()); | |
2379 if (IsSpdy2()) { | |
2380 // Try comparing with SIMD version, if that fails, do a failing check | |
2381 // with pretty printing against non-SIMD version | |
2382 if (memcmp(frame_data, | |
2383 kV2SIMDFrameData, | |
2384 std::min(arraysize(kV2SIMDFrameData), frame->size())) != 0) { | |
2385 CompareCharArraysWithHexError(kDescription, | |
2386 frame_data, | |
2387 frame->size(), | |
2388 kV2FrameData, | |
2389 arraysize(kV2FrameData)); | |
2390 } | |
2391 } else if (IsSpdy3()) { | |
2392 if (memcmp(frame_data, | |
2393 kV3SIMDFrameData, | |
2394 std::min(arraysize(kV3SIMDFrameData), frame->size())) != 0) { | |
2395 CompareCharArraysWithHexError(kDescription, | |
2396 frame_data, | |
2397 frame->size(), | |
2398 kV3FrameData, | |
2399 arraysize(kV3FrameData)); | |
2400 } | |
2401 } else { | |
2402 LOG(FATAL) << "Unsupported version in test."; | |
2403 } | |
2404 } | |
2405 } | |
2406 #endif // !defined(USE_SYSTEM_ZLIB) | |
2407 | |
2408 TEST_P(SpdyFramerTest, CreateRstStream) { | |
2409 SpdyFramer framer(spdy_version_); | |
2410 | |
2411 { | |
2412 const char kDescription[] = "RST_STREAM frame"; | |
2413 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
2414 0x80, spdy_version_ch_, 0x00, 0x03, | |
2415 0x00, 0x00, 0x00, 0x08, | |
2416 0x00, 0x00, 0x00, 0x01, | |
2417 0x00, 0x00, 0x00, 0x01, | |
2418 }; | |
2419 const unsigned char kV4FrameData[] = { | |
2420 0x00, 0x00, 0x07, 0x03, | |
2421 0x00, 0x00, 0x00, 0x00, | |
2422 0x01, 0x00, 0x00, 0x00, | |
2423 0x01, 0x52, 0x53, 0x54 | |
2424 }; | |
2425 SpdyRstStreamIR rst_stream(1, RST_STREAM_PROTOCOL_ERROR, "RST"); | |
2426 scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream)); | |
2427 if (IsSpdy4()) { | |
2428 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2429 } else { | |
2430 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2431 } | |
2432 } | |
2433 | |
2434 { | |
2435 const char kDescription[] = "RST_STREAM frame with max stream ID"; | |
2436 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
2437 0x80, spdy_version_ch_, 0x00, 0x03, | |
2438 0x00, 0x00, 0x00, 0x08, | |
2439 0x7f, 0xff, 0xff, 0xff, | |
2440 0x00, 0x00, 0x00, 0x01, | |
2441 }; | |
2442 const unsigned char kV4FrameData[] = { | |
2443 0x00, 0x00, 0x04, 0x03, | |
2444 0x00, 0x7f, 0xff, 0xff, | |
2445 0xff, 0x00, 0x00, 0x00, | |
2446 0x01, | |
2447 }; | |
2448 SpdyRstStreamIR rst_stream(0x7FFFFFFF, | |
2449 RST_STREAM_PROTOCOL_ERROR, | |
2450 ""); | |
2451 scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream)); | |
2452 if (IsSpdy4()) { | |
2453 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2454 } else { | |
2455 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2456 } | |
2457 } | |
2458 | |
2459 { | |
2460 const char kDescription[] = "RST_STREAM frame with max status code"; | |
2461 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
2462 0x80, spdy_version_ch_, 0x00, 0x03, | |
2463 0x00, 0x00, 0x00, 0x08, | |
2464 0x7f, 0xff, 0xff, 0xff, | |
2465 0x00, 0x00, 0x00, 0x06, | |
2466 }; | |
2467 const unsigned char kV4FrameData[] = { | |
2468 0x00, 0x00, 0x04, 0x03, | |
2469 0x00, 0x7f, 0xff, 0xff, | |
2470 0xff, 0x00, 0x00, 0x00, | |
2471 0x02, | |
2472 }; | |
2473 SpdyRstStreamIR rst_stream(0x7FFFFFFF, | |
2474 RST_STREAM_INTERNAL_ERROR, | |
2475 ""); | |
2476 scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream)); | |
2477 if (IsSpdy4()) { | |
2478 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2479 } else { | |
2480 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2481 } | |
2482 } | |
2483 } | |
2484 | |
2485 TEST_P(SpdyFramerTest, CreateSettings) { | |
2486 SpdyFramer framer(spdy_version_); | |
2487 | |
2488 { | |
2489 const char kDescription[] = "Network byte order SETTINGS frame"; | |
2490 | |
2491 const unsigned char kV2FrameData[] = { | |
2492 0x80, spdy_version_ch_, 0x00, 0x04, | |
2493 0x00, 0x00, 0x00, 0x0c, | |
2494 0x00, 0x00, 0x00, 0x01, | |
2495 0x07, 0x00, 0x00, 0x01, | |
2496 0x0a, 0x0b, 0x0c, 0x0d, | |
2497 }; | |
2498 const unsigned char kV3FrameData[] = { | |
2499 0x80, spdy_version_ch_, 0x00, 0x04, | |
2500 0x00, 0x00, 0x00, 0x0c, | |
2501 0x00, 0x00, 0x00, 0x01, | |
2502 0x01, 0x00, 0x00, 0x07, | |
2503 0x0a, 0x0b, 0x0c, 0x0d, | |
2504 }; | |
2505 const unsigned char kV4FrameData[] = { | |
2506 0x00, 0x00, 0x06, 0x04, | |
2507 0x00, 0x00, 0x00, 0x00, | |
2508 0x00, 0x00, 0x04, 0x0a, | |
2509 0x0b, 0x0c, 0x0d, | |
2510 }; | |
2511 | |
2512 uint32 kValue = 0x0a0b0c0d; | |
2513 SpdySettingsIR settings_ir; | |
2514 | |
2515 SpdySettingsFlags kFlags = static_cast<SpdySettingsFlags>(0x01); | |
2516 SpdySettingsIds kId = SETTINGS_INITIAL_WINDOW_SIZE; | |
2517 SettingsMap settings; | |
2518 settings[kId] = SettingsFlagsAndValue(kFlags, kValue); | |
2519 EXPECT_EQ(kFlags, settings[kId].first); | |
2520 EXPECT_EQ(kValue, settings[kId].second); | |
2521 settings_ir.AddSetting(kId, | |
2522 kFlags & SETTINGS_FLAG_PLEASE_PERSIST, | |
2523 kFlags & SETTINGS_FLAG_PERSISTED, | |
2524 kValue); | |
2525 | |
2526 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir)); | |
2527 if (IsSpdy2()) { | |
2528 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2529 } else if (IsSpdy3()) { | |
2530 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2531 } else { | |
2532 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2533 } | |
2534 } | |
2535 | |
2536 { | |
2537 const char kDescription[] = "Basic SETTINGS frame"; | |
2538 | |
2539 const unsigned char kV2FrameData[] = { | |
2540 0x80, spdy_version_ch_, 0x00, 0x04, | |
2541 0x00, 0x00, 0x00, 0x24, | |
2542 0x00, 0x00, 0x00, 0x04, | |
2543 0x01, 0x00, 0x00, 0x00, // 1st Setting | |
2544 0x00, 0x00, 0x00, 0x05, | |
2545 0x02, 0x00, 0x00, 0x00, // 2nd Setting | |
2546 0x00, 0x00, 0x00, 0x06, | |
2547 0x03, 0x00, 0x00, 0x00, // 3rd Setting | |
2548 0x00, 0x00, 0x00, 0x07, | |
2549 0x04, 0x00, 0x00, 0x00, // 4th Setting | |
2550 0x00, 0x00, 0x00, 0x08, | |
2551 }; | |
2552 const unsigned char kV3FrameData[] = { | |
2553 0x80, spdy_version_ch_, 0x00, 0x04, | |
2554 0x00, 0x00, 0x00, 0x24, | |
2555 0x00, 0x00, 0x00, 0x04, | |
2556 0x00, 0x00, 0x00, 0x01, // 1st Setting | |
2557 0x00, 0x00, 0x00, 0x05, | |
2558 0x00, 0x00, 0x00, 0x02, // 2nd Setting | |
2559 0x00, 0x00, 0x00, 0x06, | |
2560 0x00, 0x00, 0x00, 0x03, // 3rd Setting | |
2561 0x00, 0x00, 0x00, 0x07, | |
2562 0x00, 0x00, 0x00, 0x04, // 4th Setting | |
2563 0x00, 0x00, 0x00, 0x08, | |
2564 }; | |
2565 // These end up seemingly out of order because of the way that our internal | |
2566 // ordering for settings_ir works. HTTP2 has no requirement on ordering on | |
2567 // the wire. | |
2568 const unsigned char kV4FrameData[] = { | |
2569 0x00, 0x00, 0x18, 0x04, | |
2570 0x00, 0x00, 0x00, 0x00, | |
2571 0x00, 0x00, 0x03, // 3rd Setting | |
2572 0x00, 0x00, 0x00, 0x07, | |
2573 0x00, 0x04, // 4th Setting | |
2574 0x00, 0x00, 0x00, 0x08, | |
2575 0x00, 0x01, // 1st Setting | |
2576 0x00, 0x00, 0x00, 0x05, | |
2577 0x00, 0x02, // 2nd Setting | |
2578 0x00, 0x00, 0x00, 0x06, | |
2579 }; | |
2580 | |
2581 SpdySettingsIR settings_ir; | |
2582 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 1), | |
2583 false, // persist | |
2584 false, // persisted | |
2585 5); | |
2586 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 2), | |
2587 false, // persist | |
2588 false, // persisted | |
2589 6); | |
2590 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 3), | |
2591 false, // persist | |
2592 false, // persisted | |
2593 7); | |
2594 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 4), | |
2595 false, // persist | |
2596 false, // persisted | |
2597 8); | |
2598 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir)); | |
2599 | |
2600 if (IsSpdy2()) { | |
2601 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2602 } else if (IsSpdy3()) { | |
2603 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2604 } else { | |
2605 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2606 } | |
2607 } | |
2608 | |
2609 { | |
2610 const char kDescription[] = "Empty SETTINGS frame"; | |
2611 | |
2612 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
2613 0x80, spdy_version_ch_, 0x00, 0x04, | |
2614 0x00, 0x00, 0x00, 0x04, | |
2615 0x00, 0x00, 0x00, 0x00, | |
2616 }; | |
2617 const unsigned char kV4FrameData[] = { | |
2618 0x00, 0x00, 0x00, 0x04, | |
2619 0x00, 0x00, 0x00, 0x00, | |
2620 0x00, | |
2621 }; | |
2622 SpdySettingsIR settings_ir; | |
2623 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir)); | |
2624 if (IsSpdy4()) { | |
2625 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2626 } else { | |
2627 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2628 } | |
2629 } | |
2630 } | |
2631 | |
2632 TEST_P(SpdyFramerTest, CreatePingFrame) { | |
2633 SpdyFramer framer(spdy_version_); | |
2634 | |
2635 { | |
2636 const char kDescription[] = "PING frame"; | |
2637 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
2638 0x80, spdy_version_ch_, 0x00, 0x06, | |
2639 0x00, 0x00, 0x00, 0x04, | |
2640 0x12, 0x34, 0x56, 0x78, | |
2641 }; | |
2642 const unsigned char kV4FrameData[] = { | |
2643 0x00, 0x00, 0x08, 0x06, | |
2644 0x00, 0x00, 0x00, 0x00, | |
2645 0x00, 0x12, 0x34, 0x56, | |
2646 0x78, 0x9a, 0xbc, 0xde, | |
2647 0xff, | |
2648 }; | |
2649 const unsigned char kV4FrameDataWithAck[] = { | |
2650 0x00, 0x00, 0x08, 0x06, | |
2651 0x01, 0x00, 0x00, 0x00, | |
2652 0x00, 0x12, 0x34, 0x56, | |
2653 0x78, 0x9a, 0xbc, 0xde, | |
2654 0xff, | |
2655 }; | |
2656 scoped_ptr<SpdyFrame> frame; | |
2657 if (IsSpdy4()) { | |
2658 const SpdyPingId kPingId = 0x123456789abcdeffULL; | |
2659 SpdyPingIR ping_ir(kPingId); | |
2660 // Tests SpdyPingIR when the ping is not an ack. | |
2661 ASSERT_FALSE(ping_ir.is_ack()); | |
2662 frame.reset(framer.SerializePing(ping_ir)); | |
2663 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2664 | |
2665 // Tests SpdyPingIR when the ping is an ack. | |
2666 ping_ir.set_is_ack(true); | |
2667 frame.reset(framer.SerializePing(ping_ir)); | |
2668 CompareFrame(kDescription, *frame, | |
2669 kV4FrameDataWithAck, arraysize(kV4FrameDataWithAck)); | |
2670 | |
2671 } else { | |
2672 frame.reset(framer.SerializePing(SpdyPingIR(0x12345678ull))); | |
2673 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2674 } | |
2675 } | |
2676 } | |
2677 | |
2678 TEST_P(SpdyFramerTest, CreateGoAway) { | |
2679 SpdyFramer framer(spdy_version_); | |
2680 | |
2681 { | |
2682 const char kDescription[] = "GOAWAY frame"; | |
2683 const unsigned char kV2FrameData[] = { | |
2684 0x80, spdy_version_ch_, 0x00, 0x07, | |
2685 0x00, 0x00, 0x00, 0x04, | |
2686 0x00, 0x00, 0x00, 0x00, // Stream Id | |
2687 }; | |
2688 const unsigned char kV3FrameData[] = { | |
2689 0x80, spdy_version_ch_, 0x00, 0x07, | |
2690 0x00, 0x00, 0x00, 0x08, | |
2691 0x00, 0x00, 0x00, 0x00, // Stream Id | |
2692 0x00, 0x00, 0x00, 0x00, // Status | |
2693 }; | |
2694 const unsigned char kV4FrameData[] = { | |
2695 0x00, 0x00, 0x0a, 0x07, | |
2696 0x00, 0x00, 0x00, 0x00, | |
2697 0x00, 0x00, 0x00, 0x00, // Stream id | |
2698 0x00, 0x00, 0x00, 0x00, // Status | |
2699 0x00, 0x47, 0x41, // Opaque Description | |
2700 }; | |
2701 SpdyGoAwayIR goaway_ir(0, GOAWAY_OK, "GA"); | |
2702 scoped_ptr<SpdyFrame> frame(framer.SerializeGoAway(goaway_ir)); | |
2703 if (IsSpdy2()) { | |
2704 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2705 } else if (IsSpdy3()) { | |
2706 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2707 } else { | |
2708 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2709 } | |
2710 } | |
2711 | |
2712 { | |
2713 const char kDescription[] = "GOAWAY frame with max stream ID, status"; | |
2714 const unsigned char kV2FrameData[] = { | |
2715 0x80, spdy_version_ch_, 0x00, 0x07, | |
2716 0x00, 0x00, 0x00, 0x04, | |
2717 0x7f, 0xff, 0xff, 0xff, // Stream Id | |
2718 }; | |
2719 const unsigned char kV3FrameData[] = { | |
2720 0x80, spdy_version_ch_, 0x00, 0x07, | |
2721 0x00, 0x00, 0x00, 0x08, | |
2722 0x7f, 0xff, 0xff, 0xff, // Stream Id | |
2723 0x00, 0x00, 0x00, 0x01, // Status: PROTOCOL_ERROR. | |
2724 }; | |
2725 const unsigned char kV4FrameData[] = { | |
2726 0x00, 0x00, 0x0a, 0x07, | |
2727 0x00, 0x00, 0x00, 0x00, | |
2728 0x00, 0x7f, 0xff, 0xff, // Stream Id | |
2729 0xff, 0x00, 0x00, 0x00, // Status: INTERNAL_ERROR. | |
2730 0x02, 0x47, 0x41, // Opaque Description | |
2731 }; | |
2732 SpdyGoAwayIR goaway_ir(0x7FFFFFFF, GOAWAY_INTERNAL_ERROR, "GA"); | |
2733 scoped_ptr<SpdyFrame> frame(framer.SerializeGoAway(goaway_ir)); | |
2734 if (IsSpdy2()) { | |
2735 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2736 } else if (IsSpdy3()) { | |
2737 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2738 } else { | |
2739 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2740 } | |
2741 } | |
2742 } | |
2743 | |
2744 TEST_P(SpdyFramerTest, CreateHeadersUncompressed) { | |
2745 SpdyFramer framer(spdy_version_); | |
2746 framer.set_enable_compression(false); | |
2747 | |
2748 { | |
2749 const char kDescription[] = "HEADERS frame, no FIN"; | |
2750 | |
2751 const unsigned char kV2FrameData[] = { | |
2752 0x80, spdy_version_ch_, 0x00, 0x08, | |
2753 0x00, 0x00, 0x00, 0x1C, | |
2754 0x00, 0x00, 0x00, 0x01, | |
2755 0x00, 0x00, 0x00, 0x02, | |
2756 0x00, 0x03, 'b', 'a', | |
2757 'r', 0x00, 0x03, 'f', | |
2758 'o', 'o', 0x00, 0x03, | |
2759 'f', 'o', 'o', 0x00, | |
2760 0x03, 'b', 'a', 'r' | |
2761 }; | |
2762 const unsigned char kV3FrameData[] = { | |
2763 0x80, spdy_version_ch_, 0x00, 0x08, | |
2764 0x00, 0x00, 0x00, 0x24, | |
2765 0x00, 0x00, 0x00, 0x01, | |
2766 0x00, 0x00, 0x00, 0x02, | |
2767 0x00, 0x00, 0x00, 0x03, | |
2768 'b', 'a', 'r', 0x00, | |
2769 0x00, 0x00, 0x03, 'f', | |
2770 'o', 'o', 0x00, 0x00, | |
2771 0x00, 0x03, 'f', 'o', | |
2772 'o', 0x00, 0x00, 0x00, | |
2773 0x03, 'b', 'a', 'r' | |
2774 }; | |
2775 const unsigned char kV4FrameData[] = { | |
2776 0x00, 0x00, 0x12, 0x01, // Headers: END_HEADERS | |
2777 0x04, 0x00, 0x00, 0x00, // Stream 1 | |
2778 0x01, 0x00, 0x03, 0x62, // @.ba | |
2779 0x61, 0x72, 0x03, 0x66, // r.fo | |
2780 0x6f, 0x6f, 0x00, 0x03, // o@.f | |
2781 0x66, 0x6f, 0x6f, 0x03, // oo.b | |
2782 0x62, 0x61, 0x72, // ar | |
2783 }; | |
2784 SpdyHeadersIR headers_ir(1); | |
2785 headers_ir.SetHeader("bar", "foo"); | |
2786 headers_ir.SetHeader("foo", "bar"); | |
2787 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); | |
2788 if (IsSpdy2()) { | |
2789 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2790 } else if (IsSpdy3()) { | |
2791 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2792 } else { | |
2793 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2794 } | |
2795 } | |
2796 | |
2797 { | |
2798 const char kDescription[] = | |
2799 "HEADERS frame with a 0-length header name, FIN, max stream ID"; | |
2800 | |
2801 const unsigned char kV2FrameData[] = { | |
2802 0x80, spdy_version_ch_, 0x00, 0x08, | |
2803 0x01, 0x00, 0x00, 0x19, | |
2804 0x7f, 0xff, 0xff, 0xff, | |
2805 0x00, 0x00, 0x00, 0x02, | |
2806 0x00, 0x00, 0x00, 0x03, | |
2807 'f', 'o', 'o', 0x00, | |
2808 0x03, 'f', 'o', 'o', | |
2809 0x00, 0x03, 'b', 'a', | |
2810 'r' | |
2811 }; | |
2812 const unsigned char kV3FrameData[] = { | |
2813 0x80, spdy_version_ch_, 0x00, 0x08, | |
2814 0x01, 0x00, 0x00, 0x21, | |
2815 0x7f, 0xff, 0xff, 0xff, | |
2816 0x00, 0x00, 0x00, 0x02, | |
2817 0x00, 0x00, 0x00, 0x00, | |
2818 0x00, 0x00, 0x00, 0x03, | |
2819 'f', 'o', 'o', 0x00, | |
2820 0x00, 0x00, 0x03, 'f', | |
2821 'o', 'o', 0x00, 0x00, | |
2822 0x00, 0x03, 'b', 'a', | |
2823 'r' | |
2824 }; | |
2825 const unsigned char kV4FrameData[] = { | |
2826 0x00, 0x00, 0x0f, 0x01, // Headers: FIN | END_HEADERS | |
2827 0x05, 0x7f, 0xff, 0xff, // Stream 0x7fffffff | |
2828 0xff, 0x00, 0x00, 0x03, // @.. | |
2829 0x66, 0x6f, 0x6f, 0x00, // foo@ | |
2830 0x03, 0x66, 0x6f, 0x6f, // .foo | |
2831 0x03, 0x62, 0x61, 0x72, // .bar | |
2832 }; | |
2833 SpdyHeadersIR headers_ir(0x7fffffff); | |
2834 headers_ir.set_fin(true); | |
2835 headers_ir.SetHeader("", "foo"); | |
2836 headers_ir.SetHeader("foo", "bar"); | |
2837 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); | |
2838 if (IsSpdy2()) { | |
2839 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2840 } else if (IsSpdy3()) { | |
2841 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2842 } else { | |
2843 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2844 } | |
2845 } | |
2846 | |
2847 { | |
2848 const char kDescription[] = | |
2849 "HEADERS frame with a 0-length header val, FIN, max stream ID"; | |
2850 | |
2851 const unsigned char kV2FrameData[] = { | |
2852 0x80, spdy_version_ch_, 0x00, 0x08, | |
2853 0x01, 0x00, 0x00, 0x19, | |
2854 0x7f, 0xff, 0xff, 0xff, | |
2855 0x00, 0x00, 0x00, 0x02, | |
2856 0x00, 0x03, 'b', 'a', | |
2857 'r', 0x00, 0x03, 'f', | |
2858 'o', 'o', 0x00, 0x03, | |
2859 'f', 'o', 'o', 0x00, | |
2860 0x00 | |
2861 }; | |
2862 const unsigned char kV3FrameData[] = { | |
2863 0x80, spdy_version_ch_, 0x00, 0x08, | |
2864 0x01, 0x00, 0x00, 0x21, | |
2865 0x7f, 0xff, 0xff, 0xff, | |
2866 0x00, 0x00, 0x00, 0x02, | |
2867 0x00, 0x00, 0x00, 0x03, | |
2868 'b', 'a', 'r', 0x00, | |
2869 0x00, 0x00, 0x03, 'f', | |
2870 'o', 'o', 0x00, 0x00, | |
2871 0x00, 0x03, 'f', 'o', | |
2872 'o', 0x00, 0x00, 0x00, | |
2873 0x00 | |
2874 }; | |
2875 const unsigned char kV4FrameData[] = { | |
2876 0x00, 0x00, 0x0f, 0x01, // Headers: FIN | END_HEADERS | |
2877 0x05, 0x7f, 0xff, 0xff, // Stream 0x7fffffff | |
2878 0xff, 0x00, 0x03, 0x62, // @.b | |
2879 0x61, 0x72, 0x03, 0x66, // ar.f | |
2880 0x6f, 0x6f, 0x00, 0x03, // oo@. | |
2881 0x66, 0x6f, 0x6f, 0x00, // foo. | |
2882 }; | |
2883 SpdyHeadersIR headers_ir(0x7fffffff); | |
2884 headers_ir.set_fin(true); | |
2885 headers_ir.SetHeader("bar", "foo"); | |
2886 headers_ir.SetHeader("foo", ""); | |
2887 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); | |
2888 if (IsSpdy2()) { | |
2889 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); | |
2890 } else if (IsSpdy3()) { | |
2891 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
2892 } else { | |
2893 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2894 } | |
2895 } | |
2896 | |
2897 { | |
2898 const char kDescription[] = | |
2899 "HEADERS frame with a 0-length header val, FIN, max stream ID, pri"; | |
2900 | |
2901 const unsigned char kV4FrameData[] = { | |
2902 0x00, 0x00, 0x14, 0x01, // Headers: FIN | END_HEADERS | PRIORITY | |
2903 0x25, 0x7f, 0xff, 0xff, // Stream 0x7fffffff | |
2904 0xff, 0x00, 0x00, 0x00, // parent stream | |
2905 0x00, 0xdb, // weight | |
2906 0x00, 0x03, 0x62, 0x61, // @.ba | |
2907 0x72, 0x03, 0x66, 0x6f, // r.fo | |
2908 0x6f, 0x00, 0x03, 0x66, // o@.f | |
2909 0x6f, 0x6f, 0x00, // oo. | |
2910 }; | |
2911 SpdyHeadersIR headers_ir(0x7fffffff); | |
2912 headers_ir.set_fin(true); | |
2913 headers_ir.set_priority(1); | |
2914 headers_ir.set_has_priority(true); | |
2915 headers_ir.SetHeader("bar", "foo"); | |
2916 headers_ir.SetHeader("foo", ""); | |
2917 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); | |
2918 if (IsSpdy2() || IsSpdy3()) { | |
2919 // HEADERS with priority not supported. | |
2920 } else { | |
2921 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2922 } | |
2923 } | |
2924 | |
2925 { | |
2926 const char kDescription[] = | |
2927 "HEADERS frame with a 0-length header name, FIN, max stream ID, padded"; | |
2928 | |
2929 const unsigned char kV4FrameData[] = { | |
2930 0x00, 0x00, 0x15, 0x01, // Headers | |
2931 0x0d, 0x7f, 0xff, 0xff, // FIN | END_HEADERS | PADDED, Stream | |
2932 // 0x7fffffff | |
2933 0xff, 0x05, 0x00, 0x00, // Pad length field | |
2934 0x03, 0x66, 0x6f, 0x6f, // .foo | |
2935 0x00, 0x03, 0x66, 0x6f, // @.fo | |
2936 0x6f, 0x03, 0x62, 0x61, // o.ba | |
2937 0x72, // r | |
2938 // Padding payload | |
2939 0x00, 0x00, 0x00, 0x00, 0x00, | |
2940 }; | |
2941 SpdyHeadersIR headers_ir(0x7fffffff); | |
2942 headers_ir.set_fin(true); | |
2943 headers_ir.SetHeader("", "foo"); | |
2944 headers_ir.SetHeader("foo", "bar"); | |
2945 headers_ir.set_padding_len(6); | |
2946 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); | |
2947 if (IsSpdy2() || IsSpdy3()) { | |
2948 // Padding is not supported. | |
2949 } else { | |
2950 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
2951 } | |
2952 } | |
2953 } | |
2954 | |
2955 // TODO(phajdan.jr): Clean up after we no longer need | |
2956 // to workaround http://crbug.com/139744. | |
2957 #if !defined(USE_SYSTEM_ZLIB) | |
2958 TEST_P(SpdyFramerTest, CreateHeadersCompressed) { | |
2959 SpdyFramer framer(spdy_version_); | |
2960 framer.set_enable_compression(true); | |
2961 | |
2962 { | |
2963 const char kDescription[] = "HEADERS frame, no FIN"; | |
2964 | |
2965 const unsigned char kV2FrameData[] = { | |
2966 0x80, spdy_version_ch_, 0x00, 0x08, | |
2967 0x00, 0x00, 0x00, 0x32, | |
2968 0x00, 0x00, 0x00, 0x01, | |
2969 0x00, 0x00, 0x38, 0xea, | |
2970 0xdf, 0xa2, 0x51, 0xb2, | |
2971 0x62, 0x60, 0x62, 0x60, | |
2972 0x4e, 0x4a, 0x2c, 0x62, | |
2973 0x60, 0x06, 0x08, 0xa0, | |
2974 0xb4, 0xfc, 0x7c, 0x80, | |
2975 0x00, 0x62, 0x60, 0x4e, | |
2976 0xcb, 0xcf, 0x67, 0x60, | |
2977 0x06, 0x08, 0xa0, 0xa4, | |
2978 0xc4, 0x22, 0x80, 0x00, | |
2979 0x02, 0x00, 0x00, 0x00, | |
2980 0xff, 0xff, | |
2981 }; | |
2982 const unsigned char kV3FrameData[] = { | |
2983 0x80, spdy_version_ch_, 0x00, 0x08, | |
2984 0x00, 0x00, 0x00, 0x31, | |
2985 0x00, 0x00, 0x00, 0x01, | |
2986 0x38, 0xea, 0xe3, 0xc6, | |
2987 0xa7, 0xc2, 0x02, 0xe5, | |
2988 0x0e, 0x50, 0xc2, 0x4b, | |
2989 0x4a, 0x04, 0xe5, 0x0b, | |
2990 0x66, 0x80, 0x00, 0x4a, | |
2991 0xcb, 0xcf, 0x07, 0x08, | |
2992 0x20, 0x10, 0x95, 0x96, | |
2993 0x9f, 0x0f, 0xa2, 0x00, | |
2994 0x02, 0x28, 0x29, 0xb1, | |
2995 0x08, 0x20, 0x80, 0x00, | |
2996 0x00, 0x00, 0x00, 0xff, | |
2997 0xff, | |
2998 }; | |
2999 const unsigned char kV2SIMDFrameData[] = { | |
3000 0x80, spdy_version_ch_, 0x00, 0x08, | |
3001 0x00, 0x00, 0x00, 0x2f, | |
3002 0x00, 0x00, 0x00, 0x01, | |
3003 0x00, 0x00, 0x38, 0xea, | |
3004 0xdf, 0xa2, 0x51, 0xb2, | |
3005 0x62, 0x60, 0x62, 0x60, | |
3006 0x4e, 0x4a, 0x2c, 0x62, | |
3007 0x60, 0x06, 0x08, 0xa0, | |
3008 0xb4, 0xfc, 0x7c, 0x80, | |
3009 0x00, 0x62, 0x60, 0x06, | |
3010 0x13, 0x00, 0x01, 0x94, | |
3011 0x94, 0x58, 0x04, 0x10, | |
3012 0x40, 0x00, 0x00, 0x00, | |
3013 0x00, 0xff, 0xff, | |
3014 }; | |
3015 const unsigned char kV3SIMDFrameData[] = { | |
3016 0x80, spdy_version_ch_, 0x00, 0x08, | |
3017 0x00, 0x00, 0x00, 0x2c, | |
3018 0x00, 0x00, 0x00, 0x01, | |
3019 0x38, 0xea, 0xe3, 0xc6, | |
3020 0xa7, 0xc2, 0x02, 0xe5, | |
3021 0x0e, 0x50, 0xc2, 0x4b, | |
3022 0x4a, 0x04, 0xe5, 0x0b, | |
3023 0x66, 0x80, 0x00, 0x4a, | |
3024 0xcb, 0xcf, 0x07, 0x08, | |
3025 0x20, 0x24, 0x0a, 0x20, | |
3026 0x80, 0x92, 0x12, 0x8b, | |
3027 0x00, 0x02, 0x08, 0x00, | |
3028 0x00, 0x00, 0xff, 0xff, | |
3029 }; | |
3030 | |
3031 SpdyHeadersIR headers_ir(1); | |
3032 headers_ir.SetHeader("bar", "foo"); | |
3033 headers_ir.SetHeader("foo", "bar"); | |
3034 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); | |
3035 const unsigned char* frame_data = | |
3036 reinterpret_cast<const unsigned char*>(frame->data()); | |
3037 if (IsSpdy2()) { | |
3038 // Try comparing with SIMD version, if that fails, do a failing check | |
3039 // with pretty printing against non-SIMD version | |
3040 if (memcmp(frame_data, | |
3041 kV2SIMDFrameData, | |
3042 std::min(arraysize(kV2SIMDFrameData), frame->size())) != 0) { | |
3043 CompareCharArraysWithHexError(kDescription, | |
3044 frame_data, | |
3045 frame->size(), | |
3046 kV2FrameData, | |
3047 arraysize(kV2FrameData)); | |
3048 } | |
3049 } else if (IsSpdy3()) { | |
3050 if (memcmp(frame_data, | |
3051 kV3SIMDFrameData, | |
3052 std::min(arraysize(kV3SIMDFrameData), frame->size())) != 0) { | |
3053 CompareCharArraysWithHexError(kDescription, | |
3054 frame_data, | |
3055 frame->size(), | |
3056 kV3FrameData, | |
3057 arraysize(kV3FrameData)); | |
3058 } | |
3059 } else { | |
3060 // Deflate compression doesn't apply to HPACK. | |
3061 } | |
3062 } | |
3063 } | |
3064 #endif // !defined(USE_SYSTEM_ZLIB) | |
3065 | |
3066 TEST_P(SpdyFramerTest, CreateWindowUpdate) { | |
3067 SpdyFramer framer(spdy_version_); | |
3068 | |
3069 { | |
3070 const char kDescription[] = "WINDOW_UPDATE frame"; | |
3071 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
3072 0x80, spdy_version_ch_, 0x00, 0x09, | |
3073 0x00, 0x00, 0x00, 0x08, | |
3074 0x00, 0x00, 0x00, 0x01, | |
3075 0x00, 0x00, 0x00, 0x01, | |
3076 }; | |
3077 const unsigned char kV4FrameData[] = { | |
3078 0x00, 0x00, 0x04, 0x08, | |
3079 0x00, 0x00, 0x00, 0x00, | |
3080 0x01, 0x00, 0x00, 0x00, | |
3081 0x01, | |
3082 }; | |
3083 scoped_ptr<SpdyFrame> frame( | |
3084 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 1))); | |
3085 if (IsSpdy4()) { | |
3086 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
3087 } else { | |
3088 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
3089 } | |
3090 } | |
3091 | |
3092 { | |
3093 const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; | |
3094 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
3095 0x80, spdy_version_ch_, 0x00, 0x09, | |
3096 0x00, 0x00, 0x00, 0x08, | |
3097 0x7f, 0xff, 0xff, 0xff, | |
3098 0x00, 0x00, 0x00, 0x01, | |
3099 }; | |
3100 const unsigned char kV4FrameData[] = { | |
3101 0x00, 0x00, 0x04, 0x08, | |
3102 0x00, 0x7f, 0xff, 0xff, | |
3103 0xff, 0x00, 0x00, 0x00, | |
3104 0x01, | |
3105 }; | |
3106 scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate( | |
3107 SpdyWindowUpdateIR(0x7FFFFFFF, 1))); | |
3108 if (IsSpdy4()) { | |
3109 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
3110 } else { | |
3111 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
3112 } | |
3113 } | |
3114 | |
3115 { | |
3116 const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; | |
3117 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
3118 0x80, spdy_version_ch_, 0x00, 0x09, | |
3119 0x00, 0x00, 0x00, 0x08, | |
3120 0x00, 0x00, 0x00, 0x01, | |
3121 0x7f, 0xff, 0xff, 0xff, | |
3122 }; | |
3123 const unsigned char kV4FrameData[] = { | |
3124 0x00, 0x00, 0x04, 0x08, | |
3125 0x00, 0x00, 0x00, 0x00, | |
3126 0x01, 0x7f, 0xff, 0xff, | |
3127 0xff, | |
3128 }; | |
3129 scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate( | |
3130 SpdyWindowUpdateIR(1, 0x7FFFFFFF))); | |
3131 if (IsSpdy4()) { | |
3132 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); | |
3133 } else { | |
3134 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); | |
3135 } | |
3136 } | |
3137 } | |
3138 | |
3139 TEST_P(SpdyFramerTest, SerializeBlocked) { | |
3140 if (spdy_version_ <= SPDY3) { | |
3141 return; | |
3142 } | |
3143 | |
3144 SpdyFramer framer(spdy_version_); | |
3145 | |
3146 const char kDescription[] = "BLOCKED frame"; | |
3147 const unsigned char kType = static_cast<unsigned char>( | |
3148 SpdyConstants::SerializeFrameType(spdy_version_, BLOCKED)); | |
3149 const unsigned char kFrameData[] = { | |
3150 0x00, 0x00, 0x00, kType, 0x00, | |
3151 0x00, 0x00, 0x00, 0x00, | |
3152 }; | |
3153 SpdyBlockedIR blocked_ir(0); | |
3154 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(blocked_ir)); | |
3155 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
3156 } | |
3157 | |
3158 TEST_P(SpdyFramerTest, CreateBlocked) { | |
3159 if (spdy_version_ <= SPDY3) { | |
3160 return; | |
3161 } | |
3162 | |
3163 SpdyFramer framer(spdy_version_); | |
3164 | |
3165 const char kDescription[] = "BLOCKED frame"; | |
3166 const SpdyStreamId kStreamId = 3; | |
3167 | |
3168 scoped_ptr<SpdySerializedFrame> frame_serialized( | |
3169 framer.SerializeBlocked(SpdyBlockedIR(kStreamId))); | |
3170 SpdyBlockedIR blocked_ir(kStreamId); | |
3171 scoped_ptr<SpdySerializedFrame> frame_created( | |
3172 framer.SerializeFrame(blocked_ir)); | |
3173 | |
3174 CompareFrames(kDescription, *frame_serialized, *frame_created); | |
3175 } | |
3176 | |
3177 TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) { | |
3178 if (spdy_version_ <= SPDY3) { | |
3179 return; | |
3180 } | |
3181 | |
3182 { | |
3183 // Test framing PUSH_PROMISE without padding. | |
3184 SpdyFramer framer(spdy_version_); | |
3185 framer.set_enable_compression(false); | |
3186 const char kDescription[] = "PUSH_PROMISE frame without padding"; | |
3187 | |
3188 const unsigned char kFrameData[] = { | |
3189 0x00, 0x00, 0x16, 0x05, // PUSH_PROMISE | |
3190 0x04, 0x00, 0x00, 0x00, // END_HEADERS | |
3191 0x2a, 0x00, 0x00, 0x00, // Stream 42 | |
3192 0x39, 0x00, 0x03, 0x62, // Promised stream 57, @.b | |
3193 0x61, 0x72, 0x03, 0x66, // ar.f | |
3194 0x6f, 0x6f, 0x00, 0x03, // oo@. | |
3195 0x66, 0x6f, 0x6f, 0x03, // foo. | |
3196 0x62, 0x61, 0x72, // bar | |
3197 }; | |
3198 | |
3199 SpdyPushPromiseIR push_promise(42, 57); | |
3200 push_promise.SetHeader("bar", "foo"); | |
3201 push_promise.SetHeader("foo", "bar"); | |
3202 scoped_ptr<SpdySerializedFrame> frame( | |
3203 framer.SerializePushPromise(push_promise)); | |
3204 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
3205 } | |
3206 | |
3207 { | |
3208 // Test framing PUSH_PROMISE with one byte of padding. | |
3209 SpdyFramer framer(spdy_version_); | |
3210 framer.set_enable_compression(false); | |
3211 const char kDescription[] = "PUSH_PROMISE frame with one byte of padding"; | |
3212 | |
3213 const unsigned char kFrameData[] = { | |
3214 0x00, 0x00, 0x17, 0x05, // PUSH_PROMISE | |
3215 0x0c, 0x00, 0x00, 0x00, // END_HEADERS | PADDED | |
3216 0x2a, 0x00, 0x00, 0x00, // Stream 42, Pad length field | |
3217 0x00, 0x39, 0x00, 0x03, // Promised stream 57 | |
3218 0x62, 0x61, 0x72, 0x03, // bar. | |
3219 0x66, 0x6f, 0x6f, 0x00, // foo@ | |
3220 0x03, 0x66, 0x6f, 0x6f, // .foo | |
3221 0x03, 0x62, 0x61, 0x72, // .bar | |
3222 }; | |
3223 | |
3224 SpdyPushPromiseIR push_promise(42, 57); | |
3225 push_promise.set_padding_len(1); | |
3226 push_promise.SetHeader("bar", "foo"); | |
3227 push_promise.SetHeader("foo", "bar"); | |
3228 scoped_ptr<SpdySerializedFrame> frame( | |
3229 framer.SerializePushPromise(push_promise)); | |
3230 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
3231 } | |
3232 | |
3233 { | |
3234 // Test framing PUSH_PROMISE with 177 bytes of padding. | |
3235 SpdyFramer framer(spdy_version_); | |
3236 framer.set_enable_compression(false); | |
3237 const char kDescription[] = "PUSH_PROMISE frame with 177 bytes of padding"; | |
3238 | |
3239 const unsigned char kFrameData[] = { | |
3240 0x00, 0x00, 0xc7, 0x05, // PUSH_PROMISE | |
3241 0x0c, 0x00, 0x00, 0x00, // END_HEADERS | PADDED | |
3242 0x2a, 0xb0, 0x00, 0x00, // Stream 42, Pad length field | |
3243 0x00, 0x39, 0x00, 0x03, // Promised stream 57 | |
3244 0x62, 0x61, 0x72, 0x03, // bar. | |
3245 0x66, 0x6f, 0x6f, 0x00, // foo@ | |
3246 0x03, 0x66, 0x6f, 0x6f, // .foo | |
3247 0x03, 0x62, 0x61, 0x72, // .bar | |
3248 // Padding of 176 0x00(s). | |
3249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
3264 }; | |
3265 | |
3266 SpdyPushPromiseIR push_promise(42, 57); | |
3267 push_promise.set_padding_len(177); | |
3268 push_promise.SetHeader("bar", "foo"); | |
3269 push_promise.SetHeader("foo", "bar"); | |
3270 scoped_ptr<SpdySerializedFrame> frame( | |
3271 framer.SerializePushPromise(push_promise)); | |
3272 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
3273 } | |
3274 } | |
3275 | |
3276 TEST_P(SpdyFramerTest, CreateContinuationUncompressed) { | |
3277 if (spdy_version_ <= SPDY3) { | |
3278 return; | |
3279 } | |
3280 | |
3281 SpdyFramer framer(spdy_version_); | |
3282 framer.set_enable_compression(false); | |
3283 const char kDescription[] = "CONTINUATION frame"; | |
3284 | |
3285 const unsigned char kFrameData[] = { | |
3286 0x00, 0x00, 0x12, 0x09, 0x00, // CONTINUATION | |
3287 0x00, 0x00, 0x00, 0x2a, // Stream 42 | |
3288 0x00, 0x03, 0x62, 0x61, // @.ba | |
3289 0x72, 0x03, 0x66, 0x6f, // r.fo | |
3290 0x6f, 0x00, 0x03, 0x66, // o@.f | |
3291 0x6f, 0x6f, 0x03, 0x62, // oo.b | |
3292 0x61, 0x72, // ar | |
3293 }; | |
3294 | |
3295 SpdyContinuationIR continuation(42); | |
3296 continuation.SetHeader("bar", "foo"); | |
3297 continuation.SetHeader("foo", "bar"); | |
3298 scoped_ptr<SpdySerializedFrame> frame( | |
3299 framer.SerializeContinuation(continuation)); | |
3300 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
3301 } | |
3302 | |
3303 TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) { | |
3304 if (spdy_version_ <= SPDY3) { | |
3305 return; | |
3306 } | |
3307 | |
3308 { | |
3309 // Test framing in a case such that a PUSH_PROMISE frame, with one byte of | |
3310 // padding, cannot hold all the data payload, which is overflowed to the | |
3311 // consecutive CONTINUATION frame. | |
3312 SpdyFramer framer(spdy_version_); | |
3313 framer.set_enable_compression(false); | |
3314 const char kDescription[] = | |
3315 "PUSH_PROMISE and CONTINUATION frames with one byte of padding"; | |
3316 | |
3317 const unsigned char kPartialPushPromiseFrameData[] = { | |
3318 0x00, 0x03, 0xf7, 0x05, // PUSH_PROMISE | |
3319 0x08, 0x00, 0x00, 0x00, // PADDED | |
3320 0x2a, 0x00, 0x00, 0x00, // Stream 42 | |
3321 0x00, 0x39, 0x00, 0x03, // Promised stream 57 | |
3322 0x78, 0x78, 0x78, 0x7f, // xxx. | |
3323 0x81, 0x07, 0x78, 0x78, // ..xx | |
3324 0x78, 0x78, 0x78, 0x78, // xxxx | |
3325 0x78, 0x78, 0x78, 0x78, // xxxx | |
3326 0x78, 0x78, 0x78, 0x78, // xxxx | |
3327 0x78, 0x78, 0x78, 0x78, // xxxx | |
3328 0x78, 0x78, 0x78, 0x78, // xxxx | |
3329 0x78, 0x78, 0x78, 0x78, // xxxx | |
3330 0x78, 0x78, 0x78, 0x78, // xxxx | |
3331 0x78, 0x78, 0x78, 0x78, // xxxx | |
3332 0x78, 0x78, 0x78, 0x78, // xxxx | |
3333 0x78, 0x78, 0x78, 0x78, // xxxx | |
3334 0x78, 0x78, 0x78, 0x78, // xxxx | |
3335 0x78, 0x78, 0x78, 0x78, // xxxx | |
3336 0x78, 0x78, 0x78, 0x78, // xxxx | |
3337 0x78, 0x78, 0x78, 0x78, // xxxx | |
3338 0x78, 0x78, 0x78, 0x78, // xxxx | |
3339 0x78, 0x78, 0x78, 0x78, // xxxx | |
3340 0x78, 0x78, 0x78, 0x78, // xxxx | |
3341 0x78, 0x78, 0x78, 0x78, // xxxx | |
3342 0x78, 0x78, 0x78, 0x78, // xxxx | |
3343 0x78, 0x78, 0x78, 0x78, // xxxx | |
3344 0x78, 0x78, // xx | |
3345 }; | |
3346 | |
3347 const unsigned char kContinuationFrameData[] = { | |
3348 0x00, 0x00, 0x16, 0x09, // CONTINUATION | |
3349 0x04, 0x00, 0x00, 0x00, // END_HEADERS | |
3350 0x2a, 0x78, 0x78, 0x78, // Stream 42, xxx | |
3351 0x78, 0x78, 0x78, 0x78, // xxxx | |
3352 0x78, 0x78, 0x78, 0x78, // xxxx | |
3353 0x78, 0x78, 0x78, 0x78, // xxxx | |
3354 0x78, 0x78, 0x78, 0x78, // xxxx | |
3355 0x78, 0x78, | |
3356 }; | |
3357 | |
3358 SpdyPushPromiseIR push_promise(42, 57); | |
3359 push_promise.set_padding_len(1); | |
3360 string big_value(TestSpdyVisitor::sent_control_frame_max_size(), 'x'); | |
3361 push_promise.SetHeader("xxx", big_value); | |
3362 scoped_ptr<SpdySerializedFrame> frame( | |
3363 framer.SerializePushPromise(push_promise)); | |
3364 | |
3365 // The entire frame should look like below: | |
3366 // Name Length in Byte | |
3367 // ------------------------------------------- Begin of PUSH_PROMISE frame | |
3368 // PUSH_PROMISE header 9 | |
3369 // Pad length field 1 | |
3370 // Promised stream 4 | |
3371 // Length field of key 2 | |
3372 // Content of key 3 | |
3373 // Length field of value 3 | |
3374 // Part of big_value 16361 | |
3375 // ------------------------------------------- Begin of CONTINUATION frame | |
3376 // CONTINUATION header 9 | |
3377 // Remaining of big_value 22 | |
3378 // ------------------------------------------- End | |
3379 | |
3380 // Length of everything listed above except big_value. | |
3381 int len_non_data_payload = 31; | |
3382 EXPECT_EQ( | |
3383 TestSpdyVisitor::sent_control_frame_max_size() + len_non_data_payload, | |
3384 frame->size()); | |
3385 | |
3386 // Partially compare the PUSH_PROMISE frame against the template. | |
3387 const unsigned char* frame_data = | |
3388 reinterpret_cast<const unsigned char*>(frame->data()); | |
3389 CompareCharArraysWithHexError(kDescription, | |
3390 frame_data, | |
3391 arraysize(kPartialPushPromiseFrameData), | |
3392 kPartialPushPromiseFrameData, | |
3393 arraysize(kPartialPushPromiseFrameData)); | |
3394 | |
3395 // Compare the CONTINUATION frame against the template. | |
3396 frame_data += TestSpdyVisitor::sent_control_frame_max_size(); | |
3397 CompareCharArraysWithHexError(kDescription, | |
3398 frame_data, | |
3399 arraysize(kContinuationFrameData), | |
3400 kContinuationFrameData, | |
3401 arraysize(kContinuationFrameData)); | |
3402 } | |
3403 } | |
3404 | |
3405 TEST_P(SpdyFramerTest, CreateAltSvc) { | |
3406 if (spdy_version_ <= SPDY3) { | |
3407 return; | |
3408 } | |
3409 | |
3410 SpdyFramer framer(spdy_version_); | |
3411 | |
3412 const char kDescription[] = "ALTSVC frame"; | |
3413 const unsigned char kType = static_cast<unsigned char>( | |
3414 SpdyConstants::SerializeFrameType(spdy_version_, ALTSVC)); | |
3415 const unsigned char kFrameData[] = { | |
3416 0x00, 0x00, 0x17, kType, 0x00, | |
3417 0x00, 0x00, 0x00, 0x03, | |
3418 0x00, 0x00, 0x00, 0x05, | |
3419 0x01, 0xbb, 0x00, 0x04, // Port = 443 | |
3420 'p', 'i', 'd', '1', // Protocol-ID | |
3421 0x04, 'h', 'o', 's', | |
3422 't', 'o', 'r', 'i', | |
3423 'g', 'i', 'n', | |
3424 }; | |
3425 SpdyAltSvcIR altsvc_ir(3); | |
3426 altsvc_ir.set_max_age(5); | |
3427 altsvc_ir.set_port(443); | |
3428 altsvc_ir.set_protocol_id("pid1"); | |
3429 altsvc_ir.set_host("host"); | |
3430 altsvc_ir.set_origin("origin"); | |
3431 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir)); | |
3432 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
3433 } | |
3434 | |
3435 TEST_P(SpdyFramerTest, CreatePriority) { | |
3436 if (spdy_version_ <= SPDY3) { | |
3437 return; | |
3438 } | |
3439 | |
3440 SpdyFramer framer(spdy_version_); | |
3441 | |
3442 const char kDescription[] = "PRIORITY frame"; | |
3443 const unsigned char kType = static_cast<unsigned char>( | |
3444 SpdyConstants::SerializeFrameType(spdy_version_, PRIORITY)); | |
3445 const unsigned char kFrameData[] = { | |
3446 0x00, 0x00, 0x05, kType, 0x00, | |
3447 0x00, 0x00, 0x00, 0x02, // Stream ID = 2 | |
3448 0x80, 0x00, 0x00, 0x01, // Exclusive dependency, parent stream ID = 1 | |
3449 0x10, // Weight = 16 | |
3450 }; | |
3451 SpdyPriorityIR priority_ir(2, 1, 16, true); | |
3452 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(priority_ir)); | |
3453 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
3454 } | |
3455 | |
3456 TEST_P(SpdyFramerTest, ReadCompressedSynStreamHeaderBlock) { | |
3457 if (spdy_version_ > SPDY3) { | |
3458 // SYN_STREAM not supported in SPDY>3 | |
3459 return; | |
3460 } | |
3461 SpdyFramer framer(spdy_version_); | |
3462 SpdySynStreamIR syn_stream(1); | |
3463 syn_stream.set_priority(1); | |
3464 syn_stream.SetHeader("aa", "vv"); | |
3465 syn_stream.SetHeader("bb", "ww"); | |
3466 SpdyHeaderBlock headers = syn_stream.name_value_block(); | |
3467 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynStream(syn_stream)); | |
3468 EXPECT_TRUE(control_frame.get() != NULL); | |
3469 TestSpdyVisitor visitor(spdy_version_); | |
3470 visitor.use_compression_ = true; | |
3471 visitor.SimulateInFramer( | |
3472 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3473 control_frame->size()); | |
3474 EXPECT_EQ(1, visitor.syn_frame_count_); | |
3475 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
3476 } | |
3477 | |
3478 TEST_P(SpdyFramerTest, ReadCompressedSynReplyHeaderBlock) { | |
3479 if (spdy_version_ > SPDY3) { | |
3480 return; | |
3481 } | |
3482 SpdyFramer framer(spdy_version_); | |
3483 SpdySynReplyIR syn_reply(1); | |
3484 syn_reply.SetHeader("alpha", "beta"); | |
3485 syn_reply.SetHeader("gamma", "delta"); | |
3486 SpdyHeaderBlock headers = syn_reply.name_value_block(); | |
3487 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynReply(syn_reply)); | |
3488 EXPECT_TRUE(control_frame.get() != NULL); | |
3489 TestSpdyVisitor visitor(spdy_version_); | |
3490 visitor.use_compression_ = true; | |
3491 visitor.SimulateInFramer( | |
3492 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3493 control_frame->size()); | |
3494 if (IsSpdy4()) { | |
3495 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
3496 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3497 } else { | |
3498 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
3499 EXPECT_EQ(0, visitor.headers_frame_count_); | |
3500 } | |
3501 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
3502 } | |
3503 | |
3504 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) { | |
3505 SpdyFramer framer(spdy_version_); | |
3506 SpdyHeadersIR headers_ir(1); | |
3507 headers_ir.SetHeader("alpha", "beta"); | |
3508 headers_ir.SetHeader("gamma", "delta"); | |
3509 SpdyHeaderBlock headers = headers_ir.name_value_block(); | |
3510 scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers_ir)); | |
3511 EXPECT_TRUE(control_frame.get() != NULL); | |
3512 TestSpdyVisitor visitor(spdy_version_); | |
3513 visitor.use_compression_ = true; | |
3514 visitor.SimulateInFramer( | |
3515 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3516 control_frame->size()); | |
3517 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3518 // control_frame_header_data_count_ depends on the random sequence | |
3519 // produced by rand(), so adding, removing or running single tests | |
3520 // alters this value. The best we can do is assert that it happens | |
3521 // at least twice. | |
3522 EXPECT_LE(2, visitor.control_frame_header_data_count_); | |
3523 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
3524 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); | |
3525 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
3526 } | |
3527 | |
3528 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) { | |
3529 SpdyFramer framer(spdy_version_); | |
3530 SpdyHeadersIR headers_ir(1); | |
3531 headers_ir.set_fin(true); | |
3532 headers_ir.SetHeader("alpha", "beta"); | |
3533 headers_ir.SetHeader("gamma", "delta"); | |
3534 SpdyHeaderBlock headers = headers_ir.name_value_block(); | |
3535 scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers_ir)); | |
3536 EXPECT_TRUE(control_frame.get() != NULL); | |
3537 TestSpdyVisitor visitor(spdy_version_); | |
3538 visitor.use_compression_ = true; | |
3539 visitor.SimulateInFramer( | |
3540 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3541 control_frame->size()); | |
3542 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3543 // control_frame_header_data_count_ depends on the random sequence | |
3544 // produced by rand(), so adding, removing or running single tests | |
3545 // alters this value. The best we can do is assert that it happens | |
3546 // at least twice. | |
3547 EXPECT_LE(2, visitor.control_frame_header_data_count_); | |
3548 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
3549 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
3550 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
3551 } | |
3552 | |
3553 TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) { | |
3554 if (spdy_version_ > SPDY3) { | |
3555 // TODO(jgraettinger): This test setup doesn't work with HPACK. | |
3556 return; | |
3557 } | |
3558 // First find the size of the header value in order to just reach the control | |
3559 // frame max size. | |
3560 SpdyFramer framer(spdy_version_); | |
3561 framer.set_enable_compression(false); | |
3562 SpdySynStreamIR syn_stream(1); | |
3563 syn_stream.set_priority(1); | |
3564 syn_stream.SetHeader("aa", ""); | |
3565 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynStream(syn_stream)); | |
3566 const size_t kBigValueSize = | |
3567 TestSpdyVisitor::sent_control_frame_max_size() - control_frame->size(); | |
3568 | |
3569 // Create a frame at exactly that size. | |
3570 string big_value(kBigValueSize, 'x'); | |
3571 syn_stream.SetHeader("aa", big_value); | |
3572 control_frame.reset(framer.SerializeSynStream(syn_stream)); | |
3573 EXPECT_TRUE(control_frame.get() != NULL); | |
3574 EXPECT_EQ(TestSpdyVisitor::sent_control_frame_max_size(), | |
3575 control_frame->size()); | |
3576 | |
3577 TestSpdyVisitor visitor(spdy_version_); | |
3578 visitor.SimulateInFramer( | |
3579 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3580 control_frame->size()); | |
3581 EXPECT_TRUE(visitor.header_buffer_valid_); | |
3582 EXPECT_EQ(0, visitor.error_count_); | |
3583 EXPECT_EQ(1, visitor.syn_frame_count_); | |
3584 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
3585 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); | |
3586 EXPECT_LT(kBigValueSize, visitor.header_buffer_length_); | |
3587 } | |
3588 | |
3589 // This test is disabled because Chromium is willing to accept control frames up | |
3590 // to the maximum size allowed by the specification, and SpdyFrameBuilder is not | |
3591 // capable of building larger frames. | |
3592 TEST_P(SpdyFramerTest, DISABLED_ControlFrameTooLarge) { | |
3593 if (spdy_version_ > SPDY3) { | |
3594 // TODO(jgraettinger): This test setup doesn't work with HPACK. | |
3595 return; | |
3596 } | |
3597 // First find the size of the header value in order to just reach the control | |
3598 // frame max size. | |
3599 SpdyFramer framer(spdy_version_); | |
3600 framer.set_enable_compression(false); | |
3601 SpdySynStreamIR syn_stream(1); | |
3602 syn_stream.SetHeader("aa", ""); | |
3603 syn_stream.set_priority(1); | |
3604 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynStream(syn_stream)); | |
3605 const size_t kBigValueSize = | |
3606 SpdyConstants::GetFrameMaximumSize(spdy_version_) - | |
3607 control_frame->size() + 1; | |
3608 | |
3609 // Create a frame at exatly that size. | |
3610 string big_value(kBigValueSize, 'x'); | |
3611 syn_stream.SetHeader("aa", big_value); | |
3612 // Upstream branches here and wraps SPDY4 with EXPECT_DEBUG_DFATAL. We | |
3613 // neither support that in Chromium, nor do we use the same DFATAL (see | |
3614 // SpdyFrameBuilder::WriteFramePrefix()). | |
3615 control_frame.reset(framer.SerializeSynStream(syn_stream)); | |
3616 | |
3617 EXPECT_TRUE(control_frame.get() != NULL); | |
3618 EXPECT_EQ(SpdyConstants::GetFrameMaximumSize(spdy_version_) + 1, | |
3619 control_frame->size()); | |
3620 | |
3621 TestSpdyVisitor visitor(spdy_version_); | |
3622 visitor.SimulateInFramer( | |
3623 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3624 control_frame->size()); | |
3625 EXPECT_FALSE(visitor.header_buffer_valid_); | |
3626 EXPECT_EQ(1, visitor.error_count_); | |
3627 EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE, | |
3628 visitor.framer_.error_code()) | |
3629 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
3630 EXPECT_EQ(0, visitor.syn_frame_count_); | |
3631 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
3632 } | |
3633 | |
3634 TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) { | |
3635 if (spdy_version_ <= SPDY3) { | |
3636 return; | |
3637 } | |
3638 SpdyFramer framer(spdy_version_); | |
3639 framer.set_enable_compression(false); | |
3640 SpdyHeadersIR headers(1); | |
3641 headers.set_padding_len(256); | |
3642 | |
3643 // Exact payload length will change with HPACK, but this should be long | |
3644 // enough to cause an overflow. | |
3645 const size_t kBigValueSize = kControlFrameSizeLimit; | |
3646 string big_value(kBigValueSize, 'x'); | |
3647 headers.SetHeader("aa", big_value); | |
3648 scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers)); | |
3649 EXPECT_TRUE(control_frame.get() != NULL); | |
3650 EXPECT_GT(control_frame->size(), | |
3651 TestSpdyVisitor::sent_control_frame_max_size()); | |
3652 | |
3653 TestSpdyVisitor visitor(spdy_version_); | |
3654 visitor.SimulateInFramer( | |
3655 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3656 control_frame->size()); | |
3657 EXPECT_TRUE(visitor.header_buffer_valid_); | |
3658 EXPECT_EQ(0, visitor.error_count_); | |
3659 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3660 EXPECT_EQ(16, visitor.continuation_count_); | |
3661 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
3662 } | |
3663 | |
3664 TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) { | |
3665 if (spdy_version_ <= SPDY3) { | |
3666 return; | |
3667 } | |
3668 SpdyFramer framer(spdy_version_); | |
3669 framer.set_enable_compression(false); | |
3670 SpdyPushPromiseIR push_promise(1, 2); | |
3671 push_promise.set_padding_len(256); | |
3672 | |
3673 // Exact payload length will change with HPACK, but this should be long | |
3674 // enough to cause an overflow. | |
3675 const size_t kBigValueSize = kControlFrameSizeLimit; | |
3676 string big_value(kBigValueSize, 'x'); | |
3677 push_promise.SetHeader("aa", big_value); | |
3678 scoped_ptr<SpdyFrame> control_frame( | |
3679 framer.SerializePushPromise(push_promise)); | |
3680 EXPECT_TRUE(control_frame.get() != NULL); | |
3681 EXPECT_GT(control_frame->size(), | |
3682 TestSpdyVisitor::sent_control_frame_max_size()); | |
3683 | |
3684 TestSpdyVisitor visitor(spdy_version_); | |
3685 visitor.SimulateInFramer( | |
3686 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3687 control_frame->size()); | |
3688 EXPECT_TRUE(visitor.header_buffer_valid_); | |
3689 EXPECT_EQ(0, visitor.error_count_); | |
3690 EXPECT_EQ(1, visitor.push_promise_frame_count_); | |
3691 EXPECT_EQ(16, visitor.continuation_count_); | |
3692 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
3693 } | |
3694 | |
3695 // Check that the framer stops delivering header data chunks once the visitor | |
3696 // declares it doesn't want any more. This is important to guard against | |
3697 // "zip bomb" types of attacks. | |
3698 TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) { | |
3699 const size_t kHeaderBufferChunks = 4; | |
3700 const size_t kHeaderBufferSize = | |
3701 TestSpdyVisitor::header_data_chunk_max_size() * kHeaderBufferChunks; | |
3702 const size_t kBigValueSize = kHeaderBufferSize * 2; | |
3703 string big_value(kBigValueSize, 'x'); | |
3704 SpdyFramer framer(spdy_version_); | |
3705 SpdyHeadersIR headers(1); | |
3706 headers.set_priority(1); | |
3707 headers.set_fin(true); | |
3708 headers.SetHeader("aa", big_value); | |
3709 scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers)); | |
3710 EXPECT_TRUE(control_frame.get() != NULL); | |
3711 TestSpdyVisitor visitor(spdy_version_); | |
3712 visitor.set_header_buffer_size(kHeaderBufferSize); | |
3713 visitor.use_compression_ = true; | |
3714 visitor.SimulateInFramer( | |
3715 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3716 control_frame->size()); | |
3717 EXPECT_FALSE(visitor.header_buffer_valid_); | |
3718 EXPECT_EQ(1, visitor.error_count_); | |
3719 EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE, | |
3720 visitor.framer_.error_code()) | |
3721 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
3722 | |
3723 // The framer should have stoped delivering chunks after the visitor | |
3724 // signaled "stop" by returning false from OnControlFrameHeaderData(). | |
3725 // | |
3726 // control_frame_header_data_count_ depends on the random sequence | |
3727 // produced by rand(), so adding, removing or running single tests | |
3728 // alters this value. The best we can do is assert that it happens | |
3729 // at least kHeaderBufferChunks + 1. | |
3730 EXPECT_LE(kHeaderBufferChunks + 1, | |
3731 static_cast<unsigned>(visitor.control_frame_header_data_count_)); | |
3732 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
3733 | |
3734 // The framer should not have sent half-close to the visitor. | |
3735 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); | |
3736 } | |
3737 | |
3738 TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) { | |
3739 if (spdy_version_ > SPDY3) { | |
3740 // Deflate compression doesn't apply to HPACK. | |
3741 return; | |
3742 } | |
3743 SpdyFramer framer(spdy_version_); | |
3744 framer.set_enable_compression(false); | |
3745 // Construct a SYN_STREAM control frame without compressing the header block, | |
3746 // and have the framer try to decompress it. This will cause the framer to | |
3747 // deal with a decompression error. | |
3748 SpdySynStreamIR syn_stream(1); | |
3749 syn_stream.set_priority(1); | |
3750 syn_stream.SetHeader("aa", "alpha beta gamma delta"); | |
3751 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSynStream(syn_stream)); | |
3752 TestSpdyVisitor visitor(spdy_version_); | |
3753 visitor.use_compression_ = true; | |
3754 visitor.SimulateInFramer( | |
3755 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3756 control_frame->size()); | |
3757 EXPECT_EQ(1, visitor.error_count_); | |
3758 EXPECT_EQ(SpdyFramer::SPDY_DECOMPRESS_FAILURE, visitor.framer_.error_code()) | |
3759 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
3760 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
3761 } | |
3762 | |
3763 TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) { | |
3764 SpdyFramer framer(spdy_version_); | |
3765 // Create a GoAway frame that has a few extra bytes at the end. | |
3766 // We create enough overhead to overflow the framer's control frame buffer. | |
3767 ASSERT_LE(SpdyFramer::kControlFrameBufferSize, 250u); | |
3768 const size_t length = SpdyFramer::kControlFrameBufferSize + 1; | |
3769 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
3770 0x80, spdy_version_ch_, 0x00, 0x07, | |
3771 0x00, 0x00, 0x00, static_cast<unsigned char>(length), | |
3772 0x00, 0x00, 0x00, 0x00, // Stream ID | |
3773 0x00, 0x00, 0x00, 0x00, // Status | |
3774 }; | |
3775 | |
3776 // SPDY version 4 and up GOAWAY frames are only bound to a minimal length, | |
3777 // since it may carry opaque data. Verify that minimal length is tested. | |
3778 ASSERT_GT(framer.GetGoAwayMinimumSize(), framer.GetControlFrameHeaderSize()); | |
3779 const size_t less_than_min_length = | |
3780 framer.GetGoAwayMinimumSize() - framer.GetControlFrameHeaderSize() - 1; | |
3781 ASSERT_LE(less_than_min_length, std::numeric_limits<unsigned char>::max()); | |
3782 const unsigned char kV4FrameData[] = { | |
3783 0x00, 0x00, static_cast<unsigned char>(less_than_min_length), 0x07, | |
3784 0x00, 0x00, 0x00, 0x00, | |
3785 0x00, 0x00, 0x00, 0x00, // Stream Id | |
3786 0x00, 0x00, 0x00, 0x00, // Status | |
3787 0x00, | |
3788 }; | |
3789 const size_t pad_length = | |
3790 length + framer.GetControlFrameHeaderSize() - | |
3791 (IsSpdy4() ? sizeof(kV4FrameData) : sizeof(kV3FrameData)); | |
3792 string pad(pad_length, 'A'); | |
3793 TestSpdyVisitor visitor(spdy_version_); | |
3794 | |
3795 if (IsSpdy4()) { | |
3796 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData)); | |
3797 } else { | |
3798 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData)); | |
3799 } | |
3800 visitor.SimulateInFramer( | |
3801 reinterpret_cast<const unsigned char*>(pad.c_str()), | |
3802 pad.length()); | |
3803 | |
3804 EXPECT_EQ(1, visitor.error_count_); // This generated an error. | |
3805 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
3806 visitor.framer_.error_code()) | |
3807 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
3808 EXPECT_EQ(0, visitor.goaway_count_); // Frame not parsed. | |
3809 } | |
3810 | |
3811 TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) { | |
3812 SpdyFramer framer(spdy_version_); | |
3813 SpdySettingsIR settings_ir; | |
3814 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir)); | |
3815 SetFrameLength(control_frame.get(), 0, spdy_version_); | |
3816 TestSpdyVisitor visitor(spdy_version_); | |
3817 visitor.use_compression_ = false; | |
3818 visitor.SimulateInFramer( | |
3819 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3820 framer.GetControlFrameHeaderSize()); | |
3821 if (spdy_version_ <= SPDY3) { | |
3822 // Should generate an error, since zero-len settings frames are unsupported. | |
3823 EXPECT_EQ(1, visitor.error_count_); | |
3824 } else { | |
3825 // Zero-len settings frames are permitted as of SPDY 4. | |
3826 EXPECT_EQ(0, visitor.error_count_); | |
3827 } | |
3828 } | |
3829 | |
3830 // Tests handling of SETTINGS frames with invalid length. | |
3831 TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) { | |
3832 SpdyFramer framer(spdy_version_); | |
3833 SpdySettingsIR settings_ir; | |
3834 | |
3835 // Add a setting to pad the frame so that we don't get a buffer overflow when | |
3836 // calling SimulateInFramer() below. | |
3837 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, | |
3838 false, | |
3839 false, | |
3840 0x00000002); | |
3841 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir)); | |
3842 const size_t kNewLength = 14; | |
3843 SetFrameLength(control_frame.get(), kNewLength, spdy_version_); | |
3844 TestSpdyVisitor visitor(spdy_version_); | |
3845 visitor.use_compression_ = false; | |
3846 visitor.SimulateInFramer( | |
3847 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3848 framer.GetControlFrameHeaderSize() + kNewLength); | |
3849 // Should generate an error, since its not possible to have a | |
3850 // settings frame of length kNewLength. | |
3851 EXPECT_EQ(1, visitor.error_count_); | |
3852 } | |
3853 | |
3854 // Tests handling of SETTINGS frames larger than the frame buffer size. | |
3855 TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) { | |
3856 SpdyFramer framer(spdy_version_); | |
3857 SpdySettingsIR settings_ir; | |
3858 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 1), | |
3859 false, // persist | |
3860 false, // persisted | |
3861 5); | |
3862 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 2), | |
3863 false, // persist | |
3864 false, // persisted | |
3865 6); | |
3866 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 3), | |
3867 false, // persist | |
3868 false, // persisted | |
3869 7); | |
3870 | |
3871 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir)); | |
3872 EXPECT_LT(SpdyFramer::kControlFrameBufferSize, | |
3873 control_frame->size()); | |
3874 TestSpdyVisitor visitor(spdy_version_); | |
3875 visitor.use_compression_ = false; | |
3876 | |
3877 // Read all at once. | |
3878 visitor.SimulateInFramer( | |
3879 reinterpret_cast<unsigned char*>(control_frame->data()), | |
3880 control_frame->size()); | |
3881 EXPECT_EQ(0, visitor.error_count_); | |
3882 EXPECT_EQ(3, visitor.setting_count_); | |
3883 if (spdy_version_ > SPDY3) { | |
3884 EXPECT_EQ(1, visitor.settings_ack_sent_); | |
3885 } | |
3886 | |
3887 // Read data in small chunks. | |
3888 size_t framed_data = 0; | |
3889 size_t unframed_data = control_frame->size(); | |
3890 size_t kReadChunkSize = 5; // Read five bytes at a time. | |
3891 while (unframed_data > 0) { | |
3892 size_t to_read = std::min(kReadChunkSize, unframed_data); | |
3893 visitor.SimulateInFramer( | |
3894 reinterpret_cast<unsigned char*>(control_frame->data() + framed_data), | |
3895 to_read); | |
3896 unframed_data -= to_read; | |
3897 framed_data += to_read; | |
3898 } | |
3899 EXPECT_EQ(0, visitor.error_count_); | |
3900 EXPECT_EQ(3 * 2, visitor.setting_count_); | |
3901 if (spdy_version_ > SPDY3) { | |
3902 EXPECT_EQ(2, visitor.settings_ack_sent_); | |
3903 } | |
3904 } | |
3905 | |
3906 // Tests handling of SETTINGS frame with duplicate entries. | |
3907 TEST_P(SpdyFramerTest, ReadDuplicateSettings) { | |
3908 SpdyFramer framer(spdy_version_); | |
3909 | |
3910 const unsigned char kV2FrameData[] = { | |
3911 0x80, spdy_version_ch_, 0x00, 0x04, | |
3912 0x00, 0x00, 0x00, 0x1C, | |
3913 0x00, 0x00, 0x00, 0x03, | |
3914 0x01, 0x00, 0x00, 0x00, // 1st Setting | |
3915 0x00, 0x00, 0x00, 0x02, | |
3916 0x01, 0x00, 0x00, 0x00, // 2nd (duplicate) Setting | |
3917 0x00, 0x00, 0x00, 0x03, | |
3918 0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting | |
3919 0x00, 0x00, 0x00, 0x03, | |
3920 }; | |
3921 const unsigned char kV3FrameData[] = { | |
3922 0x80, spdy_version_ch_, 0x00, 0x04, | |
3923 0x00, 0x00, 0x00, 0x1C, | |
3924 0x00, 0x00, 0x00, 0x03, | |
3925 0x00, 0x00, 0x00, 0x01, // 1st Setting | |
3926 0x00, 0x00, 0x00, 0x02, | |
3927 0x00, 0x00, 0x00, 0x01, // 2nd (duplicate) Setting | |
3928 0x00, 0x00, 0x00, 0x03, | |
3929 0x00, 0x00, 0x00, 0x03, // 3rd (unprocessed) Setting | |
3930 0x00, 0x00, 0x00, 0x03, | |
3931 }; | |
3932 const unsigned char kV4FrameData[] = { | |
3933 0x00, 0x00, 0x12, 0x04, | |
3934 0x00, 0x00, 0x00, 0x00, | |
3935 0x00, 0x00, 0x01, // 1st Setting | |
3936 0x00, 0x00, 0x00, 0x02, | |
3937 0x00, 0x01, // 2nd (duplicate) Setting | |
3938 0x00, 0x00, 0x00, 0x03, | |
3939 0x00, 0x03, // 3rd (unprocessed) Setting | |
3940 0x00, 0x00, 0x00, 0x03, | |
3941 }; | |
3942 | |
3943 TestSpdyVisitor visitor(spdy_version_); | |
3944 visitor.use_compression_ = false; | |
3945 if (IsSpdy2()) { | |
3946 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData)); | |
3947 } else if (IsSpdy3()) { | |
3948 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData)); | |
3949 } else { | |
3950 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData)); | |
3951 } | |
3952 | |
3953 if (!IsSpdy4()) { | |
3954 EXPECT_EQ(1, visitor.setting_count_); | |
3955 EXPECT_EQ(1, visitor.error_count_); | |
3956 } else { | |
3957 // In SPDY 4+, duplicate settings are allowed; | |
3958 // each setting replaces the previous value for that setting. | |
3959 EXPECT_EQ(3, visitor.setting_count_); | |
3960 EXPECT_EQ(0, visitor.error_count_); | |
3961 EXPECT_EQ(1, visitor.settings_ack_sent_); | |
3962 } | |
3963 } | |
3964 | |
3965 // Tests handling of SETTINGS frame with a setting we don't recognize. | |
3966 TEST_P(SpdyFramerTest, ReadUnknownSettingsId) { | |
3967 SpdyFramer framer(spdy_version_); | |
3968 | |
3969 const unsigned char kV2FrameData[] = { | |
3970 0x80, spdy_version_ch_, 0x00, 0x04, | |
3971 0x00, 0x00, 0x00, 0x1C, | |
3972 0x00, 0x00, 0x00, 0x01, | |
3973 0x10, 0x00, 0x00, 0x00, // 1st Setting | |
3974 0x00, 0x00, 0x00, 0x02, | |
3975 }; | |
3976 const unsigned char kV3FrameData[] = { | |
3977 0x80, spdy_version_ch_, 0x00, 0x04, | |
3978 0x00, 0x00, 0x00, 0x1C, | |
3979 0x00, 0x00, 0x00, 0x01, | |
3980 0x00, 0x00, 0x00, 0x10, // 1st Setting | |
3981 0x00, 0x00, 0x00, 0x02, | |
3982 }; | |
3983 const unsigned char kV4FrameData[] = { | |
3984 0x00, 0x00, 0x06, 0x04, | |
3985 0x00, 0x00, 0x00, 0x00, | |
3986 0x00, 0x00, 0x10, // 1st Setting | |
3987 0x00, 0x00, 0x00, 0x02, | |
3988 }; | |
3989 | |
3990 TestSpdyVisitor visitor(spdy_version_); | |
3991 visitor.use_compression_ = false; | |
3992 if (IsSpdy2()) { | |
3993 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData)); | |
3994 } else if (IsSpdy3()) { | |
3995 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData)); | |
3996 } else { | |
3997 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData)); | |
3998 } | |
3999 | |
4000 if (!IsSpdy4()) { | |
4001 EXPECT_EQ(0, visitor.setting_count_); | |
4002 EXPECT_EQ(1, visitor.error_count_); | |
4003 } else { | |
4004 // In SPDY 4+, we ignore unknown settings because of extensions. | |
4005 EXPECT_EQ(0, visitor.setting_count_); | |
4006 EXPECT_EQ(0, visitor.error_count_); | |
4007 } | |
4008 } | |
4009 | |
4010 // Tests handling of SETTINGS frame with entries out of order. | |
4011 TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) { | |
4012 SpdyFramer framer(spdy_version_); | |
4013 | |
4014 const unsigned char kV2FrameData[] = { | |
4015 0x80, spdy_version_ch_, 0x00, 0x04, | |
4016 0x00, 0x00, 0x00, 0x1C, | |
4017 0x00, 0x00, 0x00, 0x03, | |
4018 0x02, 0x00, 0x00, 0x00, // 1st Setting | |
4019 0x00, 0x00, 0x00, 0x02, | |
4020 0x01, 0x00, 0x00, 0x00, // 2nd (out of order) Setting | |
4021 0x00, 0x00, 0x00, 0x03, | |
4022 0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting | |
4023 0x00, 0x00, 0x00, 0x03, | |
4024 }; | |
4025 const unsigned char kV3FrameData[] = { | |
4026 0x80, spdy_version_ch_, 0x00, 0x04, | |
4027 0x00, 0x00, 0x00, 0x1C, | |
4028 0x00, 0x00, 0x00, 0x03, | |
4029 0x00, 0x00, 0x00, 0x02, // 1st Setting | |
4030 0x00, 0x00, 0x00, 0x02, | |
4031 0x00, 0x00, 0x00, 0x01, // 2nd (out of order) Setting | |
4032 0x00, 0x00, 0x00, 0x03, | |
4033 0x00, 0x00, 0x01, 0x03, // 3rd (unprocessed) Setting | |
4034 0x00, 0x00, 0x00, 0x03, | |
4035 }; | |
4036 const unsigned char kV4FrameData[] = { | |
4037 0x00, 0x00, 0x12, 0x04, | |
4038 0x00, 0x00, 0x00, 0x00, | |
4039 0x00, 0x00, 0x02, // 1st Setting | |
4040 0x00, 0x00, 0x00, 0x02, | |
4041 0x00, 0x01, // 2nd (out of order) Setting | |
4042 0x00, 0x00, 0x00, 0x03, | |
4043 0x00, 0x03, // 3rd (unprocessed) Setting | |
4044 0x00, 0x00, 0x00, 0x03, | |
4045 }; | |
4046 | |
4047 TestSpdyVisitor visitor(spdy_version_); | |
4048 visitor.use_compression_ = false; | |
4049 if (IsSpdy2()) { | |
4050 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData)); | |
4051 } else if (IsSpdy3()) { | |
4052 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData)); | |
4053 } else { | |
4054 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData)); | |
4055 } | |
4056 | |
4057 if (!IsSpdy4()) { | |
4058 EXPECT_EQ(1, visitor.setting_count_); | |
4059 EXPECT_EQ(1, visitor.error_count_); | |
4060 } else { | |
4061 // In SPDY 4+, settings are allowed in any order. | |
4062 EXPECT_EQ(3, visitor.setting_count_); | |
4063 EXPECT_EQ(0, visitor.error_count_); | |
4064 } | |
4065 } | |
4066 | |
4067 TEST_P(SpdyFramerTest, ProcessSettingsAckFrame) { | |
4068 if (spdy_version_ <= SPDY3) { | |
4069 return; | |
4070 } | |
4071 SpdyFramer framer(spdy_version_); | |
4072 | |
4073 const unsigned char kFrameData[] = { | |
4074 0x00, 0x00, 0x00, 0x04, 0x01, | |
4075 0x00, 0x00, 0x00, 0x00, | |
4076 }; | |
4077 | |
4078 TestSpdyVisitor visitor(spdy_version_); | |
4079 visitor.use_compression_ = false; | |
4080 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); | |
4081 | |
4082 EXPECT_EQ(0, visitor.error_count_); | |
4083 EXPECT_EQ(0, visitor.setting_count_); | |
4084 EXPECT_EQ(1, visitor.settings_ack_received_); | |
4085 } | |
4086 | |
4087 TEST_P(SpdyFramerTest, ProcessDataFrameWithPadding) { | |
4088 if (spdy_version_ <= SPDY3) { | |
4089 return; | |
4090 } | |
4091 | |
4092 const int kPaddingLen = 119; | |
4093 const char data_payload[] = "hello"; | |
4094 | |
4095 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4096 SpdyFramer framer(spdy_version_); | |
4097 framer.set_visitor(&visitor); | |
4098 | |
4099 SpdyDataIR data_ir(1, StringPiece(data_payload, strlen(data_payload))); | |
4100 data_ir.set_padding_len(kPaddingLen); | |
4101 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
4102 ASSERT_TRUE(frame.get() != NULL); | |
4103 | |
4104 int bytes_consumed = 0; | |
4105 | |
4106 // Send the frame header. | |
4107 EXPECT_CALL(visitor, OnDataFrameHeader(1, | |
4108 kPaddingLen + strlen(data_payload), | |
4109 false)); | |
4110 CHECK_EQ(framer.GetDataFrameMinimumSize(), | |
4111 framer.ProcessInput(frame->data(), | |
4112 framer.GetDataFrameMinimumSize())); | |
4113 CHECK_EQ(framer.state(), SpdyFramer::SPDY_READ_DATA_FRAME_PADDING_LENGTH); | |
4114 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR); | |
4115 bytes_consumed += framer.GetDataFrameMinimumSize(); | |
4116 | |
4117 // Send the padding length field. | |
4118 CHECK_EQ(1u, framer.ProcessInput(frame->data() + bytes_consumed, 1)); | |
4119 CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME); | |
4120 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR); | |
4121 bytes_consumed += 1; | |
4122 | |
4123 // Send the first two bytes of the data payload, i.e., "he". | |
4124 EXPECT_CALL(visitor, OnStreamFrameData(1, _, 2, false)); | |
4125 CHECK_EQ(2u, framer.ProcessInput(frame->data() + bytes_consumed, 2)); | |
4126 CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME); | |
4127 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR); | |
4128 bytes_consumed += 2; | |
4129 | |
4130 // Send the rest three bytes of the data payload, i.e., "llo". | |
4131 EXPECT_CALL(visitor, OnStreamFrameData(1, _, 3, false)); | |
4132 CHECK_EQ(3u, framer.ProcessInput(frame->data() + bytes_consumed, 3)); | |
4133 CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING); | |
4134 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR); | |
4135 bytes_consumed += 3; | |
4136 | |
4137 // Send the first 100 bytes of the padding payload. | |
4138 EXPECT_CALL(visitor, OnStreamFrameData(1, NULL, 100, false)); | |
4139 CHECK_EQ(100u, framer.ProcessInput(frame->data() + bytes_consumed, 100)); | |
4140 CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING); | |
4141 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR); | |
4142 bytes_consumed += 100; | |
4143 | |
4144 // Send rest of the padding payload. | |
4145 EXPECT_CALL(visitor, OnStreamFrameData(1, NULL, 18, false)); | |
4146 CHECK_EQ(18u, framer.ProcessInput(frame->data() + bytes_consumed, 18)); | |
4147 CHECK_EQ(framer.state(), SpdyFramer::SPDY_RESET); | |
4148 CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR); | |
4149 } | |
4150 | |
4151 TEST_P(SpdyFramerTest, ReadWindowUpdate) { | |
4152 SpdyFramer framer(spdy_version_); | |
4153 scoped_ptr<SpdyFrame> control_frame( | |
4154 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2))); | |
4155 TestSpdyVisitor visitor(spdy_version_); | |
4156 visitor.SimulateInFramer( | |
4157 reinterpret_cast<unsigned char*>(control_frame->data()), | |
4158 control_frame->size()); | |
4159 EXPECT_EQ(1u, visitor.last_window_update_stream_); | |
4160 EXPECT_EQ(2u, visitor.last_window_update_delta_); | |
4161 } | |
4162 | |
4163 TEST_P(SpdyFramerTest, ReceiveCredentialFrame) { | |
4164 if (!IsSpdy3()) { | |
4165 return; | |
4166 } | |
4167 SpdyFramer framer(spdy_version_); | |
4168 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
4169 0x80, spdy_version_ch_, 0x00, 0x0A, | |
4170 0x00, 0x00, 0x00, 0x33, | |
4171 0x00, 0x03, 0x00, 0x00, | |
4172 0x00, 0x05, 'p', 'r', | |
4173 'o', 'o', 'f', 0x00, | |
4174 0x00, 0x00, 0x06, 'a', | |
4175 ' ', 'c', 'e', 'r', | |
4176 't', 0x00, 0x00, 0x00, | |
4177 0x0C, 'a', 'n', 'o', | |
4178 't', 'h', 'e', 'r', | |
4179 ' ', 'c', 'e', 'r', | |
4180 't', 0x00, 0x00, 0x00, | |
4181 0x0A, 'f', 'i', 'n', | |
4182 'a', 'l', ' ', 'c', | |
4183 'e', 'r', 't', | |
4184 }; | |
4185 TestSpdyVisitor visitor(spdy_version_); | |
4186 visitor.use_compression_ = false; | |
4187 visitor.SimulateInFramer(kV3FrameData, arraysize(kV3FrameData)); | |
4188 EXPECT_EQ(0, visitor.error_count_); | |
4189 } | |
4190 | |
4191 TEST_P(SpdyFramerTest, ReadCredentialFrameFollowedByAnotherFrame) { | |
4192 if (!IsSpdy3()) { | |
4193 return; | |
4194 } | |
4195 SpdyFramer framer(spdy_version_); | |
4196 const unsigned char kV3FrameData[] = { // Also applies for V2. | |
4197 0x80, spdy_version_ch_, 0x00, 0x0A, | |
4198 0x00, 0x00, 0x00, 0x33, | |
4199 0x00, 0x03, 0x00, 0x00, | |
4200 0x00, 0x05, 'p', 'r', | |
4201 'o', 'o', 'f', 0x00, | |
4202 0x00, 0x00, 0x06, 'a', | |
4203 ' ', 'c', 'e', 'r', | |
4204 't', 0x00, 0x00, 0x00, | |
4205 0x0C, 'a', 'n', 'o', | |
4206 't', 'h', 'e', 'r', | |
4207 ' ', 'c', 'e', 'r', | |
4208 't', 0x00, 0x00, 0x00, | |
4209 0x0A, 'f', 'i', 'n', | |
4210 'a', 'l', ' ', 'c', | |
4211 'e', 'r', 't', | |
4212 }; | |
4213 TestSpdyVisitor visitor(spdy_version_); | |
4214 visitor.use_compression_ = false; | |
4215 string multiple_frame_data(reinterpret_cast<const char*>(kV3FrameData), | |
4216 arraysize(kV3FrameData)); | |
4217 scoped_ptr<SpdyFrame> control_frame( | |
4218 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2))); | |
4219 multiple_frame_data.append(string(control_frame->data(), | |
4220 control_frame->size())); | |
4221 visitor.SimulateInFramer( | |
4222 reinterpret_cast<unsigned const char*>(multiple_frame_data.data()), | |
4223 multiple_frame_data.length()); | |
4224 EXPECT_EQ(0, visitor.error_count_); | |
4225 EXPECT_EQ(1u, visitor.last_window_update_stream_); | |
4226 EXPECT_EQ(2u, visitor.last_window_update_delta_); | |
4227 } | |
4228 | |
4229 TEST_P(SpdyFramerTest, ReadCompressedPushPromise) { | |
4230 if (spdy_version_ <= SPDY3) { | |
4231 return; | |
4232 } | |
4233 | |
4234 SpdyFramer framer(spdy_version_); | |
4235 SpdyPushPromiseIR push_promise(42, 57); | |
4236 push_promise.SetHeader("foo", "bar"); | |
4237 push_promise.SetHeader("bar", "foofoo"); | |
4238 SpdyHeaderBlock headers = push_promise.name_value_block(); | |
4239 scoped_ptr<SpdySerializedFrame> frame( | |
4240 framer.SerializePushPromise(push_promise)); | |
4241 EXPECT_TRUE(frame.get() != NULL); | |
4242 TestSpdyVisitor visitor(spdy_version_); | |
4243 visitor.use_compression_ = true; | |
4244 visitor.SimulateInFramer( | |
4245 reinterpret_cast<unsigned char*>(frame->data()), | |
4246 frame->size()); | |
4247 EXPECT_EQ(42u, visitor.last_push_promise_stream_); | |
4248 EXPECT_EQ(57u, visitor.last_push_promise_promised_stream_); | |
4249 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
4250 } | |
4251 | |
4252 TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) { | |
4253 if (spdy_version_ <= SPDY3) { | |
4254 return; | |
4255 } | |
4256 | |
4257 const unsigned char kInput[] = { | |
4258 0x00, 0x00, 0x14, 0x01, 0x08, // HEADERS: PADDED | |
4259 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4260 0x03, // Padding of 3. | |
4261 0x00, 0x06, 0x63, 0x6f, | |
4262 0x6f, 0x6b, 0x69, 0x65, | |
4263 0x07, 0x66, 0x6f, 0x6f, | |
4264 0x3d, 0x62, 0x61, 0x72, | |
4265 0x00, 0x00, 0x00, | |
4266 | |
4267 0x00, 0x00, 0x14, 0x09, 0x00, // CONTINUATION | |
4268 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4269 0x00, 0x06, 0x63, 0x6f, | |
4270 0x6f, 0x6b, 0x69, 0x65, | |
4271 0x08, 0x62, 0x61, 0x7a, | |
4272 0x3d, 0x62, 0x69, 0x6e, | |
4273 0x67, 0x00, 0x06, 0x63, | |
4274 | |
4275 0x00, 0x00, 0x12, 0x09, 0x04, // CONTINUATION: END_HEADERS | |
4276 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4277 0x6f, 0x6f, 0x6b, 0x69, | |
4278 0x65, 0x00, 0x00, 0x04, | |
4279 0x6e, 0x61, 0x6d, 0x65, | |
4280 0x05, 0x76, 0x61, 0x6c, | |
4281 0x75, 0x65, | |
4282 }; | |
4283 | |
4284 TestSpdyVisitor visitor(spdy_version_); | |
4285 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4286 | |
4287 EXPECT_EQ(0, visitor.error_count_); | |
4288 EXPECT_EQ(1, visitor.headers_frame_count_); | |
4289 EXPECT_EQ(2, visitor.continuation_count_); | |
4290 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
4291 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); | |
4292 | |
4293 EXPECT_THAT(visitor.headers_, | |
4294 testing::ElementsAre( | |
4295 testing::Pair("cookie", "foo=bar; baz=bing; "), | |
4296 testing::Pair("name", "value"))); | |
4297 } | |
4298 | |
4299 TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) { | |
4300 if (spdy_version_ <= SPDY3) { | |
4301 return; | |
4302 } | |
4303 | |
4304 const unsigned char kInput[] = { | |
4305 0x00, 0x00, 0x10, 0x01, 0x01, // HEADERS: FIN | |
4306 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4307 0x00, 0x06, 0x63, 0x6f, | |
4308 0x6f, 0x6b, 0x69, 0x65, | |
4309 0x07, 0x66, 0x6f, 0x6f, | |
4310 0x3d, 0x62, 0x61, 0x72, | |
4311 | |
4312 0x00, 0x00, 0x14, 0x09, 0x00, // CONTINUATION | |
4313 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4314 0x00, 0x06, 0x63, 0x6f, | |
4315 0x6f, 0x6b, 0x69, 0x65, | |
4316 0x08, 0x62, 0x61, 0x7a, | |
4317 0x3d, 0x62, 0x69, 0x6e, | |
4318 0x67, 0x00, 0x06, 0x63, | |
4319 | |
4320 0x00, 0x00, 0x12, 0x09, 0x04, // CONTINUATION: END_HEADERS | |
4321 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4322 0x6f, 0x6f, 0x6b, 0x69, | |
4323 0x65, 0x00, 0x00, 0x04, | |
4324 0x6e, 0x61, 0x6d, 0x65, | |
4325 0x05, 0x76, 0x61, 0x6c, | |
4326 0x75, 0x65, | |
4327 }; | |
4328 | |
4329 SpdyFramer framer(spdy_version_); | |
4330 TestSpdyVisitor visitor(spdy_version_); | |
4331 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4332 | |
4333 EXPECT_EQ(0, visitor.error_count_); | |
4334 EXPECT_EQ(1, visitor.headers_frame_count_); | |
4335 EXPECT_EQ(2, visitor.continuation_count_); | |
4336 EXPECT_EQ(1, visitor.fin_flag_count_); | |
4337 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
4338 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
4339 | |
4340 EXPECT_THAT(visitor.headers_, | |
4341 testing::ElementsAre( | |
4342 testing::Pair("cookie", "foo=bar; baz=bing; "), | |
4343 testing::Pair("name", "value"))); | |
4344 } | |
4345 | |
4346 TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) { | |
4347 if (spdy_version_ <= SPDY3) { | |
4348 return; | |
4349 } | |
4350 | |
4351 const unsigned char kInput[] = { | |
4352 0x00, 0x00, 0x17, 0x05, // PUSH_PROMISE | |
4353 0x08, 0x00, 0x00, 0x00, // PADDED | |
4354 0x01, 0x02, 0x00, 0x00, // Stream 1, Pad length field | |
4355 0x00, 0x2A, 0x00, 0x06, // Promised stream 42 | |
4356 0x63, 0x6f, 0x6f, 0x6b, | |
4357 0x69, 0x65, 0x07, 0x66, | |
4358 0x6f, 0x6f, 0x3d, 0x62, | |
4359 0x61, 0x72, 0x00, 0x00, | |
4360 | |
4361 0x00, 0x00, 0x14, 0x09, // CONTINUATION | |
4362 0x00, 0x00, 0x00, 0x00, | |
4363 0x01, 0x00, 0x06, 0x63, // Stream 1 | |
4364 0x6f, 0x6f, 0x6b, 0x69, | |
4365 0x65, 0x08, 0x62, 0x61, | |
4366 0x7a, 0x3d, 0x62, 0x69, | |
4367 0x6e, 0x67, 0x00, 0x06, | |
4368 0x63, | |
4369 | |
4370 0x00, 0x00, 0x12, 0x09, // CONTINUATION | |
4371 0x04, 0x00, 0x00, 0x00, // END_HEADERS | |
4372 0x01, 0x6f, 0x6f, 0x6b, // Stream 1 | |
4373 0x69, 0x65, 0x00, 0x00, | |
4374 0x04, 0x6e, 0x61, 0x6d, | |
4375 0x65, 0x05, 0x76, 0x61, | |
4376 0x6c, 0x75, 0x65, | |
4377 }; | |
4378 | |
4379 SpdyFramer framer(spdy_version_); | |
4380 TestSpdyVisitor visitor(spdy_version_); | |
4381 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4382 | |
4383 EXPECT_EQ(0, visitor.error_count_); | |
4384 EXPECT_EQ(1u, visitor.last_push_promise_stream_); | |
4385 EXPECT_EQ(42u, visitor.last_push_promise_promised_stream_); | |
4386 EXPECT_EQ(2, visitor.continuation_count_); | |
4387 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
4388 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); | |
4389 | |
4390 EXPECT_THAT(visitor.headers_, | |
4391 testing::ElementsAre( | |
4392 testing::Pair("cookie", "foo=bar; baz=bing; "), | |
4393 testing::Pair("name", "value"))); | |
4394 } | |
4395 | |
4396 TEST_P(SpdyFramerTest, ReadContinuationWithWrongStreamId) { | |
4397 if (spdy_version_ <= SPDY3) { | |
4398 return; | |
4399 } | |
4400 | |
4401 const unsigned char kInput[] = { | |
4402 0x00, 0x00, 0x10, 0x01, 0x00, // HEADERS | |
4403 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4404 0x00, 0x06, 0x63, 0x6f, | |
4405 0x6f, 0x6b, 0x69, 0x65, | |
4406 0x07, 0x66, 0x6f, 0x6f, | |
4407 0x3d, 0x62, 0x61, 0x72, | |
4408 | |
4409 0x00, 0x00, 0x14, 0x09, 0x00, // CONTINUATION | |
4410 0x00, 0x00, 0x00, 0x02, // Stream 2 | |
4411 0x00, 0x06, 0x63, 0x6f, | |
4412 0x6f, 0x6b, 0x69, 0x65, | |
4413 0x08, 0x62, 0x61, 0x7a, | |
4414 0x3d, 0x62, 0x69, 0x6e, | |
4415 0x67, 0x00, 0x06, 0x63, | |
4416 }; | |
4417 | |
4418 SpdyFramer framer(spdy_version_); | |
4419 TestSpdyVisitor visitor(spdy_version_); | |
4420 framer.set_visitor(&visitor); | |
4421 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4422 | |
4423 EXPECT_EQ(1, visitor.error_count_); | |
4424 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
4425 visitor.framer_.error_code()) | |
4426 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4427 EXPECT_EQ(1, visitor.headers_frame_count_); | |
4428 EXPECT_EQ(0, visitor.continuation_count_); | |
4429 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
4430 } | |
4431 | |
4432 TEST_P(SpdyFramerTest, ReadContinuationOutOfOrder) { | |
4433 if (spdy_version_ <= SPDY3) { | |
4434 return; | |
4435 } | |
4436 | |
4437 const unsigned char kInput[] = { | |
4438 0x00, 0x00, 0x18, 0x09, 0x00, // CONTINUATION | |
4439 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4440 0x00, 0x06, 0x63, 0x6f, | |
4441 0x6f, 0x6b, 0x69, 0x65, | |
4442 0x07, 0x66, 0x6f, 0x6f, | |
4443 0x3d, 0x62, 0x61, 0x72, | |
4444 }; | |
4445 | |
4446 SpdyFramer framer(spdy_version_); | |
4447 TestSpdyVisitor visitor(spdy_version_); | |
4448 framer.set_visitor(&visitor); | |
4449 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4450 | |
4451 EXPECT_EQ(1, visitor.error_count_); | |
4452 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
4453 visitor.framer_.error_code()) | |
4454 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4455 EXPECT_EQ(0, visitor.continuation_count_); | |
4456 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
4457 } | |
4458 | |
4459 TEST_P(SpdyFramerTest, ExpectContinuationReceiveData) { | |
4460 if (spdy_version_ <= SPDY3) { | |
4461 return; | |
4462 } | |
4463 | |
4464 const unsigned char kInput[] = { | |
4465 0x00, 0x00, 0x10, 0x01, 0x00, // HEADERS | |
4466 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4467 0x00, 0x06, 0x63, 0x6f, | |
4468 0x6f, 0x6b, 0x69, 0x65, | |
4469 0x07, 0x66, 0x6f, 0x6f, | |
4470 0x3d, 0x62, 0x61, 0x72, | |
4471 | |
4472 0x00, 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
4473 0x00, 0x00, 0x00, 0x04, | |
4474 0xde, 0xad, 0xbe, 0xef, | |
4475 }; | |
4476 | |
4477 SpdyFramer framer(spdy_version_); | |
4478 TestSpdyVisitor visitor(spdy_version_); | |
4479 framer.set_visitor(&visitor); | |
4480 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4481 | |
4482 EXPECT_EQ(1, visitor.error_count_); | |
4483 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
4484 visitor.framer_.error_code()) | |
4485 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4486 EXPECT_EQ(1, visitor.headers_frame_count_); | |
4487 EXPECT_EQ(0, visitor.continuation_count_); | |
4488 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
4489 EXPECT_EQ(0, visitor.data_frame_count_); | |
4490 } | |
4491 | |
4492 TEST_P(SpdyFramerTest, ExpectContinuationReceiveControlFrame) { | |
4493 if (spdy_version_ <= SPDY3) { | |
4494 return; | |
4495 } | |
4496 | |
4497 const unsigned char kInput[] = { | |
4498 0x00, 0x00, 0x18, 0x01, 0x00, // HEADERS | |
4499 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4500 0x00, 0x06, 0x63, 0x6f, | |
4501 0x6f, 0x6b, 0x69, 0x65, | |
4502 0x07, 0x66, 0x6f, 0x6f, | |
4503 0x3d, 0x62, 0x61, 0x72, | |
4504 | |
4505 0x00, 0x00, 0x1c, 0x08, 0x00, // HEADERS | |
4506 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4507 0x00, 0x06, 0x63, 0x6f, // (Note this is a valid continued encoding). | |
4508 0x6f, 0x6b, 0x69, 0x65, | |
4509 0x08, 0x62, 0x61, 0x7a, | |
4510 0x3d, 0x62, 0x69, 0x6e, | |
4511 0x67, 0x00, 0x06, 0x63, | |
4512 }; | |
4513 | |
4514 SpdyFramer framer(spdy_version_); | |
4515 TestSpdyVisitor visitor(spdy_version_); | |
4516 framer.set_visitor(&visitor); | |
4517 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4518 | |
4519 EXPECT_EQ(1, visitor.error_count_); | |
4520 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
4521 visitor.framer_.error_code()) | |
4522 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4523 EXPECT_EQ(1, visitor.headers_frame_count_); | |
4524 EXPECT_EQ(0, visitor.continuation_count_); | |
4525 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
4526 EXPECT_EQ(0, visitor.data_frame_count_); | |
4527 } | |
4528 | |
4529 TEST_P(SpdyFramerTest, EndSegmentOnDataFrame) { | |
4530 if (spdy_version_ <= SPDY3) { | |
4531 return; | |
4532 } | |
4533 const unsigned char kInput[] = { | |
4534 0x00, 0x00, 0x0c, 0x00, 0x02, // DATA: END_SEGMENT | |
4535 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4536 0xde, 0xad, 0xbe, 0xef, | |
4537 0xde, 0xad, 0xbe, 0xef, | |
4538 0xde, 0xad, 0xbe, 0xef, | |
4539 }; | |
4540 | |
4541 TestSpdyVisitor visitor(spdy_version_); | |
4542 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4543 | |
4544 // TODO(jgraettinger): Verify END_SEGMENT when support is added. | |
4545 EXPECT_EQ(0, visitor.error_count_); | |
4546 EXPECT_EQ(12, visitor.data_bytes_); | |
4547 EXPECT_EQ(0, visitor.fin_frame_count_); | |
4548 EXPECT_EQ(0, visitor.fin_flag_count_); | |
4549 } | |
4550 | |
4551 TEST_P(SpdyFramerTest, EndSegmentOnHeadersFrame) { | |
4552 if (spdy_version_ <= SPDY3) { | |
4553 return; | |
4554 } | |
4555 const unsigned char kInput[] = { | |
4556 0x00, 0x00, 0x10, 0x01, 0x06, // HEADERS: END_SEGMENT | END_HEADERS | |
4557 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4558 0x00, 0x06, 0x63, 0x6f, | |
4559 0x6f, 0x6b, 0x69, 0x65, | |
4560 0x07, 0x66, 0x6f, 0x6f, | |
4561 0x3d, 0x62, 0x61, 0x72, | |
4562 }; | |
4563 | |
4564 TestSpdyVisitor visitor(spdy_version_); | |
4565 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
4566 | |
4567 // TODO(jgraettinger): Verify END_SEGMENT when support is added. | |
4568 EXPECT_EQ(0, visitor.error_count_); | |
4569 EXPECT_EQ(1, visitor.headers_frame_count_); | |
4570 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); | |
4571 | |
4572 EXPECT_THAT(visitor.headers_, | |
4573 testing::ElementsAre(testing::Pair("cookie", "foo=bar"))); | |
4574 } | |
4575 | |
4576 TEST_P(SpdyFramerTest, ReadGarbage) { | |
4577 SpdyFramer framer(spdy_version_); | |
4578 unsigned char garbage_frame[256]; | |
4579 memset(garbage_frame, ~0, sizeof(garbage_frame)); | |
4580 TestSpdyVisitor visitor(spdy_version_); | |
4581 visitor.use_compression_ = false; | |
4582 visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame)); | |
4583 EXPECT_EQ(1, visitor.error_count_); | |
4584 } | |
4585 | |
4586 TEST_P(SpdyFramerTest, ReadUnknownExtensionFrame) { | |
4587 if (spdy_version_ <= SPDY3) { | |
4588 return; | |
4589 } | |
4590 SpdyFramer framer(spdy_version_); | |
4591 | |
4592 // The unrecognized frame type should still have a valid length. | |
4593 const unsigned char unknown_frame[] = { | |
4594 0x00, 0x00, 0x08, 0xff, 0xff, | |
4595 0xff, 0xff, 0xff, 0xff, | |
4596 0xff, 0xff, 0xff, 0xff, | |
4597 0xff, 0xff, 0xff, 0xff, | |
4598 }; | |
4599 TestSpdyVisitor visitor(spdy_version_); | |
4600 | |
4601 // Simulate the case where the stream id validation checks out. | |
4602 visitor.on_unknown_frame_result_ = true; | |
4603 visitor.use_compression_ = false; | |
4604 visitor.SimulateInFramer(unknown_frame, arraysize(unknown_frame)); | |
4605 EXPECT_EQ(0, visitor.error_count_); | |
4606 | |
4607 // Follow it up with a valid control frame to make sure we handle | |
4608 // subsequent frames correctly. | |
4609 SpdySettingsIR settings_ir; | |
4610 settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 1), | |
4611 false, // persist | |
4612 false, // persisted | |
4613 10); | |
4614 scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir)); | |
4615 visitor.SimulateInFramer( | |
4616 reinterpret_cast<unsigned char*>(control_frame->data()), | |
4617 control_frame->size()); | |
4618 EXPECT_EQ(0, visitor.error_count_); | |
4619 EXPECT_EQ(1u, static_cast<unsigned>(visitor.setting_count_)); | |
4620 EXPECT_EQ(1u, static_cast<unsigned>(visitor.settings_ack_sent_)); | |
4621 } | |
4622 | |
4623 TEST_P(SpdyFramerTest, ReadGarbageWithValidLength) { | |
4624 if (!IsSpdy4()) { | |
4625 return; | |
4626 } | |
4627 SpdyFramer framer(spdy_version_); | |
4628 const unsigned char kFrameData[] = { | |
4629 0x00, 0x00, 0x08, 0xff, 0xff, | |
4630 0xff, 0xff, 0xff, 0xff, | |
4631 0xff, 0xff, 0xff, 0xff, | |
4632 0xff, 0xff, 0xff, 0xff, | |
4633 }; | |
4634 TestSpdyVisitor visitor(spdy_version_); | |
4635 visitor.use_compression_ = false; | |
4636 visitor.SimulateInFramer(kFrameData, arraysize(kFrameData)); | |
4637 EXPECT_EQ(1, visitor.error_count_); | |
4638 } | |
4639 | |
4640 TEST_P(SpdyFramerTest, ReadGarbageWithValidVersion) { | |
4641 if (IsSpdy4()) { | |
4642 // Not valid for SPDY 4 since there is no version field. | |
4643 return; | |
4644 } | |
4645 SpdyFramer framer(spdy_version_); | |
4646 const unsigned char kFrameData[] = { | |
4647 0x80, spdy_version_ch_, 0xff, 0xff, | |
4648 0xff, 0xff, 0xff, 0xff, | |
4649 }; | |
4650 TestSpdyVisitor visitor(spdy_version_); | |
4651 visitor.use_compression_ = false; | |
4652 visitor.SimulateInFramer(kFrameData, arraysize(kFrameData)); | |
4653 EXPECT_EQ(1, visitor.error_count_); | |
4654 } | |
4655 | |
4656 TEST_P(SpdyFramerTest, ReadGarbageHPACKEncoding) { | |
4657 if (spdy_version_ <= SPDY3) { | |
4658 return; | |
4659 } | |
4660 const unsigned char kInput[] = { | |
4661 0x00, 0x12, 0x01, 0x04, // HEADER: END_HEADERS | |
4662 0x00, 0x00, 0x00, 0x01, // Stream 1 | |
4663 0xef, 0xef, 0xff, 0xff, | |
4664 0xff, 0xff, 0xff, 0xff, | |
4665 0xff, 0xff, 0xff, 0xff, | |
4666 0xff, 0xff, 0xff, 0xff, | |
4667 0xff, 0xff, | |
4668 }; | |
4669 | |
4670 TestSpdyVisitor visitor(spdy_version_); | |
4671 visitor.SimulateInFramer(kInput, arraysize(kInput)); | |
4672 EXPECT_EQ(1, visitor.error_count_); | |
4673 } | |
4674 | |
4675 TEST_P(SpdyFramerTest, SizesTest) { | |
4676 SpdyFramer framer(spdy_version_); | |
4677 if (IsSpdy4()) { | |
4678 EXPECT_EQ(9u, framer.GetDataFrameMinimumSize()); | |
4679 EXPECT_EQ(9u, framer.GetControlFrameHeaderSize()); | |
4680 EXPECT_EQ(14u, framer.GetSynStreamMinimumSize()); | |
4681 EXPECT_EQ(9u, framer.GetSynReplyMinimumSize()); | |
4682 EXPECT_EQ(13u, framer.GetRstStreamMinimumSize()); | |
4683 EXPECT_EQ(9u, framer.GetSettingsMinimumSize()); | |
4684 EXPECT_EQ(17u, framer.GetPingSize()); | |
4685 EXPECT_EQ(17u, framer.GetGoAwayMinimumSize()); | |
4686 EXPECT_EQ(9u, framer.GetHeadersMinimumSize()); | |
4687 EXPECT_EQ(13u, framer.GetWindowUpdateSize()); | |
4688 EXPECT_EQ(9u, framer.GetBlockedSize()); | |
4689 EXPECT_EQ(13u, framer.GetPushPromiseMinimumSize()); | |
4690 EXPECT_EQ(18u, framer.GetAltSvcMinimumSize()); | |
4691 EXPECT_EQ(9u, framer.GetFrameMinimumSize()); | |
4692 EXPECT_EQ(16393u, framer.GetFrameMaximumSize()); | |
4693 EXPECT_EQ(16384u, framer.GetDataFrameMaximumPayload()); | |
4694 } else { | |
4695 EXPECT_EQ(8u, framer.GetDataFrameMinimumSize()); | |
4696 EXPECT_EQ(8u, framer.GetControlFrameHeaderSize()); | |
4697 EXPECT_EQ(18u, framer.GetSynStreamMinimumSize()); | |
4698 EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetSynReplyMinimumSize()); | |
4699 EXPECT_EQ(16u, framer.GetRstStreamMinimumSize()); | |
4700 EXPECT_EQ(12u, framer.GetSettingsMinimumSize()); | |
4701 EXPECT_EQ(12u, framer.GetPingSize()); | |
4702 EXPECT_EQ(IsSpdy2() ? 12u : 16u, framer.GetGoAwayMinimumSize()); | |
4703 EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetHeadersMinimumSize()); | |
4704 EXPECT_EQ(16u, framer.GetWindowUpdateSize()); | |
4705 EXPECT_EQ(8u, framer.GetFrameMinimumSize()); | |
4706 EXPECT_EQ(16777223u, framer.GetFrameMaximumSize()); | |
4707 EXPECT_EQ(16777215u, framer.GetDataFrameMaximumPayload()); | |
4708 } | |
4709 } | |
4710 | |
4711 TEST_P(SpdyFramerTest, StateToStringTest) { | |
4712 EXPECT_STREQ("ERROR", | |
4713 SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR)); | |
4714 EXPECT_STREQ("AUTO_RESET", | |
4715 SpdyFramer::StateToString(SpdyFramer::SPDY_AUTO_RESET)); | |
4716 EXPECT_STREQ("RESET", | |
4717 SpdyFramer::StateToString(SpdyFramer::SPDY_RESET)); | |
4718 EXPECT_STREQ("READING_COMMON_HEADER", | |
4719 SpdyFramer::StateToString( | |
4720 SpdyFramer::SPDY_READING_COMMON_HEADER)); | |
4721 EXPECT_STREQ("CONTROL_FRAME_PAYLOAD", | |
4722 SpdyFramer::StateToString( | |
4723 SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD)); | |
4724 EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD", | |
4725 SpdyFramer::StateToString( | |
4726 SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD)); | |
4727 EXPECT_STREQ("FORWARD_STREAM_FRAME", | |
4728 SpdyFramer::StateToString( | |
4729 SpdyFramer::SPDY_FORWARD_STREAM_FRAME)); | |
4730 EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK", | |
4731 SpdyFramer::StateToString( | |
4732 SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK)); | |
4733 EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK", | |
4734 SpdyFramer::StateToString( | |
4735 SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK)); | |
4736 EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD", | |
4737 SpdyFramer::StateToString( | |
4738 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD)); | |
4739 EXPECT_STREQ("SPDY_ALTSVC_FRAME_PAYLOAD", | |
4740 SpdyFramer::StateToString( | |
4741 SpdyFramer::SPDY_ALTSVC_FRAME_PAYLOAD)); | |
4742 EXPECT_STREQ("UNKNOWN_STATE", | |
4743 SpdyFramer::StateToString( | |
4744 SpdyFramer::SPDY_ALTSVC_FRAME_PAYLOAD + 1)); | |
4745 } | |
4746 | |
4747 TEST_P(SpdyFramerTest, ErrorCodeToStringTest) { | |
4748 EXPECT_STREQ("NO_ERROR", | |
4749 SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR)); | |
4750 EXPECT_STREQ("INVALID_CONTROL_FRAME", | |
4751 SpdyFramer::ErrorCodeToString( | |
4752 SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); | |
4753 EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE", | |
4754 SpdyFramer::ErrorCodeToString( | |
4755 SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); | |
4756 EXPECT_STREQ("ZLIB_INIT_FAILURE", | |
4757 SpdyFramer::ErrorCodeToString( | |
4758 SpdyFramer::SPDY_ZLIB_INIT_FAILURE)); | |
4759 EXPECT_STREQ("UNSUPPORTED_VERSION", | |
4760 SpdyFramer::ErrorCodeToString( | |
4761 SpdyFramer::SPDY_UNSUPPORTED_VERSION)); | |
4762 EXPECT_STREQ("DECOMPRESS_FAILURE", | |
4763 SpdyFramer::ErrorCodeToString( | |
4764 SpdyFramer::SPDY_DECOMPRESS_FAILURE)); | |
4765 EXPECT_STREQ("COMPRESS_FAILURE", | |
4766 SpdyFramer::ErrorCodeToString( | |
4767 SpdyFramer::SPDY_COMPRESS_FAILURE)); | |
4768 EXPECT_STREQ("SPDY_INVALID_DATA_FRAME_FLAGS", | |
4769 SpdyFramer::ErrorCodeToString( | |
4770 SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS)); | |
4771 EXPECT_STREQ("SPDY_INVALID_CONTROL_FRAME_FLAGS", | |
4772 SpdyFramer::ErrorCodeToString( | |
4773 SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS)); | |
4774 EXPECT_STREQ("UNKNOWN_ERROR", | |
4775 SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR)); | |
4776 } | |
4777 | |
4778 TEST_P(SpdyFramerTest, StatusCodeToStringTest) { | |
4779 EXPECT_STREQ("INVALID", | |
4780 SpdyFramer::StatusCodeToString(RST_STREAM_INVALID)); | |
4781 EXPECT_STREQ("PROTOCOL_ERROR", | |
4782 SpdyFramer::StatusCodeToString(RST_STREAM_PROTOCOL_ERROR)); | |
4783 EXPECT_STREQ("INVALID_STREAM", | |
4784 SpdyFramer::StatusCodeToString(RST_STREAM_INVALID_STREAM)); | |
4785 EXPECT_STREQ("REFUSED_STREAM", | |
4786 SpdyFramer::StatusCodeToString(RST_STREAM_REFUSED_STREAM)); | |
4787 EXPECT_STREQ("UNSUPPORTED_VERSION", | |
4788 SpdyFramer::StatusCodeToString(RST_STREAM_UNSUPPORTED_VERSION)); | |
4789 EXPECT_STREQ("CANCEL", | |
4790 SpdyFramer::StatusCodeToString(RST_STREAM_CANCEL)); | |
4791 EXPECT_STREQ("INTERNAL_ERROR", | |
4792 SpdyFramer::StatusCodeToString(RST_STREAM_INTERNAL_ERROR)); | |
4793 EXPECT_STREQ("FLOW_CONTROL_ERROR", | |
4794 SpdyFramer::StatusCodeToString(RST_STREAM_FLOW_CONTROL_ERROR)); | |
4795 EXPECT_STREQ("UNKNOWN_STATUS", | |
4796 SpdyFramer::StatusCodeToString(-1)); | |
4797 } | |
4798 | |
4799 TEST_P(SpdyFramerTest, FrameTypeToStringTest) { | |
4800 EXPECT_STREQ("DATA", | |
4801 SpdyFramer::FrameTypeToString(DATA)); | |
4802 EXPECT_STREQ("SYN_STREAM", | |
4803 SpdyFramer::FrameTypeToString(SYN_STREAM)); | |
4804 EXPECT_STREQ("SYN_REPLY", | |
4805 SpdyFramer::FrameTypeToString(SYN_REPLY)); | |
4806 EXPECT_STREQ("RST_STREAM", | |
4807 SpdyFramer::FrameTypeToString(RST_STREAM)); | |
4808 EXPECT_STREQ("SETTINGS", | |
4809 SpdyFramer::FrameTypeToString(SETTINGS)); | |
4810 EXPECT_STREQ("PING", | |
4811 SpdyFramer::FrameTypeToString(PING)); | |
4812 EXPECT_STREQ("GOAWAY", | |
4813 SpdyFramer::FrameTypeToString(GOAWAY)); | |
4814 EXPECT_STREQ("HEADERS", | |
4815 SpdyFramer::FrameTypeToString(HEADERS)); | |
4816 EXPECT_STREQ("WINDOW_UPDATE", | |
4817 SpdyFramer::FrameTypeToString(WINDOW_UPDATE)); | |
4818 EXPECT_STREQ("PUSH_PROMISE", | |
4819 SpdyFramer::FrameTypeToString(PUSH_PROMISE)); | |
4820 EXPECT_STREQ("CREDENTIAL", | |
4821 SpdyFramer::FrameTypeToString(CREDENTIAL)); | |
4822 EXPECT_STREQ("CONTINUATION", | |
4823 SpdyFramer::FrameTypeToString(CONTINUATION)); | |
4824 } | |
4825 | |
4826 TEST_P(SpdyFramerTest, CatchProbableHttpResponse) { | |
4827 if (IsSpdy4()) { | |
4828 // TODO(hkhalil): catch probable HTTP response in SPDY 4? | |
4829 return; | |
4830 } | |
4831 { | |
4832 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4833 SpdyFramer framer(spdy_version_); | |
4834 framer.set_visitor(&visitor); | |
4835 | |
4836 EXPECT_CALL(visitor, OnError(_)); | |
4837 framer.ProcessInput("HTTP/1.1", 8); | |
4838 EXPECT_TRUE(framer.probable_http_response()); | |
4839 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
4840 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code()) | |
4841 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4842 } | |
4843 { | |
4844 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4845 SpdyFramer framer(spdy_version_); | |
4846 framer.set_visitor(&visitor); | |
4847 | |
4848 EXPECT_CALL(visitor, OnError(_)); | |
4849 framer.ProcessInput("HTTP/1.0", 8); | |
4850 EXPECT_TRUE(framer.probable_http_response()); | |
4851 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
4852 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code()) | |
4853 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4854 } | |
4855 } | |
4856 | |
4857 TEST_P(SpdyFramerTest, DataFrameFlagsV2V3) { | |
4858 if (spdy_version_ > SPDY3) { | |
4859 return; | |
4860 } | |
4861 | |
4862 uint8 flags = 0; | |
4863 do { | |
4864 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
4865 | |
4866 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4867 SpdyFramer framer(spdy_version_); | |
4868 framer.set_visitor(&visitor); | |
4869 | |
4870 SpdyDataIR data_ir(1, StringPiece("hello", 5)); | |
4871 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
4872 SetFrameFlags(frame.get(), flags, spdy_version_); | |
4873 | |
4874 if (flags & ~DATA_FLAG_FIN) { | |
4875 EXPECT_CALL(visitor, OnError(_)); | |
4876 } else { | |
4877 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN)); | |
4878 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false)); | |
4879 if (flags & DATA_FLAG_FIN) { | |
4880 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); | |
4881 } | |
4882 } | |
4883 | |
4884 framer.ProcessInput(frame->data(), frame->size()); | |
4885 if (flags & ~DATA_FLAG_FIN) { | |
4886 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
4887 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, | |
4888 framer.error_code()) | |
4889 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4890 } else { | |
4891 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
4892 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
4893 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4894 } | |
4895 } while (++flags != 0); | |
4896 } | |
4897 | |
4898 TEST_P(SpdyFramerTest, DataFrameFlagsV4) { | |
4899 if (spdy_version_ <= SPDY3) { | |
4900 return; | |
4901 } | |
4902 | |
4903 uint8 valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT | | |
4904 DATA_FLAG_PADDED; | |
4905 | |
4906 uint8 flags = 0; | |
4907 do { | |
4908 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
4909 | |
4910 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4911 SpdyFramer framer(spdy_version_); | |
4912 framer.set_visitor(&visitor); | |
4913 | |
4914 SpdyDataIR data_ir(1, StringPiece("hello", 5)); | |
4915 scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); | |
4916 SetFrameFlags(frame.get(), flags, spdy_version_); | |
4917 | |
4918 if (flags & ~valid_data_flags) { | |
4919 EXPECT_CALL(visitor, OnError(_)); | |
4920 } else { | |
4921 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN)); | |
4922 if (flags & DATA_FLAG_PADDED) { | |
4923 // Expect Error since we don't set padded in payload. | |
4924 EXPECT_CALL(visitor, OnError(_)); | |
4925 } else { | |
4926 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false)); | |
4927 if (flags & DATA_FLAG_FIN) { | |
4928 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); | |
4929 } | |
4930 } | |
4931 } | |
4932 | |
4933 framer.ProcessInput(frame->data(), frame->size()); | |
4934 if ((flags & ~valid_data_flags) || (flags & DATA_FLAG_PADDED)) { | |
4935 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
4936 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, | |
4937 framer.error_code()) | |
4938 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4939 } else { | |
4940 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
4941 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
4942 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4943 } | |
4944 } while (++flags != 0); | |
4945 } | |
4946 | |
4947 TEST_P(SpdyFramerTest, SynStreamFrameFlags) { | |
4948 if (!IsSpdy2() && !IsSpdy3()) { | |
4949 // SYN_STREAM not supported in SPDY>3 | |
4950 return; | |
4951 } | |
4952 uint8 flags = 0; | |
4953 do { | |
4954 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
4955 | |
4956 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4957 testing::StrictMock<test::MockDebugVisitor> debug_visitor; | |
4958 SpdyFramer framer(spdy_version_); | |
4959 framer.set_visitor(&visitor); | |
4960 framer.set_debug_visitor(&debug_visitor); | |
4961 | |
4962 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(8, SYN_STREAM, _, _)); | |
4963 | |
4964 SpdySynStreamIR syn_stream(8); | |
4965 syn_stream.set_associated_to_stream_id(3); | |
4966 syn_stream.set_priority(1); | |
4967 syn_stream.SetHeader("foo", "bar"); | |
4968 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); | |
4969 SetFrameFlags(frame.get(), flags, spdy_version_); | |
4970 | |
4971 if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) { | |
4972 EXPECT_CALL(visitor, OnError(_)); | |
4973 } else { | |
4974 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(8, SYN_STREAM, _)); | |
4975 EXPECT_CALL(visitor, OnSynStream(8, 3, 1, flags & CONTROL_FLAG_FIN, | |
4976 flags & CONTROL_FLAG_UNIDIRECTIONAL)); | |
4977 EXPECT_CALL(visitor, OnControlFrameHeaderData(8, _, _)) | |
4978 .WillRepeatedly(testing::Return(true)); | |
4979 if (flags & DATA_FLAG_FIN) { | |
4980 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); | |
4981 } else { | |
4982 // Do not close the stream if we are expecting a CONTINUATION frame. | |
4983 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)).Times(0); | |
4984 } | |
4985 } | |
4986 | |
4987 framer.ProcessInput(frame->data(), frame->size()); | |
4988 if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) { | |
4989 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
4990 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
4991 framer.error_code()) | |
4992 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4993 } else { | |
4994 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
4995 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
4996 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
4997 } | |
4998 } while (++flags != 0); | |
4999 } | |
5000 | |
5001 TEST_P(SpdyFramerTest, SynReplyFrameFlags) { | |
5002 if (!IsSpdy2() && !IsSpdy3()) { | |
5003 // SYN_REPLY not supported in SPDY>3 | |
5004 return; | |
5005 } | |
5006 uint8 flags = 0; | |
5007 do { | |
5008 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5009 | |
5010 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5011 SpdyFramer framer(spdy_version_); | |
5012 framer.set_visitor(&visitor); | |
5013 | |
5014 SpdySynReplyIR syn_reply(37); | |
5015 syn_reply.SetHeader("foo", "bar"); | |
5016 scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply)); | |
5017 SetFrameFlags(frame.get(), flags, spdy_version_); | |
5018 | |
5019 if (flags & ~CONTROL_FLAG_FIN) { | |
5020 EXPECT_CALL(visitor, OnError(_)); | |
5021 } else { | |
5022 EXPECT_CALL(visitor, OnSynReply(37, flags & CONTROL_FLAG_FIN)); | |
5023 EXPECT_CALL(visitor, OnControlFrameHeaderData(37, _, _)) | |
5024 .WillRepeatedly(testing::Return(true)); | |
5025 if (flags & DATA_FLAG_FIN) { | |
5026 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); | |
5027 } | |
5028 } | |
5029 | |
5030 framer.ProcessInput(frame->data(), frame->size()); | |
5031 if (flags & ~CONTROL_FLAG_FIN) { | |
5032 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5033 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5034 framer.error_code()) | |
5035 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5036 } else { | |
5037 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5038 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5039 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5040 } | |
5041 } while (++flags != 0); | |
5042 } | |
5043 | |
5044 TEST_P(SpdyFramerTest, RstStreamFrameFlags) { | |
5045 uint8 flags = 0; | |
5046 do { | |
5047 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5048 | |
5049 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5050 SpdyFramer framer(spdy_version_); | |
5051 framer.set_visitor(&visitor); | |
5052 | |
5053 SpdyRstStreamIR rst_stream(13, RST_STREAM_CANCEL, ""); | |
5054 scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream)); | |
5055 SetFrameFlags(frame.get(), flags, spdy_version_); | |
5056 | |
5057 if (flags != 0) { | |
5058 EXPECT_CALL(visitor, OnError(_)); | |
5059 } else { | |
5060 EXPECT_CALL(visitor, OnRstStream(13, RST_STREAM_CANCEL)); | |
5061 } | |
5062 | |
5063 framer.ProcessInput(frame->data(), frame->size()); | |
5064 if (flags != 0) { | |
5065 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5066 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5067 framer.error_code()) | |
5068 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5069 } else { | |
5070 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5071 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5072 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5073 } | |
5074 } while (++flags != 0); | |
5075 } | |
5076 | |
5077 TEST_P(SpdyFramerTest, SettingsFrameFlagsOldFormat) { | |
5078 if (spdy_version_ > SPDY3) { return; } | |
5079 uint8 flags = 0; | |
5080 do { | |
5081 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5082 | |
5083 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5084 SpdyFramer framer(spdy_version_); | |
5085 framer.set_visitor(&visitor); | |
5086 | |
5087 SpdySettingsIR settings_ir; | |
5088 settings_ir.AddSetting(SETTINGS_UPLOAD_BANDWIDTH, | |
5089 false, | |
5090 false, | |
5091 54321); | |
5092 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir)); | |
5093 SetFrameFlags(frame.get(), flags, spdy_version_); | |
5094 | |
5095 if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) { | |
5096 EXPECT_CALL(visitor, OnError(_)); | |
5097 } else { | |
5098 EXPECT_CALL(visitor, OnSettings( | |
5099 flags & SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS)); | |
5100 EXPECT_CALL(visitor, OnSetting(SETTINGS_UPLOAD_BANDWIDTH, | |
5101 SETTINGS_FLAG_NONE, 54321)); | |
5102 EXPECT_CALL(visitor, OnSettingsEnd()); | |
5103 } | |
5104 | |
5105 framer.ProcessInput(frame->data(), frame->size()); | |
5106 if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) { | |
5107 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5108 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5109 framer.error_code()) | |
5110 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5111 } else { | |
5112 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5113 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5114 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5115 } | |
5116 } while (++flags != 0); | |
5117 } | |
5118 | |
5119 TEST_P(SpdyFramerTest, SettingsFrameFlags) { | |
5120 if (spdy_version_ <= SPDY3) { return; } | |
5121 uint8 flags = 0; | |
5122 do { | |
5123 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5124 | |
5125 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5126 SpdyFramer framer(spdy_version_); | |
5127 framer.set_visitor(&visitor); | |
5128 | |
5129 SpdySettingsIR settings_ir; | |
5130 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 0, 0, 16); | |
5131 scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir)); | |
5132 SetFrameFlags(frame.get(), flags, spdy_version_); | |
5133 | |
5134 if (flags != 0) { | |
5135 EXPECT_CALL(visitor, OnError(_)); | |
5136 } else { | |
5137 EXPECT_CALL(visitor, OnSettings(flags & SETTINGS_FLAG_ACK)); | |
5138 EXPECT_CALL(visitor, OnSetting(SETTINGS_INITIAL_WINDOW_SIZE, 0, 16)); | |
5139 EXPECT_CALL(visitor, OnSettingsEnd()); | |
5140 } | |
5141 | |
5142 framer.ProcessInput(frame->data(), frame->size()); | |
5143 if (flags & ~SETTINGS_FLAG_ACK) { | |
5144 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5145 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5146 framer.error_code()) | |
5147 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5148 } else if (flags & SETTINGS_FLAG_ACK) { | |
5149 // The frame is invalid because ACK frames should have no payload. | |
5150 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5151 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
5152 framer.error_code()) | |
5153 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5154 } else { | |
5155 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5156 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5157 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5158 } | |
5159 } while (++flags != 0); | |
5160 } | |
5161 | |
5162 TEST_P(SpdyFramerTest, GoawayFrameFlags) { | |
5163 uint8 flags = 0; | |
5164 do { | |
5165 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5166 | |
5167 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5168 SpdyFramer framer(spdy_version_); | |
5169 framer.set_visitor(&visitor); | |
5170 | |
5171 SpdyGoAwayIR goaway_ir(97, GOAWAY_OK, "test"); | |
5172 scoped_ptr<SpdyFrame> frame(framer.SerializeGoAway(goaway_ir)); | |
5173 SetFrameFlags(frame.get(), flags, spdy_version_); | |
5174 | |
5175 if (flags != 0) { | |
5176 EXPECT_CALL(visitor, OnError(_)); | |
5177 } else { | |
5178 EXPECT_CALL(visitor, OnGoAway(97, GOAWAY_OK)); | |
5179 } | |
5180 | |
5181 framer.ProcessInput(frame->data(), frame->size()); | |
5182 if (flags != 0) { | |
5183 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5184 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5185 framer.error_code()) | |
5186 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5187 } else { | |
5188 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5189 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5190 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5191 } | |
5192 } while (++flags != 0); | |
5193 } | |
5194 | |
5195 TEST_P(SpdyFramerTest, HeadersFrameFlags) { | |
5196 uint8 flags = 0; | |
5197 do { | |
5198 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5199 | |
5200 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5201 SpdyFramer framer(spdy_version_); | |
5202 framer.set_visitor(&visitor); | |
5203 | |
5204 SpdyHeadersIR headers_ir(57); | |
5205 if (IsSpdy4() && (flags & HEADERS_FLAG_PRIORITY)) { | |
5206 headers_ir.set_priority(3); | |
5207 headers_ir.set_has_priority(true); | |
5208 } | |
5209 headers_ir.SetHeader("foo", "bar"); | |
5210 scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); | |
5211 uint8 set_flags = flags; | |
5212 if (IsSpdy4()) { | |
5213 // TODO(jgraettinger): Add padding to SpdyHeadersIR, | |
5214 // and implement framing. | |
5215 set_flags &= ~HEADERS_FLAG_PADDED; | |
5216 } | |
5217 SetFrameFlags(frame.get(), set_flags, spdy_version_); | |
5218 | |
5219 if (!IsSpdy4() && flags & ~CONTROL_FLAG_FIN) { | |
5220 EXPECT_CALL(visitor, OnError(_)); | |
5221 } else if (IsSpdy4() && flags & ~(CONTROL_FLAG_FIN | | |
5222 HEADERS_FLAG_END_HEADERS | | |
5223 HEADERS_FLAG_END_SEGMENT | | |
5224 HEADERS_FLAG_PADDED | | |
5225 HEADERS_FLAG_PRIORITY)) { | |
5226 EXPECT_CALL(visitor, OnError(_)); | |
5227 } else { | |
5228 if (spdy_version_ > SPDY3 && flags & HEADERS_FLAG_PRIORITY) { | |
5229 EXPECT_CALL(visitor, OnHeaders(57, // stream id | |
5230 true, // has priority? | |
5231 3, // priority | |
5232 flags & CONTROL_FLAG_FIN, // fin? | |
5233 (flags & HEADERS_FLAG_END_HEADERS) || | |
5234 !IsSpdy4())); // end headers? | |
5235 } else { | |
5236 EXPECT_CALL(visitor, OnHeaders(57, false, 0, | |
5237 flags & CONTROL_FLAG_FIN, | |
5238 (flags & HEADERS_FLAG_END_HEADERS) || | |
5239 !IsSpdy4())); | |
5240 } | |
5241 EXPECT_CALL(visitor, OnControlFrameHeaderData(57, _, _)) | |
5242 .WillRepeatedly(testing::Return(true)); | |
5243 if (flags & DATA_FLAG_FIN && (!IsSpdy4() || | |
5244 flags & HEADERS_FLAG_END_HEADERS)) { | |
5245 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); | |
5246 } else { | |
5247 // Do not close the stream if we are expecting a CONTINUATION frame. | |
5248 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)).Times(0); | |
5249 } | |
5250 } | |
5251 | |
5252 framer.ProcessInput(frame->data(), frame->size()); | |
5253 if (!IsSpdy4() && flags & ~CONTROL_FLAG_FIN) { | |
5254 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5255 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5256 framer.error_code()) | |
5257 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5258 } else if (IsSpdy4() && flags & ~(CONTROL_FLAG_FIN | | |
5259 HEADERS_FLAG_END_HEADERS | | |
5260 HEADERS_FLAG_END_SEGMENT | | |
5261 HEADERS_FLAG_PADDED | | |
5262 HEADERS_FLAG_PRIORITY)) { | |
5263 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5264 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5265 framer.error_code()) | |
5266 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5267 } else if (IsSpdy4() && ~(flags & HEADERS_FLAG_END_HEADERS)) { | |
5268 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5269 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5270 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5271 } else { | |
5272 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5273 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5274 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5275 } | |
5276 } while (++flags != 0); | |
5277 } | |
5278 | |
5279 TEST_P(SpdyFramerTest, PingFrameFlags) { | |
5280 uint8 flags = 0; | |
5281 do { | |
5282 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5283 | |
5284 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5285 SpdyFramer framer(spdy_version_); | |
5286 framer.set_visitor(&visitor); | |
5287 | |
5288 scoped_ptr<SpdyFrame> frame(framer.SerializePing(SpdyPingIR(42))); | |
5289 SetFrameFlags(frame.get(), flags, spdy_version_); | |
5290 | |
5291 if (spdy_version_ > SPDY3 && | |
5292 flags == PING_FLAG_ACK) { | |
5293 EXPECT_CALL(visitor, OnPing(42, true)); | |
5294 } else if (flags == 0) { | |
5295 EXPECT_CALL(visitor, OnPing(42, false)); | |
5296 } else { | |
5297 EXPECT_CALL(visitor, OnError(_)); | |
5298 } | |
5299 | |
5300 framer.ProcessInput(frame->data(), frame->size()); | |
5301 if ((spdy_version_ > SPDY3 && flags == PING_FLAG_ACK) || | |
5302 flags == 0) { | |
5303 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5304 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5305 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5306 } else { | |
5307 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5308 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5309 framer.error_code()) | |
5310 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5311 } | |
5312 } while (++flags != 0); | |
5313 } | |
5314 | |
5315 TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) { | |
5316 uint8 flags = 0; | |
5317 do { | |
5318 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5319 | |
5320 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5321 SpdyFramer framer(spdy_version_); | |
5322 framer.set_visitor(&visitor); | |
5323 | |
5324 scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate( | |
5325 SpdyWindowUpdateIR(4, 1024))); | |
5326 SetFrameFlags(frame.get(), flags, spdy_version_); | |
5327 | |
5328 if (flags != 0) { | |
5329 EXPECT_CALL(visitor, OnError(_)); | |
5330 } else { | |
5331 EXPECT_CALL(visitor, OnWindowUpdate(4, 1024)); | |
5332 } | |
5333 | |
5334 framer.ProcessInput(frame->data(), frame->size()); | |
5335 if (flags != 0) { | |
5336 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5337 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5338 framer.error_code()) | |
5339 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5340 } else { | |
5341 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5342 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5343 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5344 } | |
5345 } while (++flags != 0); | |
5346 } | |
5347 | |
5348 TEST_P(SpdyFramerTest, PushPromiseFrameFlags) { | |
5349 if (spdy_version_ <= SPDY3) { | |
5350 return; | |
5351 } | |
5352 | |
5353 uint8 flags = 0; | |
5354 do { | |
5355 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5356 | |
5357 testing::StrictMock<net::test::MockSpdyFramerVisitor> visitor; | |
5358 testing::StrictMock<net::test::MockDebugVisitor> debug_visitor; | |
5359 SpdyFramer framer(spdy_version_); | |
5360 framer.set_visitor(&visitor); | |
5361 framer.set_debug_visitor(&debug_visitor); | |
5362 | |
5363 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(42, PUSH_PROMISE, _, _)); | |
5364 | |
5365 SpdyPushPromiseIR push_promise(42, 57); | |
5366 push_promise.SetHeader("foo", "bar"); | |
5367 scoped_ptr<SpdySerializedFrame> frame( | |
5368 framer.SerializePushPromise(push_promise)); | |
5369 // TODO(jgraettinger): Add padding to SpdyPushPromiseIR, | |
5370 // and implement framing. | |
5371 SetFrameFlags(frame.get(), flags & ~HEADERS_FLAG_PADDED, spdy_version_); | |
5372 | |
5373 if (flags & ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | HEADERS_FLAG_PADDED)) { | |
5374 EXPECT_CALL(visitor, OnError(_)); | |
5375 } else { | |
5376 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, PUSH_PROMISE, _)); | |
5377 EXPECT_CALL(visitor, OnPushPromise(42, 57, | |
5378 flags & PUSH_PROMISE_FLAG_END_PUSH_PROMISE)); | |
5379 EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _)) | |
5380 .WillRepeatedly(testing::Return(true)); | |
5381 } | |
5382 | |
5383 framer.ProcessInput(frame->data(), frame->size()); | |
5384 if (flags & ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | HEADERS_FLAG_PADDED)) { | |
5385 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5386 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5387 framer.error_code()) | |
5388 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5389 } else { | |
5390 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5391 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5392 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5393 } | |
5394 } while (++flags != 0); | |
5395 } | |
5396 | |
5397 TEST_P(SpdyFramerTest, ContinuationFrameFlags) { | |
5398 if (spdy_version_ <= SPDY3) { | |
5399 return; | |
5400 } | |
5401 | |
5402 uint8 flags = 0; | |
5403 do { | |
5404 SCOPED_TRACE(testing::Message() << "Flags " << flags); | |
5405 | |
5406 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5407 testing::StrictMock<net::test::MockDebugVisitor> debug_visitor; | |
5408 SpdyFramer framer(spdy_version_); | |
5409 framer.set_visitor(&visitor); | |
5410 framer.set_debug_visitor(&debug_visitor); | |
5411 | |
5412 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(42, HEADERS, _, _)); | |
5413 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, HEADERS, _)); | |
5414 EXPECT_CALL(visitor, OnHeaders(42, false, 0, 0, false)); | |
5415 EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _)) | |
5416 .WillRepeatedly(testing::Return(true)); | |
5417 | |
5418 SpdyHeadersIR headers_ir(42); | |
5419 headers_ir.SetHeader("foo", "bar"); | |
5420 scoped_ptr<SpdyFrame> frame0(framer.SerializeHeaders(headers_ir)); | |
5421 SetFrameFlags(frame0.get(), 0, spdy_version_); | |
5422 | |
5423 SpdyContinuationIR continuation(42); | |
5424 continuation.SetHeader("foo", "bar"); | |
5425 scoped_ptr<SpdySerializedFrame> frame( | |
5426 framer.SerializeContinuation(continuation)); | |
5427 SetFrameFlags(frame.get(), flags, spdy_version_); | |
5428 | |
5429 if (flags & ~(HEADERS_FLAG_END_HEADERS)) { | |
5430 EXPECT_CALL(visitor, OnError(_)); | |
5431 } else { | |
5432 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, CONTINUATION, _)); | |
5433 EXPECT_CALL(visitor, OnContinuation(42, | |
5434 flags & HEADERS_FLAG_END_HEADERS)); | |
5435 EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _)) | |
5436 .WillRepeatedly(testing::Return(true)); | |
5437 } | |
5438 | |
5439 framer.ProcessInput(frame0->data(), frame0->size()); | |
5440 framer.ProcessInput(frame->data(), frame->size()); | |
5441 if (flags & ~(HEADERS_FLAG_END_HEADERS)) { | |
5442 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
5443 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, | |
5444 framer.error_code()) | |
5445 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5446 } else { | |
5447 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5448 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5449 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5450 } | |
5451 } while (++flags != 0); | |
5452 } | |
5453 | |
5454 // TODO(mlavan): Add TEST_P(SpdyFramerTest, AltSvcFrameFlags) | |
5455 | |
5456 // TODO(hkhalil): Add TEST_P(SpdyFramerTest, BlockedFrameFlags) | |
5457 | |
5458 TEST_P(SpdyFramerTest, EmptySynStream) { | |
5459 if (!IsSpdy2() && !IsSpdy3()) { | |
5460 // SYN_STREAM not supported in SPDY>3. | |
5461 return; | |
5462 } | |
5463 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5464 testing::StrictMock<test::MockDebugVisitor> debug_visitor; | |
5465 SpdyFramer framer(spdy_version_); | |
5466 framer.set_visitor(&visitor); | |
5467 framer.set_debug_visitor(&debug_visitor); | |
5468 | |
5469 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(1, SYN_STREAM, _, _)); | |
5470 | |
5471 SpdySynStreamIR syn_stream(1); | |
5472 syn_stream.set_priority(1); | |
5473 scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); | |
5474 // Adjust size to remove the name/value block. | |
5475 SetFrameLength( | |
5476 frame.get(), | |
5477 framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(), | |
5478 spdy_version_); | |
5479 | |
5480 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(1, SYN_STREAM, _)); | |
5481 EXPECT_CALL(visitor, OnSynStream(1, 0, 1, false, false)); | |
5482 EXPECT_CALL(visitor, OnControlFrameHeaderData(1, NULL, 0)); | |
5483 | |
5484 framer.ProcessInput(frame->data(), framer.GetSynStreamMinimumSize()); | |
5485 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5486 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5487 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5488 } | |
5489 | |
5490 TEST_P(SpdyFramerTest, SettingsFlagsAndId) { | |
5491 const uint32 kId = 0x020304; | |
5492 const uint32 kFlags = 0x01; | |
5493 const uint32 kWireFormat = htonl(IsSpdy2() ? 0x04030201 : 0x01020304); | |
5494 | |
5495 SettingsFlagsAndId id_and_flags = | |
5496 SettingsFlagsAndId::FromWireFormat(spdy_version_, kWireFormat); | |
5497 EXPECT_EQ(kId, id_and_flags.id()); | |
5498 EXPECT_EQ(kFlags, id_and_flags.flags()); | |
5499 EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(spdy_version_)); | |
5500 } | |
5501 | |
5502 // Test handling of a RST_STREAM with out-of-bounds status codes. | |
5503 TEST_P(SpdyFramerTest, RstStreamStatusBounds) { | |
5504 const unsigned char kRstStreamStatusTooLow = 0x00; | |
5505 const unsigned char kRstStreamStatusTooHigh = 0xff; | |
5506 const unsigned char kV3RstStreamInvalid[] = { | |
5507 0x80, spdy_version_ch_, 0x00, 0x03, | |
5508 0x00, 0x00, 0x00, 0x08, | |
5509 0x00, 0x00, 0x00, 0x01, | |
5510 0x00, 0x00, 0x00, kRstStreamStatusTooLow | |
5511 }; | |
5512 const unsigned char kV4RstStreamInvalid[] = { | |
5513 0x00, 0x00, 0x04, 0x03, | |
5514 0x00, 0x00, 0x00, 0x00, | |
5515 0x01, 0x00, 0x00, 0x00, | |
5516 kRstStreamStatusTooLow | |
5517 }; | |
5518 | |
5519 const unsigned char kV3RstStreamNumStatusCodes[] = { | |
5520 0x80, spdy_version_ch_, 0x00, 0x03, | |
5521 0x00, 0x00, 0x00, 0x08, | |
5522 0x00, 0x00, 0x00, 0x01, | |
5523 0x00, 0x00, 0x00, kRstStreamStatusTooHigh | |
5524 }; | |
5525 const unsigned char kV4RstStreamNumStatusCodes[] = { | |
5526 0x00, 0x00, 0x04, 0x03, | |
5527 0x00, 0x00, 0x00, 0x00, | |
5528 0x01, 0x00, 0x00, 0x00, | |
5529 kRstStreamStatusTooHigh | |
5530 }; | |
5531 | |
5532 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5533 SpdyFramer framer(spdy_version_); | |
5534 framer.set_visitor(&visitor); | |
5535 | |
5536 if (IsSpdy4()) { | |
5537 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INTERNAL_ERROR)); | |
5538 framer.ProcessInput(reinterpret_cast<const char*>(kV4RstStreamInvalid), | |
5539 arraysize(kV4RstStreamInvalid)); | |
5540 } else { | |
5541 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID)); | |
5542 framer.ProcessInput(reinterpret_cast<const char*>(kV3RstStreamInvalid), | |
5543 arraysize(kV3RstStreamInvalid)); | |
5544 } | |
5545 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5546 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5547 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5548 | |
5549 | |
5550 framer.Reset(); | |
5551 | |
5552 if (IsSpdy4()) { | |
5553 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INTERNAL_ERROR)); | |
5554 framer.ProcessInput( | |
5555 reinterpret_cast<const char*>(kV4RstStreamNumStatusCodes), | |
5556 arraysize(kV4RstStreamNumStatusCodes)); | |
5557 } else { | |
5558 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID)); | |
5559 framer.ProcessInput( | |
5560 reinterpret_cast<const char*>(kV3RstStreamNumStatusCodes), | |
5561 arraysize(kV3RstStreamNumStatusCodes)); | |
5562 } | |
5563 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5564 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5565 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5566 } | |
5567 | |
5568 // Test handling of GOAWAY frames with out-of-bounds status code. | |
5569 TEST_P(SpdyFramerTest, GoAwayStatusBounds) { | |
5570 if (spdy_version_ <= SPDY2) { | |
5571 return; | |
5572 } | |
5573 SpdyFramer framer(spdy_version_); | |
5574 | |
5575 const unsigned char kV3FrameData[] = { | |
5576 0x80, spdy_version_ch_, 0x00, 0x07, | |
5577 0x00, 0x00, 0x00, 0x08, | |
5578 0x00, 0x00, 0x00, 0x01, // Stream Id | |
5579 0xff, 0xff, 0xff, 0xff, // Status | |
5580 }; | |
5581 const unsigned char kV4FrameData[] = { | |
5582 0x00, 0x00, 0x0a, 0x07, | |
5583 0x00, 0x00, 0x00, 0x00, | |
5584 0x00, 0x00, 0x00, 0x00, // Stream id | |
5585 0x01, 0xff, 0xff, 0xff, // Status | |
5586 0xff, 0x47, 0x41, // Opaque Description | |
5587 }; | |
5588 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5589 framer.set_visitor(&visitor); | |
5590 | |
5591 if (IsSpdy3()) { | |
5592 EXPECT_CALL(visitor, OnGoAway(1, GOAWAY_OK)); | |
5593 framer.ProcessInput(reinterpret_cast<const char*>(kV3FrameData), | |
5594 arraysize(kV3FrameData)); | |
5595 } else { | |
5596 EXPECT_CALL(visitor, OnGoAway(1, GOAWAY_INTERNAL_ERROR)); | |
5597 framer.ProcessInput(reinterpret_cast<const char*>(kV4FrameData), | |
5598 arraysize(kV4FrameData)); | |
5599 } | |
5600 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5601 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5602 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5603 } | |
5604 | |
5605 // Tests handling of a GOAWAY frame with out-of-bounds stream ID. | |
5606 TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) { | |
5607 const unsigned char kV2FrameData[] = { | |
5608 0x80, spdy_version_ch_, 0x00, 0x07, | |
5609 0x00, 0x00, 0x00, 0x04, | |
5610 0xff, 0xff, 0xff, 0xff, | |
5611 }; | |
5612 const unsigned char kV3FrameData[] = { | |
5613 0x80, spdy_version_ch_, 0x00, 0x07, | |
5614 0x00, 0x00, 0x00, 0x08, | |
5615 0xff, 0xff, 0xff, 0xff, | |
5616 0x00, 0x00, 0x00, 0x00, | |
5617 }; | |
5618 const unsigned char kV4FrameData[] = { | |
5619 0x00, 0x00, 0x08, 0x07, | |
5620 0x00, 0x00, 0x00, 0x00, | |
5621 0x00, 0xff, 0xff, 0xff, | |
5622 0xff, 0x00, 0x00, 0x00, | |
5623 0x00, | |
5624 }; | |
5625 | |
5626 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5627 SpdyFramer framer(spdy_version_); | |
5628 framer.set_visitor(&visitor); | |
5629 | |
5630 EXPECT_CALL(visitor, OnGoAway(0x7fffffff, GOAWAY_OK)); | |
5631 if (IsSpdy2()) { | |
5632 framer.ProcessInput(reinterpret_cast<const char*>(kV2FrameData), | |
5633 arraysize(kV2FrameData)); | |
5634 } else if (IsSpdy3()) { | |
5635 framer.ProcessInput(reinterpret_cast<const char*>(kV3FrameData), | |
5636 arraysize(kV3FrameData)); | |
5637 } else { | |
5638 framer.ProcessInput(reinterpret_cast<const char*>(kV4FrameData), | |
5639 arraysize(kV4FrameData)); | |
5640 } | |
5641 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5642 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5643 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5644 } | |
5645 | |
5646 TEST_P(SpdyFramerTest, OnBlocked) { | |
5647 if (spdy_version_ <= SPDY3) { | |
5648 return; | |
5649 } | |
5650 | |
5651 const SpdyStreamId kStreamId = 0; | |
5652 | |
5653 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5654 SpdyFramer framer(spdy_version_); | |
5655 framer.set_visitor(&visitor); | |
5656 | |
5657 EXPECT_CALL(visitor, OnBlocked(kStreamId)); | |
5658 | |
5659 SpdyBlockedIR blocked_ir(0); | |
5660 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(blocked_ir)); | |
5661 framer.ProcessInput(frame->data(), framer.GetBlockedSize()); | |
5662 | |
5663 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5664 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5665 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5666 } | |
5667 | |
5668 TEST_P(SpdyFramerTest, OnAltSvc) { | |
5669 if (spdy_version_ <= SPDY3) { | |
5670 return; | |
5671 } | |
5672 | |
5673 const SpdyStreamId kStreamId = 1; | |
5674 | |
5675 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5676 SpdyFramer framer(spdy_version_); | |
5677 framer.set_visitor(&visitor); | |
5678 | |
5679 EXPECT_CALL(visitor, OnAltSvc(kStreamId, | |
5680 10, | |
5681 443, | |
5682 StringPiece("pid"), | |
5683 StringPiece("h1"), | |
5684 StringPiece("o1"))); | |
5685 | |
5686 SpdyAltSvcIR altsvc_ir(1); | |
5687 altsvc_ir.set_max_age(10); | |
5688 altsvc_ir.set_port(443); | |
5689 altsvc_ir.set_protocol_id("pid"); | |
5690 altsvc_ir.set_host("h1"); | |
5691 altsvc_ir.set_origin("o1"); | |
5692 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir)); | |
5693 framer.ProcessInput(frame->data(), framer.GetAltSvcMinimumSize() + | |
5694 altsvc_ir.protocol_id().length() + | |
5695 altsvc_ir.host().length() + | |
5696 altsvc_ir.origin().length()); | |
5697 | |
5698 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5699 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5700 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5701 } | |
5702 | |
5703 TEST_P(SpdyFramerTest, OnAltSvcNoOrigin) { | |
5704 if (spdy_version_ <= SPDY3) { | |
5705 return; | |
5706 } | |
5707 | |
5708 const SpdyStreamId kStreamId = 1; | |
5709 | |
5710 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5711 SpdyFramer framer(spdy_version_); | |
5712 framer.set_visitor(&visitor); | |
5713 | |
5714 EXPECT_CALL(visitor, OnAltSvc(kStreamId, | |
5715 10, | |
5716 443, | |
5717 StringPiece("pid"), | |
5718 StringPiece("h1"), | |
5719 StringPiece(""))); | |
5720 | |
5721 SpdyAltSvcIR altsvc_ir(1); | |
5722 altsvc_ir.set_max_age(10); | |
5723 altsvc_ir.set_port(443); | |
5724 altsvc_ir.set_protocol_id("pid"); | |
5725 altsvc_ir.set_host("h1"); | |
5726 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir)); | |
5727 framer.ProcessInput(frame->data(), framer.GetAltSvcMinimumSize() + | |
5728 altsvc_ir.protocol_id().length() + | |
5729 altsvc_ir.host().length()); | |
5730 | |
5731 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5732 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5733 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5734 } | |
5735 | |
5736 TEST_P(SpdyFramerTest, OnAltSvcBadLengths) { | |
5737 if (spdy_version_ <= SPDY3) { | |
5738 return; | |
5739 } | |
5740 | |
5741 const unsigned char kType = static_cast<unsigned char>( | |
5742 SpdyConstants::SerializeFrameType(spdy_version_, ALTSVC)); | |
5743 { | |
5744 TestSpdyVisitor visitor(spdy_version_); | |
5745 SpdyFramer framer(spdy_version_); | |
5746 framer.set_visitor(&visitor); | |
5747 | |
5748 const unsigned char kFrameDataLargePIDLen[] = { | |
5749 0x00, 0x00, 0x17, kType, 0x00, | |
5750 0x00, 0x00, 0x00, 0x03, | |
5751 0x00, 0x00, 0x00, 0x05, | |
5752 0x01, 0xbb, 0x00, 0x05, // Port = 443 | |
5753 'p', 'i', 'd', '1', // Protocol-ID | |
5754 0x04, 'h', 'o', 's', | |
5755 't', 'o', 'r', 'i', | |
5756 'g', 'i', 'n', | |
5757 }; | |
5758 | |
5759 visitor.SimulateInFramer(kFrameDataLargePIDLen, | |
5760 sizeof(kFrameDataLargePIDLen)); | |
5761 EXPECT_EQ(1, visitor.error_count_); | |
5762 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
5763 visitor.framer_.error_code()); | |
5764 } | |
5765 | |
5766 { | |
5767 TestSpdyVisitor visitor(spdy_version_); | |
5768 SpdyFramer framer(spdy_version_); | |
5769 framer.set_visitor(&visitor); | |
5770 const unsigned char kFrameDataPIDLenLargerThanFrame[] = { | |
5771 0x00, 0x00, 0x17, kType, 0x00, | |
5772 0x00, 0x00, 0x00, 0x03, | |
5773 0x00, 0x00, 0x00, 0x05, | |
5774 0x01, 0xbb, 0x00, 0x99, // Port = 443 | |
5775 'p', 'i', 'd', '1', // Protocol-ID | |
5776 0x04, 'h', 'o', 's', | |
5777 't', 'o', 'r', 'i', | |
5778 'g', 'i', 'n', | |
5779 }; | |
5780 | |
5781 visitor.SimulateInFramer(kFrameDataPIDLenLargerThanFrame, | |
5782 sizeof(kFrameDataPIDLenLargerThanFrame)); | |
5783 EXPECT_EQ(1, visitor.error_count_); | |
5784 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
5785 visitor.framer_.error_code()); | |
5786 } | |
5787 | |
5788 { | |
5789 TestSpdyVisitor visitor(spdy_version_); | |
5790 SpdyFramer framer(spdy_version_); | |
5791 framer.set_visitor(&visitor); | |
5792 | |
5793 const unsigned char kFrameDataLargeHostLen[] = { | |
5794 0x00, 0x00, 0x17, kType, 0x00, | |
5795 0x00, 0x00, 0x00, 0x03, | |
5796 0x00, 0x00, 0x00, 0x05, | |
5797 0x01, 0xbb, 0x00, 0x04, // Port = 443 | |
5798 'p', 'i', 'd', '1', // Protocol-ID | |
5799 0x0f, 'h', 'o', 's', | |
5800 't', 'o', 'r', 'i', | |
5801 'g', 'i', 'n', | |
5802 }; | |
5803 | |
5804 visitor.SimulateInFramer(kFrameDataLargeHostLen, | |
5805 sizeof(kFrameDataLargeHostLen)); | |
5806 EXPECT_EQ(1, visitor.error_count_); | |
5807 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
5808 visitor.framer_.error_code()); | |
5809 } | |
5810 | |
5811 { | |
5812 TestSpdyVisitor visitor(spdy_version_); | |
5813 SpdyFramer framer(spdy_version_); | |
5814 framer.set_visitor(&visitor); | |
5815 const unsigned char kFrameDataSmallPIDLen[] = { | |
5816 0x00, 0x00, 0x17, kType, 0x00, | |
5817 0x00, 0x00, 0x00, 0x03, | |
5818 0x00, 0x00, 0x00, 0x05, | |
5819 0x01, 0xbb, 0x00, 0x01, // Port = 443 | |
5820 'p', 'i', 'd', '1', // Protocol-ID | |
5821 0x04, 'h', 'o', 's', | |
5822 't', 'o', 'r', 'i', | |
5823 'g', 'i', 'n', | |
5824 }; | |
5825 | |
5826 visitor.SimulateInFramer(kFrameDataSmallPIDLen, | |
5827 sizeof(kFrameDataSmallPIDLen)); | |
5828 EXPECT_EQ(1, visitor.error_count_); | |
5829 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
5830 visitor.framer_.error_code()); | |
5831 } | |
5832 } | |
5833 | |
5834 // Tests handling of ALTSVC frames delivered in small chunks. | |
5835 TEST_P(SpdyFramerTest, ReadChunkedAltSvcFrame) { | |
5836 if (spdy_version_ <= SPDY3) { | |
5837 return; | |
5838 } | |
5839 SpdyFramer framer(spdy_version_); | |
5840 SpdyAltSvcIR altsvc_ir(1); | |
5841 altsvc_ir.set_max_age(20); | |
5842 altsvc_ir.set_port(443); | |
5843 altsvc_ir.set_protocol_id("protocolid"); | |
5844 altsvc_ir.set_host("hostname"); | |
5845 | |
5846 scoped_ptr<SpdyFrame> control_frame(framer.SerializeAltSvc(altsvc_ir)); | |
5847 TestSpdyVisitor visitor(spdy_version_); | |
5848 visitor.use_compression_ = false; | |
5849 | |
5850 // Read data in small chunks. | |
5851 size_t framed_data = 0; | |
5852 size_t unframed_data = control_frame->size(); | |
5853 size_t kReadChunkSize = 5; // Read five bytes at a time. | |
5854 while (unframed_data > 0) { | |
5855 size_t to_read = std::min(kReadChunkSize, unframed_data); | |
5856 visitor.SimulateInFramer( | |
5857 reinterpret_cast<unsigned char*>(control_frame->data() + framed_data), | |
5858 to_read); | |
5859 unframed_data -= to_read; | |
5860 framed_data += to_read; | |
5861 } | |
5862 EXPECT_EQ(0, visitor.error_count_); | |
5863 EXPECT_EQ(1, visitor.altsvc_count_); | |
5864 EXPECT_EQ(20u, visitor.test_altsvc_ir_.max_age()); | |
5865 EXPECT_EQ(443u, visitor.test_altsvc_ir_.port()); | |
5866 EXPECT_EQ("protocolid", visitor.test_altsvc_ir_.protocol_id()); | |
5867 EXPECT_EQ("hostname", visitor.test_altsvc_ir_.host()); | |
5868 } | |
5869 | |
5870 // Tests handling of PRIORITY frames. | |
5871 TEST_P(SpdyFramerTest, ReadPriority) { | |
5872 if (spdy_version_ <= SPDY3) { | |
5873 return; | |
5874 } | |
5875 SpdyFramer framer(spdy_version_); | |
5876 SpdyPriorityIR priority(3, 1, 255, false); | |
5877 scoped_ptr<SpdySerializedFrame> frame(framer.SerializePriority(priority)); | |
5878 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
5879 framer.set_visitor(&visitor); | |
5880 EXPECT_CALL(visitor, OnPriority(3, 1, 255, false)); | |
5881 framer.ProcessInput(frame->data(), frame->size()); | |
5882 | |
5883 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); | |
5884 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) | |
5885 << SpdyFramer::ErrorCodeToString(framer.error_code()); | |
5886 // TODO(mlavan): once we actually maintain a priority tree, | |
5887 // check that state is adjusted correctly. | |
5888 } | |
5889 | |
5890 TEST_P(SpdyFramerTest, PriorityWeightMapping) { | |
5891 if (spdy_version_ <= SPDY3) { | |
5892 return; | |
5893 } | |
5894 SpdyFramer framer(spdy_version_); | |
5895 | |
5896 EXPECT_EQ(255u, framer.MapPriorityToWeight(0)); | |
5897 EXPECT_EQ(219u, framer.MapPriorityToWeight(1)); | |
5898 EXPECT_EQ(182u, framer.MapPriorityToWeight(2)); | |
5899 EXPECT_EQ(146u, framer.MapPriorityToWeight(3)); | |
5900 EXPECT_EQ(109u, framer.MapPriorityToWeight(4)); | |
5901 EXPECT_EQ(73u, framer.MapPriorityToWeight(5)); | |
5902 EXPECT_EQ(36u, framer.MapPriorityToWeight(6)); | |
5903 EXPECT_EQ(0u, framer.MapPriorityToWeight(7)); | |
5904 | |
5905 EXPECT_EQ(0u, framer.MapWeightToPriority(255)); | |
5906 EXPECT_EQ(0u, framer.MapWeightToPriority(220)); | |
5907 EXPECT_EQ(1u, framer.MapWeightToPriority(219)); | |
5908 EXPECT_EQ(1u, framer.MapWeightToPriority(183)); | |
5909 EXPECT_EQ(2u, framer.MapWeightToPriority(182)); | |
5910 EXPECT_EQ(2u, framer.MapWeightToPriority(147)); | |
5911 EXPECT_EQ(3u, framer.MapWeightToPriority(146)); | |
5912 EXPECT_EQ(3u, framer.MapWeightToPriority(110)); | |
5913 EXPECT_EQ(4u, framer.MapWeightToPriority(109)); | |
5914 EXPECT_EQ(4u, framer.MapWeightToPriority(74)); | |
5915 EXPECT_EQ(5u, framer.MapWeightToPriority(73)); | |
5916 EXPECT_EQ(5u, framer.MapWeightToPriority(37)); | |
5917 EXPECT_EQ(6u, framer.MapWeightToPriority(36)); | |
5918 EXPECT_EQ(6u, framer.MapWeightToPriority(1)); | |
5919 EXPECT_EQ(7u, framer.MapWeightToPriority(0)); | |
5920 } | |
5921 | |
5922 // Tests handling of PRIORITY frame with incorrect size. | |
5923 TEST_P(SpdyFramerTest, ReadIncorrectlySizedPriority) { | |
5924 if (spdy_version_ <= SPDY3) { | |
5925 return; | |
5926 } | |
5927 | |
5928 // PRIORITY frame of size 4, which isn't correct. | |
5929 const unsigned char kFrameData[] = { | |
5930 0x00, 0x00, 0x04, 0x02, 0x00, | |
5931 0x00, 0x00, 0x00, 0x03, | |
5932 0x00, 0x00, 0x00, 0x01, | |
5933 }; | |
5934 | |
5935 TestSpdyVisitor visitor(spdy_version_); | |
5936 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); | |
5937 | |
5938 EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state()); | |
5939 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
5940 visitor.framer_.error_code()) | |
5941 << SpdyFramer::ErrorCodeToString(visitor.framer_.error_code()); | |
5942 } | |
5943 | |
5944 } // namespace net | |
OLD | NEW |