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 | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "net/spdy/spdy_framer.h" | |
10 #include "net/spdy/spdy_protocol.h" | |
11 #include "net/spdy/spdy_frame_builder.h" | |
12 #include "testing/platform_test.h" | |
13 | |
14 namespace { | |
15 | |
16 // Default SPDY version for unit tests. | |
17 const int SPDY_VERSION_FOR_TESTS = 2; | |
18 | |
19 // The current default spdy version as a byte to be included in const | |
20 // byte arrays below. Name choice is unfortunate, but better to fit to four | |
21 // bytes than not. | |
22 unsigned char kVer = SPDY_VERSION_FOR_TESTS; | |
23 | |
24 spdy::SpdySetting SpdySettingFromWireFormat(uint32 key, uint32 value) { | |
25 return spdy::SpdySetting( | |
26 spdy::SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, key), | |
27 value); | |
28 } | |
29 | |
30 } // namespace | |
31 | |
32 namespace spdy { | |
33 | |
34 namespace test_spdy2 { | |
35 | |
36 static const size_t kMaxDecompressedSize = 1024; | |
37 | |
38 class SpdyFramerTestUtil { | |
39 public: | |
40 // Decompress a single frame using the decompression context held by | |
41 // the SpdyFramer. The implemention will CHECK fail if the input is anything | |
42 // other than a single, well-formed compressed frame. | |
43 // | |
44 // Returns a new decompressed SpdyFrame. | |
45 template<class SpdyFrameType> static SpdyFrame* DecompressFrame( | |
46 SpdyFramer* framer, const SpdyFrameType& frame) { | |
47 DecompressionVisitor visitor; | |
48 framer->set_visitor(&visitor); | |
49 size_t input_size = frame.length() + SpdyFrame::kHeaderSize; | |
50 CHECK_EQ(input_size, framer->ProcessInput(frame.data(), input_size)); | |
51 CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state()); | |
52 framer->set_visitor(NULL); | |
53 | |
54 char* buffer = visitor.ReleaseBuffer(); | |
55 CHECK(buffer); | |
56 SpdyFrame* decompressed_frame = new SpdyFrame(buffer, true); | |
57 decompressed_frame->set_length(visitor.size() - SpdyFrame::kHeaderSize); | |
58 return decompressed_frame; | |
59 } | |
60 | |
61 class DecompressionVisitor : public SpdyFramerVisitorInterface { | |
62 public: | |
63 DecompressionVisitor() | |
64 : buffer_(NULL), size_(0), finished_(false), allow_data_frames_(false) { | |
65 } | |
66 | |
67 virtual void OnControl(const SpdyControlFrame* frame) { | |
68 CHECK(frame->has_header_block()); | |
69 CHECK(!buffer_.get()); | |
70 CHECK_EQ(size_, 0u); | |
71 CHECK(!finished_); | |
72 | |
73 int32 control_frame_header_size = 0; | |
74 switch (frame->type()) { | |
75 case SYN_STREAM: | |
76 control_frame_header_size = SpdySynStreamControlFrame::size(); | |
77 break; | |
78 case SYN_REPLY: | |
79 control_frame_header_size = SpdySynReplyControlFrame::size(); | |
80 break; | |
81 case HEADERS: | |
82 control_frame_header_size = SpdyHeadersControlFrame::size(); | |
83 break; | |
84 default: | |
85 LOG(FATAL); | |
86 return; | |
87 } | |
88 | |
89 // Allocate space for the frame, and the copy header over. | |
90 buffer_.reset(new char[kMaxDecompressedSize]); | |
91 memcpy(buffer_.get(), frame->data(), control_frame_header_size); | |
92 size_ += control_frame_header_size; | |
93 } | |
94 | |
95 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, | |
96 const char* header_data, | |
97 size_t len) { | |
98 CHECK(buffer_.get() != NULL); | |
99 CHECK_GE(kMaxDecompressedSize, size_ + len); | |
100 CHECK(!finished_); | |
101 if (len != 0) { | |
102 memcpy(buffer_.get() + size_, header_data, len); | |
103 size_ += len; | |
104 } else { | |
105 // Done. | |
106 finished_ = true; | |
107 } | |
108 return true; | |
109 } | |
110 | |
111 virtual bool OnCredentialFrameData(const char* header_data, | |
112 size_t len) { | |
113 LOG(FATAL) << "Unexpected CREDENTIAL Frame"; | |
114 return false; | |
115 } | |
116 | |
117 virtual void OnError(SpdyFramer* framer) { LOG(FATAL); } | |
118 virtual void OnDataFrameHeader(const SpdyDataFrame* frame) { | |
119 // For most tests, this class does not expect to see OnDataFrameHeader | |
120 // calls. Individual tests can override this if they need to. | |
121 if (!allow_data_frames_) { | |
122 LOG(FATAL) << "Unexpected data frame header"; | |
123 } | |
124 } | |
125 virtual void OnStreamFrameData(SpdyStreamId stream_id, | |
126 const char* data, | |
127 size_t len) { | |
128 LOG(FATAL); | |
129 } | |
130 virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) { | |
131 LOG(FATAL); | |
132 } | |
133 | |
134 char* ReleaseBuffer() { | |
135 CHECK(finished_); | |
136 return buffer_.release(); | |
137 } | |
138 | |
139 size_t size() const { | |
140 CHECK(finished_); | |
141 return size_; | |
142 } | |
143 void set_allow_data_frames(bool allow) { allow_data_frames_ = allow; } | |
144 | |
145 private: | |
146 scoped_array<char> buffer_; | |
147 size_t size_; | |
148 bool finished_; | |
149 bool allow_data_frames_; | |
150 | |
151 DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor); | |
152 }; | |
153 | |
154 DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil); | |
155 }; | |
156 | |
157 std::string HexDumpWithMarks(const unsigned char* data, int length, | |
158 const bool* marks, int mark_length) { | |
159 static const char kHexChars[] = "0123456789abcdef"; | |
160 static const int kColumns = 4; | |
161 | |
162 const int kSizeLimit = 1024; | |
163 if (length > kSizeLimit || mark_length > kSizeLimit) { | |
164 LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes."; | |
165 length = std::min(length, kSizeLimit); | |
166 mark_length = std::min(mark_length, kSizeLimit); | |
167 } | |
168 | |
169 std::string hex; | |
170 for (const unsigned char* row = data; length > 0; | |
171 row += kColumns, length -= kColumns) { | |
172 for (const unsigned char *p = row; p < row + 4; ++p) { | |
173 if (p < row + length) { | |
174 const bool mark = | |
175 (marks && (p - data) < mark_length && marks[p - data]); | |
176 hex += mark ? '*' : ' '; | |
177 hex += kHexChars[(*p & 0xf0) >> 4]; | |
178 hex += kHexChars[*p & 0x0f]; | |
179 hex += mark ? '*' : ' '; | |
180 } else { | |
181 hex += " "; | |
182 } | |
183 } | |
184 hex = hex + " "; | |
185 | |
186 for (const unsigned char *p = row; p < row + 4 && p < row + length; ++p) | |
187 hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.'; | |
188 | |
189 hex = hex + '\n'; | |
190 } | |
191 return hex; | |
192 } | |
193 | |
194 void CompareCharArraysWithHexError( | |
195 const std::string& description, | |
196 const unsigned char* actual, | |
197 const int actual_len, | |
198 const unsigned char* expected, | |
199 const int expected_len) { | |
200 const int min_len = std::min(actual_len, expected_len); | |
201 const int max_len = std::max(actual_len, expected_len); | |
202 scoped_array<bool> marks(new bool[max_len]); | |
203 bool identical = (actual_len == expected_len); | |
204 for (int i = 0; i < min_len; ++i) { | |
205 if (actual[i] != expected[i]) { | |
206 marks[i] = true; | |
207 identical = false; | |
208 } else { | |
209 marks[i] = false; | |
210 } | |
211 } | |
212 for (int i = min_len; i < max_len; ++i) { | |
213 marks[i] = true; | |
214 } | |
215 if (identical) return; | |
216 ADD_FAILURE() | |
217 << "Description:\n" | |
218 << description | |
219 << "\n\nExpected:\n" | |
220 << HexDumpWithMarks(expected, expected_len, marks.get(), max_len) | |
221 << "\nActual:\n" | |
222 << HexDumpWithMarks(actual, actual_len, marks.get(), max_len); | |
223 } | |
224 | |
225 class TestSpdyVisitor : public SpdyFramerVisitorInterface { | |
226 public: | |
227 static const size_t kDefaultHeaderBufferSize = 64 * 1024; | |
228 static const size_t kDefaultCredentialBufferSize = 16 * 1024; | |
229 | |
230 TestSpdyVisitor() | |
231 : framer_(kVer), | |
232 use_compression_(false), | |
233 error_count_(0), | |
234 syn_frame_count_(0), | |
235 syn_reply_frame_count_(0), | |
236 headers_frame_count_(0), | |
237 goaway_count_(0), | |
238 credential_count_(0), | |
239 settings_frame_count_(0), | |
240 setting_count_(0), | |
241 data_bytes_(0), | |
242 fin_frame_count_(0), | |
243 fin_flag_count_(0), | |
244 zero_length_data_frame_count_(0), | |
245 header_blocks_count_(0), | |
246 control_frame_header_data_count_(0), | |
247 zero_length_control_frame_header_data_count_(0), | |
248 data_frame_count_(0), | |
249 header_buffer_(new char[kDefaultHeaderBufferSize]), | |
250 header_buffer_length_(0), | |
251 header_buffer_size_(kDefaultHeaderBufferSize), | |
252 header_stream_id_(-1), | |
253 header_control_type_(NUM_CONTROL_FRAME_TYPES), | |
254 header_buffer_valid_(false), | |
255 credential_buffer_(new char[kDefaultCredentialBufferSize]), | |
256 credential_buffer_length_(0), | |
257 credential_buffer_size_(kDefaultCredentialBufferSize) { | |
258 } | |
259 | |
260 void OnError(SpdyFramer* f) { | |
261 LOG(INFO) << "SpdyFramer Error: " | |
262 << SpdyFramer::ErrorCodeToString(f->error_code()); | |
263 error_count_++; | |
264 } | |
265 | |
266 void OnDataFrameHeader(const SpdyDataFrame* frame) { | |
267 data_frame_count_++; | |
268 header_stream_id_ = frame->stream_id(); | |
269 } | |
270 | |
271 void OnStreamFrameData(SpdyStreamId stream_id, | |
272 const char* data, | |
273 size_t len) { | |
274 EXPECT_EQ(header_stream_id_, stream_id); | |
275 if (len == 0) | |
276 ++zero_length_data_frame_count_; | |
277 | |
278 data_bytes_ += len; | |
279 std::cerr << "OnStreamFrameData(" << stream_id << ", \""; | |
280 if (len > 0) { | |
281 for (size_t i = 0 ; i < len; ++i) { | |
282 std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec; | |
283 } | |
284 } | |
285 std::cerr << "\", " << len << ")\n"; | |
286 } | |
287 | |
288 void OnControl(const SpdyControlFrame* frame) { | |
289 switch (frame->type()) { | |
290 case SYN_STREAM: | |
291 syn_frame_count_++; | |
292 InitHeaderStreaming(frame); | |
293 break; | |
294 case SYN_REPLY: | |
295 syn_reply_frame_count_++; | |
296 InitHeaderStreaming(frame); | |
297 break; | |
298 case RST_STREAM: | |
299 fin_frame_count_++; | |
300 break; | |
301 case HEADERS: | |
302 headers_frame_count_++; | |
303 InitHeaderStreaming(frame); | |
304 break; | |
305 case GOAWAY: | |
306 goaway_count_++; | |
307 break; | |
308 case CREDENTIAL: | |
309 credential_count_++; | |
310 break; | |
311 case SETTINGS: | |
312 settings_frame_count_++; | |
313 break; | |
314 default: | |
315 DLOG(FATAL); // Error! | |
316 } | |
317 if (frame->flags() & CONTROL_FLAG_FIN) | |
318 ++fin_flag_count_; | |
319 } | |
320 | |
321 virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) { | |
322 setting_count_++; | |
323 } | |
324 | |
325 bool OnControlFrameHeaderData(SpdyStreamId stream_id, | |
326 const char* header_data, | |
327 size_t len) { | |
328 ++control_frame_header_data_count_; | |
329 CHECK_EQ(header_stream_id_, stream_id); | |
330 if (len == 0) { | |
331 ++zero_length_control_frame_header_data_count_; | |
332 // Indicates end-of-header-block. | |
333 CHECK(header_buffer_valid_); | |
334 bool parsed_headers = framer_.ParseHeaderBlockInBuffer( | |
335 header_buffer_.get(), header_buffer_length_, &headers_); | |
336 DCHECK(parsed_headers); | |
337 return true; | |
338 } | |
339 const size_t available = header_buffer_size_ - header_buffer_length_; | |
340 if (len > available) { | |
341 header_buffer_valid_ = false; | |
342 return false; | |
343 } | |
344 memcpy(header_buffer_.get() + header_buffer_length_, header_data, len); | |
345 header_buffer_length_ += len; | |
346 return true; | |
347 } | |
348 | |
349 bool OnCredentialFrameData(const char* credential_data, | |
350 size_t len) { | |
351 if (len == 0) { | |
352 if (!framer_.ParseCredentialData(credential_buffer_.get(), | |
353 credential_buffer_length_, | |
354 &credential_)) { | |
355 ++error_count_; | |
356 } | |
357 return true; | |
358 } | |
359 const size_t available = | |
360 credential_buffer_size_ - credential_buffer_length_; | |
361 if (len > available) { | |
362 return false; | |
363 } | |
364 memcpy(credential_buffer_.get() + credential_buffer_length_, | |
365 credential_data, len); | |
366 credential_buffer_length_ += len; | |
367 return true; | |
368 } | |
369 | |
370 // Convenience function which runs a framer simulation with particular input. | |
371 void SimulateInFramer(const unsigned char* input, size_t size) { | |
372 framer_.set_enable_compression(use_compression_); | |
373 framer_.set_visitor(this); | |
374 size_t input_remaining = size; | |
375 const char* input_ptr = reinterpret_cast<const char*>(input); | |
376 while (input_remaining > 0 && | |
377 framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) { | |
378 // To make the tests more interesting, we feed random (amd small) chunks | |
379 // into the framer. This simulates getting strange-sized reads from | |
380 // the socket. | |
381 const size_t kMaxReadSize = 32; | |
382 size_t bytes_read = | |
383 (rand() % std::min(input_remaining, kMaxReadSize)) + 1; | |
384 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read); | |
385 input_remaining -= bytes_processed; | |
386 input_ptr += bytes_processed; | |
387 if (framer_.state() == SpdyFramer::SPDY_DONE) | |
388 framer_.Reset(); | |
389 } | |
390 } | |
391 | |
392 void InitHeaderStreaming(const SpdyControlFrame* frame) { | |
393 memset(header_buffer_.get(), 0, header_buffer_size_); | |
394 header_buffer_length_ = 0; | |
395 header_stream_id_ = SpdyFramer::GetControlFrameStreamId(frame); | |
396 header_control_type_ = frame->type(); | |
397 header_buffer_valid_ = true; | |
398 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
399 } | |
400 | |
401 // Override the default buffer size (16K). Call before using the framer! | |
402 void set_header_buffer_size(size_t header_buffer_size) { | |
403 header_buffer_size_ = header_buffer_size; | |
404 header_buffer_.reset(new char[header_buffer_size]); | |
405 } | |
406 | |
407 static size_t control_frame_buffer_max_size() { | |
408 return SpdyFramer::kControlFrameBufferMaxSize; | |
409 } | |
410 | |
411 static size_t header_data_chunk_max_size() { | |
412 return SpdyFramer::kHeaderDataChunkMaxSize; | |
413 } | |
414 | |
415 SpdyFramer framer_; | |
416 bool use_compression_; | |
417 | |
418 // Counters from the visitor callbacks. | |
419 int error_count_; | |
420 int syn_frame_count_; | |
421 int syn_reply_frame_count_; | |
422 int headers_frame_count_; | |
423 int goaway_count_; | |
424 int credential_count_; | |
425 int settings_frame_count_; | |
426 int setting_count_; | |
427 int data_bytes_; | |
428 int fin_frame_count_; // The count of RST_STREAM type frames received. | |
429 int fin_flag_count_; // The count of frames with the FIN flag set. | |
430 int zero_length_data_frame_count_; // The count of zero-length data frames. | |
431 int header_blocks_count_; | |
432 int control_frame_header_data_count_; // The count of chunks received. | |
433 // The count of zero-length control frame header data chunks received. | |
434 int zero_length_control_frame_header_data_count_; | |
435 int data_frame_count_; | |
436 | |
437 // Header block streaming state: | |
438 scoped_array<char> header_buffer_; | |
439 size_t header_buffer_length_; | |
440 size_t header_buffer_size_; | |
441 SpdyStreamId header_stream_id_; | |
442 SpdyControlType header_control_type_; | |
443 bool header_buffer_valid_; | |
444 SpdyHeaderBlock headers_; | |
445 | |
446 scoped_array<char> credential_buffer_; | |
447 size_t credential_buffer_length_; | |
448 size_t credential_buffer_size_; | |
449 SpdyCredential credential_; | |
450 }; | |
451 | |
452 } // namespace test_spdy2 | |
453 | |
454 } // namespace spdy | |
455 | |
456 using spdy::SpdyControlFlags; | |
457 using spdy::SpdyControlFrame; | |
458 using spdy::SpdyDataFrame; | |
459 using spdy::SpdyFrame; | |
460 using spdy::SpdyFrameBuilder; | |
461 using spdy::SpdyFramer; | |
462 using spdy::SpdyHeaderBlock; | |
463 using spdy::SpdySynStreamControlFrame; | |
464 using spdy::kControlFlagMask; | |
465 using spdy::kLengthMask; | |
466 using spdy::CONTROL_FLAG_NONE; | |
467 using spdy::DATA_FLAG_COMPRESSED; | |
468 using spdy::DATA_FLAG_FIN; | |
469 using spdy::SYN_STREAM; | |
470 using spdy::test_spdy2::CompareCharArraysWithHexError; | |
471 using spdy::test_spdy2::SpdyFramerTestUtil; | |
472 using spdy::test_spdy2::TestSpdyVisitor; | |
473 | |
474 namespace spdy { | |
475 | |
476 TEST(SpdyFrameBuilderSpdy2Test, WriteLimits) { | |
477 SpdyFrameBuilder builder(kLengthMask + 4); | |
478 // length field should fail. | |
479 EXPECT_FALSE(builder.WriteBytes(reinterpret_cast<const void*>(0x1), | |
480 kLengthMask + 1)); | |
481 EXPECT_EQ(0, builder.length()); | |
482 | |
483 // Writing a block of the maximum allowed size should succeed. | |
484 const std::string kLargeData(kLengthMask, 'A'); | |
485 builder.WriteUInt32(kLengthMask); | |
486 EXPECT_EQ(4, builder.length()); | |
487 EXPECT_TRUE(builder.WriteBytes(kLargeData.data(), kLengthMask)); | |
488 EXPECT_EQ(4 + kLengthMask, static_cast<unsigned>(builder.length())); | |
489 } | |
490 | |
491 class SpdyFramerSpdy2Test : public PlatformTest { | |
492 public: | |
493 virtual void TearDown() {} | |
494 | |
495 protected: | |
496 void CompareFrame(const std::string& description, | |
497 const SpdyFrame& actual_frame, | |
498 const unsigned char* expected, | |
499 const int expected_len) { | |
500 const unsigned char* actual = | |
501 reinterpret_cast<const unsigned char*>(actual_frame.data()); | |
502 int actual_len = actual_frame.length() + SpdyFrame::kHeaderSize; | |
503 CompareCharArraysWithHexError( | |
504 description, actual, actual_len, expected, expected_len); | |
505 } | |
506 | |
507 // Returns true if the two header blocks have equivalent content. | |
508 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected, | |
509 const SpdyHeaderBlock* actual) { | |
510 if (expected->size() != actual->size()) { | |
511 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got " | |
512 << actual->size() << "." << std::endl; | |
513 return false; | |
514 } | |
515 for (SpdyHeaderBlock::const_iterator it = expected->begin(); | |
516 it != expected->end(); | |
517 ++it) { | |
518 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first); | |
519 if (it2 == actual->end()) { | |
520 LOG(ERROR) << "Expected header name '" << it->first << "'." | |
521 << std::endl; | |
522 return false; | |
523 } | |
524 if (it->second.compare(it2->second) != 0) { | |
525 LOG(ERROR) << "Expected header named '" << it->first | |
526 << "' to have a value of '" << it->second | |
527 << "'. The actual value received was '" << it2->second | |
528 << "'." << std::endl; | |
529 return false; | |
530 } | |
531 } | |
532 return true; | |
533 } | |
534 }; | |
535 | |
536 | |
537 // Test that we can encode and decode a SpdyHeaderBlock in serialized form. | |
538 TEST_F(SpdyFramerSpdy2Test, HeaderBlockInBuffer) { | |
539 SpdyHeaderBlock headers; | |
540 headers["alpha"] = "beta"; | |
541 headers["gamma"] = "charlie"; | |
542 SpdyFramer framer(kVer); | |
543 | |
544 // Encode the header block into a SynStream frame. | |
545 scoped_ptr<SpdySynStreamControlFrame> frame( | |
546 framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, &headers)); | |
547 EXPECT_TRUE(frame.get() != NULL); | |
548 std::string serialized_headers(frame->header_block(), | |
549 frame->header_block_len()); | |
550 SpdyHeaderBlock new_headers; | |
551 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
552 serialized_headers.size(), | |
553 &new_headers)); | |
554 | |
555 EXPECT_EQ(headers.size(), new_headers.size()); | |
556 EXPECT_EQ(headers["alpha"], new_headers["alpha"]); | |
557 EXPECT_EQ(headers["gamma"], new_headers["gamma"]); | |
558 } | |
559 | |
560 // Test that if there's not a full frame, we fail to parse it. | |
561 TEST_F(SpdyFramerSpdy2Test, UndersizedHeaderBlockInBuffer) { | |
562 SpdyHeaderBlock headers; | |
563 headers["alpha"] = "beta"; | |
564 headers["gamma"] = "charlie"; | |
565 SpdyFramer framer(kVer); | |
566 | |
567 // Encode the header block into a SynStream frame. | |
568 scoped_ptr<SpdySynStreamControlFrame> frame( | |
569 framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, &headers)); | |
570 EXPECT_TRUE(frame.get() != NULL); | |
571 | |
572 std::string serialized_headers(frame->header_block(), | |
573 frame->header_block_len()); | |
574 SpdyHeaderBlock new_headers; | |
575 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
576 serialized_headers.size() - 2, | |
577 &new_headers)); | |
578 } | |
579 | |
580 TEST_F(SpdyFramerSpdy2Test, OutOfOrderHeaders) { | |
581 // Frame builder with plentiful buffer size. | |
582 SpdyFrameBuilder frame(1024); | |
583 | |
584 frame.WriteUInt16(kControlFlagMask | 1); | |
585 frame.WriteUInt16(SYN_STREAM); | |
586 frame.WriteUInt32(0); // Placeholder for the length. | |
587 frame.WriteUInt32(3); // stream_id | |
588 frame.WriteUInt32(0); // Associated stream id | |
589 frame.WriteUInt16(0); // Priority. | |
590 | |
591 if (SPDY_VERSION_FOR_TESTS < 3) { | |
592 frame.WriteUInt16(2); // Number of headers. | |
593 frame.WriteString("gamma"); | |
594 frame.WriteString("gamma"); | |
595 frame.WriteString("alpha"); | |
596 frame.WriteString("alpha"); | |
597 } else { | |
598 frame.WriteUInt32(2); // Number of headers. | |
599 frame.WriteStringPiece32("gamma"); | |
600 frame.WriteStringPiece32("gamma"); | |
601 frame.WriteStringPiece32("alpha"); | |
602 frame.WriteStringPiece32("alpha"); | |
603 } | |
604 // write the length | |
605 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); | |
606 | |
607 SpdyHeaderBlock new_headers; | |
608 scoped_ptr<SpdyFrame> control_frame(frame.take()); | |
609 SpdySynStreamControlFrame syn_frame(control_frame->data(), false); | |
610 std::string serialized_headers(syn_frame.header_block(), | |
611 syn_frame.header_block_len()); | |
612 SpdyFramer framer(kVer); | |
613 framer.set_enable_compression(false); | |
614 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
615 serialized_headers.size(), | |
616 &new_headers)); | |
617 } | |
618 | |
619 TEST_F(SpdyFramerSpdy2Test, CreateCredential) { | |
620 SpdyFramer framer(kVer); | |
621 | |
622 { | |
623 const char kDescription[] = "CREDENTIAL frame"; | |
624 const unsigned char kFrameData[] = { | |
625 0x80, kVer, 0x00, 0x0A, | |
626 0x00, 0x00, 0x00, 0x33, | |
627 0x00, 0x03, 0x00, 0x00, | |
628 0x00, 0x05, 'p', 'r', | |
629 'o', 'o', 'f', 0x00, | |
630 0x00, 0x00, 0x06, 'a', | |
631 ' ', 'c', 'e', 'r', | |
632 't', 0x00, 0x00, 0x00, | |
633 0x0C, 'a', 'n', 'o', | |
634 't', 'h', 'e', 'r', | |
635 ' ', 'c', 'e', 'r', | |
636 't', 0x00, 0x00, 0x00, | |
637 0x0A, 'f', 'i', 'n', | |
638 'a', 'l', ' ', 'c', | |
639 'e', 'r', 't', | |
640 }; | |
641 SpdyCredential credential; | |
642 credential.slot = 3; | |
643 credential.proof = "proof"; | |
644 credential.certs.push_back("a cert"); | |
645 credential.certs.push_back("another cert"); | |
646 credential.certs.push_back("final cert"); | |
647 scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential)); | |
648 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
649 } | |
650 } | |
651 | |
652 TEST_F(SpdyFramerSpdy2Test, ParseCredentialFrameData) { | |
653 SpdyFramer framer(kVer); | |
654 | |
655 { | |
656 unsigned char kFrameData[] = { | |
657 0x80, kVer, 0x00, 0x0A, | |
658 0x00, 0x00, 0x00, 0x33, | |
659 0x00, 0x03, 0x00, 0x00, | |
660 0x00, 0x05, 'p', 'r', | |
661 'o', 'o', 'f', 0x00, | |
662 0x00, 0x00, 0x06, 'a', | |
663 ' ', 'c', 'e', 'r', | |
664 't', 0x00, 0x00, 0x00, | |
665 0x0C, 'a', 'n', 'o', | |
666 't', 'h', 'e', 'r', | |
667 ' ', 'c', 'e', 'r', | |
668 't', 0x00, 0x00, 0x00, | |
669 0x0A, 'f', 'i', 'n', | |
670 'a', 'l', ' ', 'c', | |
671 'e', 'r', 't', | |
672 }; | |
673 SpdyCredentialControlFrame frame(reinterpret_cast<char*>(kFrameData), | |
674 false); | |
675 SpdyCredential credential; | |
676 EXPECT_TRUE(SpdyFramer::ParseCredentialData(frame.payload(), frame.length(), | |
677 &credential)); | |
678 EXPECT_EQ(3u, credential.slot); | |
679 EXPECT_EQ("proof", credential.proof); | |
680 EXPECT_EQ("a cert", credential.certs.front()); | |
681 credential.certs.erase(credential.certs.begin()); | |
682 EXPECT_EQ("another cert", credential.certs.front()); | |
683 credential.certs.erase(credential.certs.begin()); | |
684 EXPECT_EQ("final cert", credential.certs.front()); | |
685 credential.certs.erase(credential.certs.begin()); | |
686 EXPECT_TRUE(credential.certs.empty()); | |
687 } | |
688 } | |
689 | |
690 TEST_F(SpdyFramerSpdy2Test, DuplicateHeader) { | |
691 // Frame builder with plentiful buffer size. | |
692 SpdyFrameBuilder frame(1024); | |
693 | |
694 frame.WriteUInt16(kControlFlagMask | 1); | |
695 frame.WriteUInt16(SYN_STREAM); | |
696 frame.WriteUInt32(0); // Placeholder for the length. | |
697 frame.WriteUInt32(3); // stream_id | |
698 frame.WriteUInt32(0); // associated stream id | |
699 frame.WriteUInt16(0); // Priority. | |
700 | |
701 if (SPDY_VERSION_FOR_TESTS < 3) { | |
702 frame.WriteUInt16(2); // Number of headers. | |
703 frame.WriteString("name"); | |
704 frame.WriteString("value1"); | |
705 frame.WriteString("name"); | |
706 frame.WriteString("value2"); | |
707 } else { | |
708 frame.WriteUInt32(2); // Number of headers. | |
709 frame.WriteStringPiece32("name"); | |
710 frame.WriteStringPiece32("value1"); | |
711 frame.WriteStringPiece32("name"); | |
712 frame.WriteStringPiece32("value2"); | |
713 } | |
714 // write the length | |
715 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); | |
716 | |
717 SpdyHeaderBlock new_headers; | |
718 scoped_ptr<SpdyFrame> control_frame(frame.take()); | |
719 SpdySynStreamControlFrame syn_frame(control_frame->data(), false); | |
720 std::string serialized_headers(syn_frame.header_block(), | |
721 syn_frame.header_block_len()); | |
722 SpdyFramer framer(kVer); | |
723 framer.set_enable_compression(false); | |
724 // This should fail because duplicate headers are verboten by the spec. | |
725 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
726 serialized_headers.size(), | |
727 &new_headers)); | |
728 } | |
729 | |
730 TEST_F(SpdyFramerSpdy2Test, MultiValueHeader) { | |
731 // Frame builder with plentiful buffer size. | |
732 SpdyFrameBuilder frame(1024); | |
733 | |
734 frame.WriteUInt16(kControlFlagMask | 1); | |
735 frame.WriteUInt16(SYN_STREAM); | |
736 frame.WriteUInt32(0); // Placeholder for the length. | |
737 frame.WriteUInt32(3); // stream_id | |
738 frame.WriteUInt32(0); // associated stream id | |
739 frame.WriteUInt16(0); // Priority. | |
740 | |
741 std::string value("value1\0value2"); | |
742 if (SPDY_VERSION_FOR_TESTS < 3) { | |
743 frame.WriteUInt16(1); // Number of headers. | |
744 frame.WriteString("name"); | |
745 frame.WriteString(value); | |
746 } else { | |
747 frame.WriteUInt32(1); // Number of headers. | |
748 frame.WriteStringPiece32("name"); | |
749 frame.WriteStringPiece32(value); | |
750 } | |
751 // write the length | |
752 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); | |
753 | |
754 SpdyHeaderBlock new_headers; | |
755 scoped_ptr<SpdyFrame> control_frame(frame.take()); | |
756 SpdySynStreamControlFrame syn_frame(control_frame->data(), false); | |
757 std::string serialized_headers(syn_frame.header_block(), | |
758 syn_frame.header_block_len()); | |
759 SpdyFramer framer(kVer); | |
760 framer.set_enable_compression(false); | |
761 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
762 serialized_headers.size(), | |
763 &new_headers)); | |
764 EXPECT_TRUE(new_headers.find("name") != new_headers.end()); | |
765 EXPECT_EQ(value, new_headers.find("name")->second); | |
766 } | |
767 | |
768 TEST_F(SpdyFramerSpdy2Test, BasicCompression) { | |
769 SpdyHeaderBlock headers; | |
770 headers["server"] = "SpdyServer 1.0"; | |
771 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; | |
772 headers["status"] = "200"; | |
773 headers["version"] = "HTTP/1.1"; | |
774 headers["content-type"] = "text/html"; | |
775 headers["content-length"] = "12"; | |
776 | |
777 SpdyFramer framer(kVer); | |
778 framer.set_enable_compression(true); | |
779 scoped_ptr<SpdySynStreamControlFrame> | |
780 frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, | |
781 &headers)); | |
782 scoped_ptr<SpdySynStreamControlFrame> | |
783 frame2(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, | |
784 &headers)); | |
785 | |
786 // Expect the second frame to be more compact than the first. | |
787 EXPECT_LE(frame2->length(), frame1->length()); | |
788 | |
789 // Decompress the first frame | |
790 scoped_ptr<SpdyFrame> frame3(SpdyFramerTestUtil::DecompressFrame( | |
791 &framer, *frame1.get())); | |
792 | |
793 // Decompress the second frame | |
794 scoped_ptr<SpdyFrame> frame4(SpdyFramerTestUtil::DecompressFrame( | |
795 &framer, *frame2.get())); | |
796 | |
797 // Expect frames 3 & 4 to be the same. | |
798 EXPECT_EQ(0, | |
799 memcmp(frame3->data(), frame4->data(), | |
800 SpdyFrame::kHeaderSize + frame3->length())); | |
801 | |
802 | |
803 // Expect frames 3 to be the same as a uncompressed frame created | |
804 // from scratch. | |
805 scoped_ptr<SpdySynStreamControlFrame> | |
806 uncompressed_frame(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, | |
807 false, &headers)); | |
808 EXPECT_EQ(frame3->length(), uncompressed_frame->length()); | |
809 EXPECT_EQ(0, | |
810 memcmp(frame3->data(), uncompressed_frame->data(), | |
811 SpdyFrame::kHeaderSize + uncompressed_frame->length())); | |
812 } | |
813 | |
814 TEST_F(SpdyFramerSpdy2Test, Basic) { | |
815 const unsigned char kV2Input[] = { | |
816 0x80, kVer, 0x00, 0x01, // SYN Stream #1 | |
817 0x00, 0x00, 0x00, 0x14, | |
818 0x00, 0x00, 0x00, 0x01, | |
819 0x00, 0x00, 0x00, 0x00, | |
820 0x00, 0x00, 0x00, 0x01, | |
821 0x00, 0x02, 'h', 'h', | |
822 0x00, 0x02, 'v', 'v', | |
823 | |
824 0x80, kVer, 0x00, 0x08, // HEADERS on Stream #1 | |
825 0x00, 0x00, 0x00, 0x18, | |
826 0x00, 0x00, 0x00, 0x01, | |
827 0x00, 0x00, 0x00, 0x02, | |
828 0x00, 0x02, 'h', '2', | |
829 0x00, 0x02, 'v', '2', | |
830 0x00, 0x02, 'h', '3', | |
831 0x00, 0x02, 'v', '3', | |
832 | |
833 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
834 0x00, 0x00, 0x00, 0x0c, | |
835 0xde, 0xad, 0xbe, 0xef, | |
836 0xde, 0xad, 0xbe, 0xef, | |
837 0xde, 0xad, 0xbe, 0xef, | |
838 | |
839 0x80, kVer, 0x00, 0x01, // SYN Stream #3 | |
840 0x00, 0x00, 0x00, 0x0c, | |
841 0x00, 0x00, 0x00, 0x03, | |
842 0x00, 0x00, 0x00, 0x00, | |
843 0x00, 0x00, 0x00, 0x00, | |
844 | |
845 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
846 0x00, 0x00, 0x00, 0x08, | |
847 0xde, 0xad, 0xbe, 0xef, | |
848 0xde, 0xad, 0xbe, 0xef, | |
849 | |
850 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
851 0x00, 0x00, 0x00, 0x04, | |
852 0xde, 0xad, 0xbe, 0xef, | |
853 | |
854 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #1 | |
855 0x00, 0x00, 0x00, 0x08, | |
856 0x00, 0x00, 0x00, 0x01, | |
857 0x00, 0x00, 0x00, 0x00, | |
858 | |
859 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
860 0x00, 0x00, 0x00, 0x00, | |
861 | |
862 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #3 | |
863 0x00, 0x00, 0x00, 0x08, | |
864 0x00, 0x00, 0x00, 0x03, | |
865 0x00, 0x00, 0x00, 0x00, | |
866 }; | |
867 | |
868 const unsigned char kV3Input[] = { | |
869 0x80, kVer, 0x00, 0x01, // SYN Stream #1 | |
870 0x00, 0x00, 0x00, 0x1a, | |
871 0x00, 0x00, 0x00, 0x01, | |
872 0x00, 0x00, 0x00, 0x00, | |
873 0x00, 0x00, 0x00, 0x00, | |
874 0x00, 0x01, 0x00, 0x00, | |
875 0x00, 0x02, 'h', 'h', | |
876 0x00, 0x00, 0x00, 0x02, | |
877 'v', 'v', | |
878 | |
879 0x80, kVer, 0x00, 0x08, // HEADERS on Stream #1 | |
880 0x00, 0x00, 0x00, 0x22, | |
881 0x00, 0x00, 0x00, 0x01, | |
882 0x00, 0x00, 0x00, 0x00, | |
883 0x00, 0x02, 0x00, 0x00, | |
884 0x00, 0x02, 'h', '2', | |
885 0x00, 0x00, 0x00, 0x02, | |
886 'v', '2', 0x00, 0x00, | |
887 0x00, 0x02, 'h', '3', | |
888 0x00, 0x00, 0x00, 0x02, | |
889 'v', '3', | |
890 | |
891 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
892 0x00, 0x00, 0x00, 0x0c, | |
893 0xde, 0xad, 0xbe, 0xef, | |
894 0xde, 0xad, 0xbe, 0xef, | |
895 0xde, 0xad, 0xbe, 0xef, | |
896 | |
897 0x80, kVer, 0x00, 0x01, // SYN Stream #3 | |
898 0x00, 0x00, 0x00, 0x0e, | |
899 0x00, 0x00, 0x00, 0x03, | |
900 0x00, 0x00, 0x00, 0x00, | |
901 0x00, 0x00, 0x00, 0x00, | |
902 0x00, 0x00, | |
903 | |
904 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
905 0x00, 0x00, 0x00, 0x08, | |
906 0xde, 0xad, 0xbe, 0xef, | |
907 0xde, 0xad, 0xbe, 0xef, | |
908 | |
909 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
910 0x00, 0x00, 0x00, 0x04, | |
911 0xde, 0xad, 0xbe, 0xef, | |
912 | |
913 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #1 | |
914 0x00, 0x00, 0x00, 0x08, | |
915 0x00, 0x00, 0x00, 0x01, | |
916 0x00, 0x00, 0x00, 0x00, | |
917 | |
918 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
919 0x00, 0x00, 0x00, 0x00, | |
920 | |
921 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #3 | |
922 0x00, 0x00, 0x00, 0x08, | |
923 0x00, 0x00, 0x00, 0x03, | |
924 0x00, 0x00, 0x00, 0x00, | |
925 }; | |
926 | |
927 TestSpdyVisitor visitor; | |
928 if (SPDY_VERSION_FOR_TESTS < 3) { | |
929 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); | |
930 } else { | |
931 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); | |
932 } | |
933 | |
934 EXPECT_EQ(0, visitor.error_count_); | |
935 EXPECT_EQ(2, visitor.syn_frame_count_); | |
936 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
937 EXPECT_EQ(1, visitor.headers_frame_count_); | |
938 EXPECT_EQ(24, visitor.data_bytes_); | |
939 EXPECT_EQ(2, visitor.fin_frame_count_); | |
940 EXPECT_EQ(0, visitor.fin_flag_count_); | |
941 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); | |
942 EXPECT_EQ(4, visitor.data_frame_count_); | |
943 } | |
944 | |
945 // Test that the FIN flag on a data frame signifies EOF. | |
946 TEST_F(SpdyFramerSpdy2Test, FinOnDataFrame) { | |
947 const unsigned char kV2Input[] = { | |
948 0x80, kVer, 0x00, 0x01, // SYN Stream #1 | |
949 0x00, 0x00, 0x00, 0x14, | |
950 0x00, 0x00, 0x00, 0x01, | |
951 0x00, 0x00, 0x00, 0x00, | |
952 0x00, 0x00, 0x00, 0x01, | |
953 0x00, 0x02, 'h', 'h', | |
954 0x00, 0x02, 'v', 'v', | |
955 | |
956 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 | |
957 0x00, 0x00, 0x00, 0x10, | |
958 0x00, 0x00, 0x00, 0x01, | |
959 0x00, 0x00, 0x00, 0x01, | |
960 0x00, 0x02, 'a', 'a', | |
961 0x00, 0x02, 'b', 'b', | |
962 | |
963 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
964 0x00, 0x00, 0x00, 0x0c, | |
965 0xde, 0xad, 0xbe, 0xef, | |
966 0xde, 0xad, 0xbe, 0xef, | |
967 0xde, 0xad, 0xbe, 0xef, | |
968 | |
969 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF | |
970 0x01, 0x00, 0x00, 0x04, | |
971 0xde, 0xad, 0xbe, 0xef, | |
972 }; | |
973 const unsigned char kV3Input[] = { | |
974 0x80, kVer, 0x00, 0x01, // SYN Stream #1 | |
975 0x00, 0x00, 0x00, 0x1a, | |
976 0x00, 0x00, 0x00, 0x01, | |
977 0x00, 0x00, 0x00, 0x00, | |
978 0x00, 0x00, 0x00, 0x00, | |
979 0x00, 0x01, 0x00, 0x00, | |
980 0x00, 0x02, 'h', 'h', | |
981 0x00, 0x00, 0x00, 0x02, | |
982 'v', 'v', | |
983 | |
984 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 | |
985 0x00, 0x00, 0x00, 0x16, | |
986 0x00, 0x00, 0x00, 0x01, | |
987 0x00, 0x00, 0x00, 0x00, | |
988 0x00, 0x01, 0x00, 0x00, | |
989 0x00, 0x02, 'a', 'a', | |
990 0x00, 0x00, 0x00, 0x02, | |
991 'b', 'b', | |
992 | |
993 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
994 0x00, 0x00, 0x00, 0x0c, | |
995 0xde, 0xad, 0xbe, 0xef, | |
996 0xde, 0xad, 0xbe, 0xef, | |
997 0xde, 0xad, 0xbe, 0xef, | |
998 | |
999 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF | |
1000 0x01, 0x00, 0x00, 0x04, | |
1001 0xde, 0xad, 0xbe, 0xef, | |
1002 }; | |
1003 | |
1004 TestSpdyVisitor visitor; | |
1005 if (SPDY_VERSION_FOR_TESTS < 3) { | |
1006 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); | |
1007 } else { | |
1008 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); | |
1009 } | |
1010 | |
1011 EXPECT_EQ(0, visitor.error_count_); | |
1012 EXPECT_EQ(1, visitor.syn_frame_count_); | |
1013 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
1014 EXPECT_EQ(0, visitor.headers_frame_count_); | |
1015 EXPECT_EQ(16, visitor.data_bytes_); | |
1016 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1017 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1018 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
1019 EXPECT_EQ(2, visitor.data_frame_count_); | |
1020 } | |
1021 | |
1022 // Test that the FIN flag on a SYN reply frame signifies EOF. | |
1023 TEST_F(SpdyFramerSpdy2Test, FinOnSynReplyFrame) { | |
1024 const unsigned char kV2Input[] = { | |
1025 0x80, kVer, 0x00, 0x01, // SYN Stream #1 | |
1026 0x00, 0x00, 0x00, 0x14, | |
1027 0x00, 0x00, 0x00, 0x01, | |
1028 0x00, 0x00, 0x00, 0x00, | |
1029 0x00, 0x00, 0x00, 0x01, | |
1030 0x00, 0x02, 'h', 'h', | |
1031 0x00, 0x02, 'v', 'v', | |
1032 | |
1033 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 | |
1034 0x01, 0x00, 0x00, 0x14, | |
1035 0x00, 0x00, 0x00, 0x01, | |
1036 0x00, 0x00, 0x00, 0x00, | |
1037 0x00, 0x00, 0x00, 0x01, | |
1038 0x00, 0x02, 'a', 'a', | |
1039 0x00, 0x02, 'b', 'b', | |
1040 }; | |
1041 const unsigned char kV3Input[] = { | |
1042 0x80, kVer, 0x00, 0x01, // SYN Stream #1 | |
1043 0x00, 0x00, 0x00, 0x1a, | |
1044 0x00, 0x00, 0x00, 0x01, | |
1045 0x00, 0x00, 0x00, 0x00, | |
1046 0x00, 0x00, 0x00, 0x00, | |
1047 0x00, 0x01, 0x00, 0x00, | |
1048 0x00, 0x02, 'h', 'h', | |
1049 0x00, 0x00, 0x00, 0x02, | |
1050 'v', 'v', | |
1051 | |
1052 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 | |
1053 0x01, 0x00, 0x00, 0x1a, | |
1054 0x00, 0x00, 0x00, 0x01, | |
1055 0x00, 0x00, 0x00, 0x00, | |
1056 0x00, 0x00, 0x00, 0x00, | |
1057 0x00, 0x01, 0x00, 0x00, | |
1058 0x00, 0x02, 'a', 'a', | |
1059 0x00, 0x00, 0x00, 0x02, | |
1060 'b', 'b', | |
1061 }; | |
1062 | |
1063 TestSpdyVisitor visitor; | |
1064 if (SPDY_VERSION_FOR_TESTS < 3) { | |
1065 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); | |
1066 } else { | |
1067 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); | |
1068 } | |
1069 | |
1070 EXPECT_EQ(0, visitor.error_count_); | |
1071 EXPECT_EQ(1, visitor.syn_frame_count_); | |
1072 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
1073 EXPECT_EQ(0, visitor.headers_frame_count_); | |
1074 EXPECT_EQ(0, visitor.data_bytes_); | |
1075 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1076 EXPECT_EQ(1, visitor.fin_flag_count_); | |
1077 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
1078 EXPECT_EQ(0, visitor.data_frame_count_); | |
1079 } | |
1080 | |
1081 TEST_F(SpdyFramerSpdy2Test, HeaderCompression) { | |
1082 SpdyFramer send_framer(kVer); | |
1083 SpdyFramer recv_framer(kVer); | |
1084 | |
1085 send_framer.set_enable_compression(true); | |
1086 recv_framer.set_enable_compression(true); | |
1087 | |
1088 const char kHeader1[] = "header1"; | |
1089 const char kHeader2[] = "header2"; | |
1090 const char kHeader3[] = "header3"; | |
1091 const char kValue1[] = "value1"; | |
1092 const char kValue2[] = "value2"; | |
1093 const char kValue3[] = "value3"; | |
1094 | |
1095 // SYN_STREAM #1 | |
1096 SpdyHeaderBlock block; | |
1097 block[kHeader1] = kValue1; | |
1098 block[kHeader2] = kValue2; | |
1099 SpdyControlFlags flags(CONTROL_FLAG_NONE); | |
1100 scoped_ptr<SpdySynStreamControlFrame> syn_frame_1( | |
1101 send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); | |
1102 EXPECT_TRUE(syn_frame_1.get() != NULL); | |
1103 | |
1104 // SYN_STREAM #2 | |
1105 block[kHeader3] = kValue3; | |
1106 scoped_ptr<SpdySynStreamControlFrame> syn_frame_2( | |
1107 send_framer.CreateSynStream(3, 0, 0, flags, true, &block)); | |
1108 EXPECT_TRUE(syn_frame_2.get() != NULL); | |
1109 | |
1110 // Now start decompressing | |
1111 scoped_ptr<SpdyFrame> decompressed; | |
1112 scoped_ptr<SpdySynStreamControlFrame> syn_frame; | |
1113 scoped_ptr<std::string> serialized_headers; | |
1114 SpdyHeaderBlock decompressed_headers; | |
1115 | |
1116 // Decompress SYN_STREAM #1 | |
1117 decompressed.reset(SpdyFramerTestUtil::DecompressFrame( | |
1118 &recv_framer, *syn_frame_1.get())); | |
1119 EXPECT_TRUE(decompressed.get() != NULL); | |
1120 EXPECT_TRUE(decompressed->is_control_frame()); | |
1121 EXPECT_EQ(SYN_STREAM, | |
1122 reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type()); | |
1123 syn_frame.reset(new SpdySynStreamControlFrame(decompressed->data(), false)); | |
1124 serialized_headers.reset(new std::string(syn_frame->header_block(), | |
1125 syn_frame->header_block_len())); | |
1126 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(), | |
1127 serialized_headers->size(), | |
1128 &decompressed_headers)); | |
1129 EXPECT_EQ(2u, decompressed_headers.size()); | |
1130 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); | |
1131 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); | |
1132 | |
1133 // Decompress SYN_STREAM #2 | |
1134 decompressed.reset(SpdyFramerTestUtil::DecompressFrame( | |
1135 &recv_framer, *syn_frame_2.get())); | |
1136 EXPECT_TRUE(decompressed.get() != NULL); | |
1137 EXPECT_TRUE(decompressed->is_control_frame()); | |
1138 EXPECT_EQ(SYN_STREAM, | |
1139 reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type()); | |
1140 syn_frame.reset(new SpdySynStreamControlFrame(decompressed->data(), false)); | |
1141 serialized_headers.reset(new std::string(syn_frame->header_block(), | |
1142 syn_frame->header_block_len())); | |
1143 decompressed_headers.clear(); | |
1144 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(), | |
1145 serialized_headers->size(), | |
1146 &decompressed_headers)); | |
1147 EXPECT_EQ(3u, decompressed_headers.size()); | |
1148 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); | |
1149 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); | |
1150 EXPECT_EQ(kValue3, decompressed_headers[kHeader3]); | |
1151 | |
1152 // We didn't have data streams, so we shouldn't have (de)compressors. | |
1153 EXPECT_EQ(0, send_framer.num_stream_compressors()); | |
1154 EXPECT_EQ(0, send_framer.num_stream_decompressors()); | |
1155 EXPECT_EQ(0, recv_framer.num_stream_compressors()); | |
1156 EXPECT_EQ(0, recv_framer.num_stream_decompressors()); | |
1157 } | |
1158 | |
1159 // Verify we don't leak when we leave streams unclosed | |
1160 TEST_F(SpdyFramerSpdy2Test, UnclosedStreamDataCompressors) { | |
1161 SpdyFramer send_framer(kVer); | |
1162 | |
1163 send_framer.set_enable_compression(true); | |
1164 | |
1165 const char kHeader1[] = "header1"; | |
1166 const char kHeader2[] = "header2"; | |
1167 const char kValue1[] = "value1"; | |
1168 const char kValue2[] = "value2"; | |
1169 | |
1170 SpdyHeaderBlock block; | |
1171 block[kHeader1] = kValue1; | |
1172 block[kHeader2] = kValue2; | |
1173 SpdyControlFlags flags(CONTROL_FLAG_NONE); | |
1174 scoped_ptr<SpdyFrame> syn_frame( | |
1175 send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); | |
1176 EXPECT_TRUE(syn_frame.get() != NULL); | |
1177 | |
1178 const char bytes[] = "this is a test test test test test!"; | |
1179 scoped_ptr<SpdyFrame> send_frame( | |
1180 send_framer.CreateDataFrame( | |
1181 1, bytes, arraysize(bytes), | |
1182 static_cast<SpdyDataFlags>(DATA_FLAG_FIN))); | |
1183 EXPECT_TRUE(send_frame.get() != NULL); | |
1184 | |
1185 // Run the inputs through the framer. | |
1186 TestSpdyVisitor visitor; | |
1187 visitor.use_compression_ = true; | |
1188 const unsigned char* data; | |
1189 data = reinterpret_cast<const unsigned char*>(syn_frame->data()); | |
1190 visitor.SimulateInFramer(data, syn_frame->length() + SpdyFrame::kHeaderSize); | |
1191 data = reinterpret_cast<const unsigned char*>(send_frame->data()); | |
1192 visitor.SimulateInFramer(data, send_frame->length() + SpdyFrame::kHeaderSize); | |
1193 | |
1194 EXPECT_EQ(0, visitor.error_count_); | |
1195 EXPECT_EQ(1, visitor.syn_frame_count_); | |
1196 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
1197 EXPECT_EQ(0, visitor.headers_frame_count_); | |
1198 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); | |
1199 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1200 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1201 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
1202 EXPECT_EQ(1, visitor.data_frame_count_); | |
1203 | |
1204 // We closed the streams, so all compressors should be down. | |
1205 EXPECT_EQ(0, visitor.framer_.num_stream_compressors()); | |
1206 EXPECT_EQ(0, visitor.framer_.num_stream_decompressors()); | |
1207 EXPECT_EQ(0, send_framer.num_stream_compressors()); | |
1208 EXPECT_EQ(0, send_framer.num_stream_decompressors()); | |
1209 } | |
1210 | |
1211 // Verify we can decompress the stream even if handed over to the | |
1212 // framer 1 byte at a time. | |
1213 TEST_F(SpdyFramerSpdy2Test, UnclosedStreamDataCompressorsOneByteAtATime) { | |
1214 SpdyFramer send_framer(kVer); | |
1215 | |
1216 send_framer.set_enable_compression(true); | |
1217 | |
1218 const char kHeader1[] = "header1"; | |
1219 const char kHeader2[] = "header2"; | |
1220 const char kValue1[] = "value1"; | |
1221 const char kValue2[] = "value2"; | |
1222 | |
1223 SpdyHeaderBlock block; | |
1224 block[kHeader1] = kValue1; | |
1225 block[kHeader2] = kValue2; | |
1226 SpdyControlFlags flags(CONTROL_FLAG_NONE); | |
1227 scoped_ptr<SpdyFrame> syn_frame( | |
1228 send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); | |
1229 EXPECT_TRUE(syn_frame.get() != NULL); | |
1230 | |
1231 const char bytes[] = "this is a test test test test test!"; | |
1232 scoped_ptr<SpdyFrame> send_frame( | |
1233 send_framer.CreateDataFrame( | |
1234 1, bytes, arraysize(bytes), | |
1235 static_cast<SpdyDataFlags>(DATA_FLAG_FIN))); | |
1236 EXPECT_TRUE(send_frame.get() != NULL); | |
1237 | |
1238 // Run the inputs through the framer. | |
1239 TestSpdyVisitor visitor; | |
1240 visitor.use_compression_ = true; | |
1241 const unsigned char* data; | |
1242 data = reinterpret_cast<const unsigned char*>(syn_frame->data()); | |
1243 for (size_t idx = 0; | |
1244 idx < syn_frame->length() + SpdyFrame::kHeaderSize; | |
1245 ++idx) { | |
1246 visitor.SimulateInFramer(data + idx, 1); | |
1247 ASSERT_EQ(0, visitor.error_count_); | |
1248 } | |
1249 data = reinterpret_cast<const unsigned char*>(send_frame->data()); | |
1250 for (size_t idx = 0; | |
1251 idx < send_frame->length() + SpdyFrame::kHeaderSize; | |
1252 ++idx) { | |
1253 visitor.SimulateInFramer(data + idx, 1); | |
1254 ASSERT_EQ(0, visitor.error_count_); | |
1255 } | |
1256 | |
1257 EXPECT_EQ(0, visitor.error_count_); | |
1258 EXPECT_EQ(1, visitor.syn_frame_count_); | |
1259 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
1260 EXPECT_EQ(0, visitor.headers_frame_count_); | |
1261 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); | |
1262 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1263 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1264 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
1265 EXPECT_EQ(1, visitor.data_frame_count_); | |
1266 | |
1267 // We closed the streams, so all compressors should be down. | |
1268 EXPECT_EQ(0, visitor.framer_.num_stream_compressors()); | |
1269 EXPECT_EQ(0, visitor.framer_.num_stream_decompressors()); | |
1270 EXPECT_EQ(0, send_framer.num_stream_compressors()); | |
1271 EXPECT_EQ(0, send_framer.num_stream_decompressors()); | |
1272 } | |
1273 | |
1274 TEST_F(SpdyFramerSpdy2Test, WindowUpdateFrame) { | |
1275 SpdyFramer framer(kVer); | |
1276 scoped_ptr<SpdyWindowUpdateControlFrame> window_update_frame( | |
1277 framer.CreateWindowUpdate(1, 0x12345678)); | |
1278 | |
1279 const unsigned char expected_data_frame[] = { | |
1280 0x80, kVer, 0x00, 0x09, | |
1281 0x00, 0x00, 0x00, 0x08, | |
1282 0x00, 0x00, 0x00, 0x01, | |
1283 0x12, 0x34, 0x56, 0x78 | |
1284 }; | |
1285 | |
1286 EXPECT_EQ(16u, window_update_frame->size()); | |
1287 EXPECT_EQ(0, | |
1288 memcmp(window_update_frame->data(), expected_data_frame, 16)); | |
1289 } | |
1290 | |
1291 TEST_F(SpdyFramerSpdy2Test, CreateDataFrame) { | |
1292 SpdyFramer framer(kVer); | |
1293 | |
1294 { | |
1295 const char kDescription[] = "'hello' data frame, no FIN"; | |
1296 const unsigned char kFrameData[] = { | |
1297 0x00, 0x00, 0x00, 0x01, | |
1298 0x00, 0x00, 0x00, 0x05, | |
1299 'h', 'e', 'l', 'l', | |
1300 'o' | |
1301 }; | |
1302 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
1303 1, "hello", 5, DATA_FLAG_NONE)); | |
1304 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1305 } | |
1306 | |
1307 { | |
1308 const char kDescription[] = "Data frame with negative data byte, no FIN"; | |
1309 const unsigned char kFrameData[] = { | |
1310 0x00, 0x00, 0x00, 0x01, | |
1311 0x00, 0x00, 0x00, 0x01, | |
1312 0xff | |
1313 }; | |
1314 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
1315 1, "\xff", 1, DATA_FLAG_NONE)); | |
1316 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1317 } | |
1318 | |
1319 { | |
1320 const char kDescription[] = "'hello' data frame, with FIN"; | |
1321 const unsigned char kFrameData[] = { | |
1322 0x00, 0x00, 0x00, 0x01, | |
1323 0x01, 0x00, 0x00, 0x05, | |
1324 'h', 'e', 'l', 'l', | |
1325 'o' | |
1326 }; | |
1327 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
1328 1, "hello", 5, DATA_FLAG_FIN)); | |
1329 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1330 } | |
1331 | |
1332 { | |
1333 const char kDescription[] = "Empty data frame"; | |
1334 const unsigned char kFrameData[] = { | |
1335 0x00, 0x00, 0x00, 0x01, | |
1336 0x00, 0x00, 0x00, 0x00, | |
1337 }; | |
1338 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
1339 1, "", 0, DATA_FLAG_NONE)); | |
1340 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1341 } | |
1342 | |
1343 { | |
1344 const char kDescription[] = "Data frame with max stream ID"; | |
1345 const unsigned char kFrameData[] = { | |
1346 0x7f, 0xff, 0xff, 0xff, | |
1347 0x01, 0x00, 0x00, 0x05, | |
1348 'h', 'e', 'l', 'l', | |
1349 'o' | |
1350 }; | |
1351 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
1352 0x7fffffff, "hello", 5, DATA_FLAG_FIN)); | |
1353 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1354 } | |
1355 | |
1356 { | |
1357 const char kDescription[] = "Large data frame"; | |
1358 const int kDataSize = 4 * 1024 * 1024; // 4 MB | |
1359 const std::string kData(kDataSize, 'A'); | |
1360 const unsigned char kFrameHeader[] = { | |
1361 0x00, 0x00, 0x00, 0x01, | |
1362 0x01, 0x40, 0x00, 0x00, | |
1363 }; | |
1364 | |
1365 const int kFrameSize = arraysize(kFrameHeader) + kDataSize; | |
1366 scoped_array<unsigned char> expected_frame_data( | |
1367 new unsigned char[kFrameSize]); | |
1368 memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader)); | |
1369 memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize); | |
1370 | |
1371 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
1372 1, kData.data(), kData.size(), DATA_FLAG_FIN)); | |
1373 CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize); | |
1374 } | |
1375 } | |
1376 | |
1377 TEST_F(SpdyFramerSpdy2Test, CreateSynStreamUncompressed) { | |
1378 SpdyFramer framer(kVer); | |
1379 framer.set_enable_compression(false); | |
1380 | |
1381 { | |
1382 const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN"; | |
1383 | |
1384 SpdyHeaderBlock headers; | |
1385 headers["bar"] = "foo"; | |
1386 headers["foo"] = "bar"; | |
1387 | |
1388 const unsigned char kPri = | |
1389 (SPDY_VERSION_FOR_TESTS != 2) ? 0xE0 : 0xC0; | |
1390 const unsigned char kV2FrameData[] = { | |
1391 0x80, kVer, 0x00, 0x01, | |
1392 0x00, 0x00, 0x00, 0x20, | |
1393 0x00, 0x00, 0x00, 0x01, | |
1394 0x00, 0x00, 0x00, 0x00, | |
1395 kPri, 0x00, 0x00, 0x02, | |
1396 0x00, 0x03, 'b', 'a', | |
1397 'r', 0x00, 0x03, 'f', | |
1398 'o', 'o', 0x00, 0x03, | |
1399 'f', 'o', 'o', 0x00, | |
1400 0x03, 'b', 'a', 'r' | |
1401 }; | |
1402 const unsigned char kV3FrameData[] = { | |
1403 0x80, kVer, 0x00, 0x01, | |
1404 0x00, 0x00, 0x00, 0x2a, | |
1405 0x00, 0x00, 0x00, 0x01, | |
1406 0x00, 0x00, 0x00, 0x00, | |
1407 kPri, 0x00, 0x00, 0x00, | |
1408 0x00, 0x02, 0x00, 0x00, | |
1409 0x00, 0x03, 'b', 'a', | |
1410 'r', 0x00, 0x00, 0x00, | |
1411 0x03, 'f', 'o', 'o', | |
1412 0x00, 0x00, 0x00, 0x03, | |
1413 'f', 'o', 'o', 0x00, | |
1414 0x00, 0x00, 0x03, 'b', | |
1415 'a', 'r' | |
1416 }; | |
1417 scoped_ptr<SpdySynStreamControlFrame> frame(framer.CreateSynStream( | |
1418 1, 0, framer.GetLowestPriority(), CONTROL_FLAG_NONE, false, &headers)); | |
1419 CompareFrame(kDescription, | |
1420 *frame, | |
1421 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1422 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1423 : arraysize(kV3FrameData)); | |
1424 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); | |
1425 } | |
1426 | |
1427 { | |
1428 const char kDescription[] = | |
1429 "SYN_STREAM frame with a 0-length header name, highest pri, FIN, " | |
1430 "max stream ID"; | |
1431 | |
1432 SpdyHeaderBlock headers; | |
1433 headers[""] = "foo"; | |
1434 headers["foo"] = "bar"; | |
1435 | |
1436 const unsigned char kV2FrameData[] = { | |
1437 0x80, kVer, 0x00, 0x01, | |
1438 0x01, 0x00, 0x00, 0x1D, | |
1439 0x7f, 0xff, 0xff, 0xff, | |
1440 0x7f, 0xff, 0xff, 0xff, | |
1441 0x00, 0x00, 0x00, 0x02, | |
1442 0x00, 0x00, 0x00, 0x03, | |
1443 'f', 'o', 'o', 0x00, | |
1444 0x03, 'f', 'o', 'o', | |
1445 0x00, 0x03, 'b', 'a', | |
1446 'r' | |
1447 }; | |
1448 const unsigned char kV3FrameData[] = { | |
1449 0x80, kVer, 0x00, 0x01, | |
1450 0x01, 0x00, 0x00, 0x27, | |
1451 0x7f, 0xff, 0xff, 0xff, | |
1452 0x7f, 0xff, 0xff, 0xff, | |
1453 0x00, 0x00, 0x00, 0x00, | |
1454 0x00, 0x02, 0x00, 0x00, | |
1455 0x00, 0x00, 0x00, 0x00, | |
1456 0x00, 0x03, 'f', 'o', | |
1457 'o', 0x00, 0x00, 0x00, | |
1458 0x03, 'f', 'o', 'o', | |
1459 0x00, 0x00, 0x00, 0x03, | |
1460 'b', 'a', 'r' | |
1461 }; | |
1462 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( | |
1463 0x7fffffff, 0x7fffffff, framer.GetHighestPriority(), CONTROL_FLAG_FIN, | |
1464 false, &headers)); | |
1465 CompareFrame(kDescription, | |
1466 *frame, | |
1467 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1468 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1469 : arraysize(kV3FrameData)); | |
1470 } | |
1471 | |
1472 { | |
1473 const char kDescription[] = | |
1474 "SYN_STREAM frame with a 0-length header val, high pri, FIN, " | |
1475 "max stream ID"; | |
1476 | |
1477 SpdyHeaderBlock headers; | |
1478 headers["bar"] = "foo"; | |
1479 headers["foo"] = ""; | |
1480 | |
1481 const unsigned char kPri = | |
1482 (SPDY_VERSION_FOR_TESTS != 2) ? 0x20 : 0x40; | |
1483 const unsigned char kV2FrameData[] = { | |
1484 0x80, kVer, 0x00, 0x01, | |
1485 0x01, 0x00, 0x00, 0x1D, | |
1486 0x7f, 0xff, 0xff, 0xff, | |
1487 0x7f, 0xff, 0xff, 0xff, | |
1488 kPri, 0x00, 0x00, 0x02, | |
1489 0x00, 0x03, 'b', 'a', | |
1490 'r', 0x00, 0x03, 'f', | |
1491 'o', 'o', 0x00, 0x03, | |
1492 'f', 'o', 'o', 0x00, | |
1493 0x00 | |
1494 }; | |
1495 const unsigned char kV3FrameData[] = { | |
1496 0x80, kVer, 0x00, 0x01, | |
1497 0x01, 0x00, 0x00, 0x27, | |
1498 0x7f, 0xff, 0xff, 0xff, | |
1499 0x7f, 0xff, 0xff, 0xff, | |
1500 kPri, 0x00, 0x00, 0x00, | |
1501 0x00, 0x02, 0x00, 0x00, | |
1502 0x00, 0x03, 'b', 'a', | |
1503 'r', 0x00, 0x00, 0x00, | |
1504 0x03, 'f', 'o', 'o', | |
1505 0x00, 0x00, 0x00, 0x03, | |
1506 'f', 'o', 'o', 0x00, | |
1507 0x00, 0x00, 0x00 | |
1508 }; | |
1509 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( | |
1510 0x7fffffff, 0x7fffffff, 1, CONTROL_FLAG_FIN, false, &headers)); | |
1511 CompareFrame(kDescription, | |
1512 *frame, | |
1513 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1514 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1515 : arraysize(kV3FrameData)); | |
1516 } | |
1517 } | |
1518 | |
1519 TEST_F(SpdyFramerSpdy2Test, CreateSynStreamCompressed) { | |
1520 SpdyFramer framer(kVer); | |
1521 framer.set_enable_compression(true); | |
1522 | |
1523 { | |
1524 const char kDescription[] = | |
1525 "SYN_STREAM frame, low pri, no FIN"; | |
1526 | |
1527 SpdyHeaderBlock headers; | |
1528 headers["bar"] = "foo"; | |
1529 headers["foo"] = "bar"; | |
1530 | |
1531 const SpdyPriority priority = | |
1532 (SPDY_VERSION_FOR_TESTS != 2) ? 4 : 2; | |
1533 const unsigned char kV2FrameData[] = { | |
1534 0x80, kVer, 0x00, 0x01, | |
1535 0x00, 0x00, 0x00, 0x25, | |
1536 0x00, 0x00, 0x00, 0x01, | |
1537 0x00, 0x00, 0x00, 0x00, | |
1538 0x80, 0x00, 0x38, 0xea, | |
1539 0xdf, 0xa2, 0x51, 0xb2, | |
1540 0x62, 0x60, 0x62, 0x60, | |
1541 0x4e, 0x4a, 0x2c, 0x62, | |
1542 0x60, 0x4e, 0xcb, 0xcf, | |
1543 0x87, 0x12, 0x40, 0x2e, | |
1544 0x00, 0x00, 0x00, 0xff, | |
1545 0xff | |
1546 }; | |
1547 const unsigned char kV3FrameData[] = { | |
1548 0x80, kVer, 0x00, 0x01, | |
1549 0x00, 0x00, 0x00, 0x27, | |
1550 0x00, 0x00, 0x00, 0x01, | |
1551 0x00, 0x00, 0x00, 0x00, | |
1552 0x80, 0x00, 0x38, 0xEA, | |
1553 0xE3, 0xC6, 0xA7, 0xC2, | |
1554 0x02, 0xE5, 0x0E, 0x50, | |
1555 0xC2, 0x4B, 0x4A, 0x04, | |
1556 0xE5, 0x0B, 0xE6, 0xB4, | |
1557 0xFC, 0x7C, 0x24, 0x0A, | |
1558 0x28, 0x08, 0x00, 0x00, | |
1559 0x00, 0xFF, 0xFF | |
1560 }; | |
1561 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( | |
1562 1, 0, priority, CONTROL_FLAG_NONE, true, &headers)); | |
1563 CompareFrame(kDescription, | |
1564 *frame, | |
1565 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1566 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1567 : arraysize(kV3FrameData)); | |
1568 } | |
1569 } | |
1570 | |
1571 TEST_F(SpdyFramerSpdy2Test, CreateSynReplyUncompressed) { | |
1572 SpdyFramer framer(kVer); | |
1573 framer.set_enable_compression(false); | |
1574 | |
1575 { | |
1576 const char kDescription[] = "SYN_REPLY frame, no FIN"; | |
1577 | |
1578 SpdyHeaderBlock headers; | |
1579 headers["bar"] = "foo"; | |
1580 headers["foo"] = "bar"; | |
1581 | |
1582 const unsigned char kV2FrameData[] = { | |
1583 0x80, kVer, 0x00, 0x02, | |
1584 0x00, 0x00, 0x00, 0x1C, | |
1585 0x00, 0x00, 0x00, 0x01, | |
1586 0x00, 0x00, 0x00, 0x02, | |
1587 0x00, 0x03, 'b', 'a', | |
1588 'r', 0x00, 0x03, 'f', | |
1589 'o', 'o', 0x00, 0x03, | |
1590 'f', 'o', 'o', 0x00, | |
1591 0x03, 'b', 'a', 'r' | |
1592 }; | |
1593 const unsigned char kV3FrameData[] = { | |
1594 0x80, kVer, 0x00, 0x02, | |
1595 0x00, 0x00, 0x00, 0x24, | |
1596 0x00, 0x00, 0x00, 0x01, | |
1597 0x00, 0x00, 0x00, 0x02, | |
1598 0x00, 0x00, 0x00, 0x03, | |
1599 'b', 'a', 'r', 0x00, | |
1600 0x00, 0x00, 0x03, 'f', | |
1601 'o', 'o', 0x00, 0x00, | |
1602 0x00, 0x03, 'f', 'o', | |
1603 'o', 0x00, 0x00, 0x00, | |
1604 0x03, 'b', 'a', 'r' | |
1605 }; | |
1606 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( | |
1607 1, CONTROL_FLAG_NONE, false, &headers)); | |
1608 CompareFrame(kDescription, | |
1609 *frame, | |
1610 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1611 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1612 : arraysize(kV3FrameData)); | |
1613 } | |
1614 | |
1615 { | |
1616 const char kDescription[] = | |
1617 "SYN_REPLY frame with a 0-length header name, FIN, max stream ID"; | |
1618 | |
1619 SpdyHeaderBlock headers; | |
1620 headers[""] = "foo"; | |
1621 headers["foo"] = "bar"; | |
1622 | |
1623 const unsigned char kV2FrameData[] = { | |
1624 0x80, kVer, 0x00, 0x02, | |
1625 0x01, 0x00, 0x00, 0x19, | |
1626 0x7f, 0xff, 0xff, 0xff, | |
1627 0x00, 0x00, 0x00, 0x02, | |
1628 0x00, 0x00, 0x00, 0x03, | |
1629 'f', 'o', 'o', 0x00, | |
1630 0x03, 'f', 'o', 'o', | |
1631 0x00, 0x03, 'b', 'a', | |
1632 'r' | |
1633 }; | |
1634 const unsigned char kV3FrameData[] = { | |
1635 0x80, kVer, 0x00, 0x02, | |
1636 0x01, 0x00, 0x00, 0x21, | |
1637 0x7f, 0xff, 0xff, 0xff, | |
1638 0x00, 0x00, 0x00, 0x02, | |
1639 0x00, 0x00, 0x00, 0x00, | |
1640 0x00, 0x00, 0x00, 0x03, | |
1641 'f', 'o', 'o', 0x00, | |
1642 0x00, 0x00, 0x03, 'f', | |
1643 'o', 'o', 0x00, 0x00, | |
1644 0x00, 0x03, 'b', 'a', | |
1645 'r' | |
1646 }; | |
1647 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( | |
1648 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); | |
1649 CompareFrame(kDescription, | |
1650 *frame, | |
1651 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1652 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1653 : arraysize(kV3FrameData)); | |
1654 } | |
1655 | |
1656 { | |
1657 const char kDescription[] = | |
1658 "SYN_REPLY frame with a 0-length header val, FIN, max stream ID"; | |
1659 | |
1660 SpdyHeaderBlock headers; | |
1661 headers["bar"] = "foo"; | |
1662 headers["foo"] = ""; | |
1663 | |
1664 const unsigned char kV2FrameData[] = { | |
1665 0x80, kVer, 0x00, 0x02, | |
1666 0x01, 0x00, 0x00, 0x19, | |
1667 0x7f, 0xff, 0xff, 0xff, | |
1668 0x00, 0x00, 0x00, 0x02, | |
1669 0x00, 0x03, 'b', 'a', | |
1670 'r', 0x00, 0x03, 'f', | |
1671 'o', 'o', 0x00, 0x03, | |
1672 'f', 'o', 'o', 0x00, | |
1673 0x00 | |
1674 }; | |
1675 const unsigned char kV3FrameData[] = { | |
1676 0x80, kVer, 0x00, 0x02, | |
1677 0x01, 0x00, 0x00, 0x21, | |
1678 0x7f, 0xff, 0xff, 0xff, | |
1679 0x00, 0x00, 0x00, 0x02, | |
1680 0x00, 0x00, 0x00, 0x03, | |
1681 'b', 'a', 'r', 0x00, | |
1682 0x00, 0x00, 0x03, 'f', | |
1683 'o', 'o', 0x00, 0x00, | |
1684 0x00, 0x03, 'f', 'o', | |
1685 'o', 0x00, 0x00, 0x00, | |
1686 0x00 | |
1687 }; | |
1688 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( | |
1689 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); | |
1690 CompareFrame(kDescription, | |
1691 *frame, | |
1692 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1693 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1694 : arraysize(kV3FrameData)); | |
1695 } | |
1696 } | |
1697 | |
1698 TEST_F(SpdyFramerSpdy2Test, CreateSynReplyCompressed) { | |
1699 SpdyFramer framer(kVer); | |
1700 framer.set_enable_compression(true); | |
1701 | |
1702 { | |
1703 const char kDescription[] = "SYN_REPLY frame, no FIN"; | |
1704 | |
1705 SpdyHeaderBlock headers; | |
1706 headers["bar"] = "foo"; | |
1707 headers["foo"] = "bar"; | |
1708 | |
1709 const unsigned char kV2FrameData[] = { | |
1710 0x80, kVer, 0x00, 0x02, | |
1711 0x00, 0x00, 0x00, 0x21, | |
1712 0x00, 0x00, 0x00, 0x01, | |
1713 0x00, 0x00, 0x38, 0xea, | |
1714 0xdf, 0xa2, 0x51, 0xb2, | |
1715 0x62, 0x60, 0x62, 0x60, | |
1716 0x4e, 0x4a, 0x2c, 0x62, | |
1717 0x60, 0x4e, 0xcb, 0xcf, | |
1718 0x87, 0x12, 0x40, 0x2e, | |
1719 0x00, 0x00, 0x00, 0xff, | |
1720 0xff | |
1721 }; | |
1722 const unsigned char kV3FrameData[] = { | |
1723 0x80, kVer, 0x00, 0x02, | |
1724 0x00, 0x00, 0x00, 0x21, | |
1725 0x00, 0x00, 0x00, 0x01, | |
1726 0x38, 0xea, 0xe3, 0xc6, | |
1727 0xa7, 0xc2, 0x02, 0xe5, | |
1728 0x0e, 0x50, 0xc2, 0x4b, | |
1729 0x4a, 0x04, 0xe5, 0x0b, | |
1730 0xe6, 0xb4, 0xfc, 0x7c, | |
1731 0x24, 0x0a, 0x28, 0x08, | |
1732 0x00, 0x00, 0x00, 0xff, | |
1733 0xff | |
1734 }; | |
1735 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( | |
1736 1, CONTROL_FLAG_NONE, true, &headers)); | |
1737 CompareFrame(kDescription, | |
1738 *frame, | |
1739 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1740 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1741 : arraysize(kV3FrameData)); | |
1742 } | |
1743 } | |
1744 | |
1745 TEST_F(SpdyFramerSpdy2Test, CreateRstStream) { | |
1746 SpdyFramer framer(kVer); | |
1747 | |
1748 { | |
1749 const char kDescription[] = "RST_STREAM frame"; | |
1750 const unsigned char kFrameData[] = { | |
1751 0x80, kVer, 0x00, 0x03, | |
1752 0x00, 0x00, 0x00, 0x08, | |
1753 0x00, 0x00, 0x00, 0x01, | |
1754 0x00, 0x00, 0x00, 0x01, | |
1755 }; | |
1756 scoped_ptr<SpdyRstStreamControlFrame> frame( | |
1757 framer.CreateRstStream(1, PROTOCOL_ERROR)); | |
1758 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1759 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); | |
1760 } | |
1761 | |
1762 { | |
1763 const char kDescription[] = "RST_STREAM frame with max stream ID"; | |
1764 const unsigned char kFrameData[] = { | |
1765 0x80, kVer, 0x00, 0x03, | |
1766 0x00, 0x00, 0x00, 0x08, | |
1767 0x7f, 0xff, 0xff, 0xff, | |
1768 0x00, 0x00, 0x00, 0x01, | |
1769 }; | |
1770 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF, | |
1771 PROTOCOL_ERROR)); | |
1772 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1773 } | |
1774 | |
1775 { | |
1776 const char kDescription[] = "RST_STREAM frame with max status code"; | |
1777 const unsigned char kFrameData[] = { | |
1778 0x80, kVer, 0x00, 0x03, | |
1779 0x00, 0x00, 0x00, 0x08, | |
1780 0x7f, 0xff, 0xff, 0xff, | |
1781 0x00, 0x00, 0x00, 0x06, | |
1782 }; | |
1783 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF, | |
1784 INTERNAL_ERROR)); | |
1785 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1786 } | |
1787 } | |
1788 | |
1789 TEST_F(SpdyFramerSpdy2Test, CreateSettings) { | |
1790 SpdyFramer framer(kVer); | |
1791 | |
1792 { | |
1793 const char kDescription[] = "Network byte order SETTINGS frame"; | |
1794 | |
1795 uint32 kValue = 0x0a0b0c0d; | |
1796 uint8 kFlags = 0x04; | |
1797 uint32 kId = 0x030201; | |
1798 SettingsFlagsAndId idAndFlags(kFlags, kId); | |
1799 | |
1800 SpdySettings settings; | |
1801 settings.push_back(SpdySetting(idAndFlags, kValue)); | |
1802 | |
1803 EXPECT_EQ(kValue, settings.back().second); | |
1804 EXPECT_EQ(kFlags, settings.back().first.flags()); | |
1805 EXPECT_EQ(kId, settings.back().first.id()); | |
1806 | |
1807 const unsigned char kFrameDatav2[] = { | |
1808 0x80, kVer, 0x00, 0x04, | |
1809 0x00, 0x00, 0x00, 0x0c, | |
1810 0x00, 0x00, 0x00, 0x01, | |
1811 0x01, 0x02, 0x03, 0x04, | |
1812 0x0a, 0x0b, 0x0c, 0x0d, | |
1813 }; | |
1814 | |
1815 const unsigned char kFrameDatav3[] = { | |
1816 0x80, kVer, 0x00, 0x04, | |
1817 0x00, 0x00, 0x00, 0x0c, | |
1818 0x00, 0x00, 0x00, 0x01, | |
1819 0x04, 0x03, 0x02, 0x01, | |
1820 0x0a, 0x0b, 0x0c, 0x0d, | |
1821 }; | |
1822 | |
1823 scoped_ptr<SpdySettingsControlFrame> frame(framer.CreateSettings(settings)); | |
1824 CompareFrame(kDescription, | |
1825 *frame, | |
1826 (SPDY_VERSION_FOR_TESTS < 3) ? kFrameDatav2 : kFrameDatav3, | |
1827 arraysize(kFrameDatav3)); // Size is unchanged among versions. | |
1828 EXPECT_EQ(SpdyFramer::kInvalidStream, | |
1829 SpdyFramer::GetControlFrameStreamId(frame.get())); | |
1830 | |
1831 // Make sure that ParseSettings also works as advertised. | |
1832 SpdySettings parsed_settings; | |
1833 EXPECT_TRUE(framer.ParseSettings(frame.get(), &parsed_settings)); | |
1834 EXPECT_EQ(settings.size(), parsed_settings.size()); | |
1835 EXPECT_EQ(kFlags, parsed_settings.back().first.flags()); | |
1836 EXPECT_EQ(kId, parsed_settings.back().first.id()); | |
1837 } | |
1838 | |
1839 { | |
1840 const char kDescription[] = "Basic SETTINGS frame"; | |
1841 | |
1842 SpdySettings settings; | |
1843 settings.push_back( | |
1844 SpdySettingFromWireFormat(0x00000000, 0x00000000)); // 1st Setting | |
1845 settings.push_back( | |
1846 SpdySettingFromWireFormat(0xffffffff, 0x00000001)); // 2nd Setting | |
1847 settings.push_back( | |
1848 SpdySettingFromWireFormat(0xff000001, 0x00000002)); // 3rd Setting | |
1849 | |
1850 // Duplicates allowed | |
1851 settings.push_back( | |
1852 SpdySettingFromWireFormat(0x01000002, 0x00000003)); // 4th Setting | |
1853 settings.push_back( | |
1854 SpdySettingFromWireFormat(0x01000002, 0x00000003)); // 5th Setting | |
1855 | |
1856 settings.push_back( | |
1857 SpdySettingFromWireFormat(0x01000003, 0x000000ff)); // 6th Setting | |
1858 settings.push_back( | |
1859 SpdySettingFromWireFormat(0x01000004, 0xff000001)); // 7th Setting | |
1860 settings.push_back( | |
1861 SpdySettingFromWireFormat(0x01000004, 0xffffffff)); // 8th Setting | |
1862 | |
1863 const unsigned char kFrameData[] = { | |
1864 0x80, kVer, 0x00, 0x04, | |
1865 0x00, 0x00, 0x00, 0x44, | |
1866 0x00, 0x00, 0x00, 0x08, | |
1867 0x00, 0x00, 0x00, 0x00, // 1st Setting | |
1868 0x00, 0x00, 0x00, 0x00, | |
1869 0xff, 0xff, 0xff, 0xff, // 2nd Setting | |
1870 0x00, 0x00, 0x00, 0x01, | |
1871 0x01, 0x00, 0x00, 0xff, // 3rd Setting | |
1872 0x00, 0x00, 0x00, 0x02, | |
1873 0x02, 0x00, 0x00, 0x01, // 4th Setting | |
1874 0x00, 0x00, 0x00, 0x03, | |
1875 0x02, 0x00, 0x00, 0x01, // 5th Setting | |
1876 0x00, 0x00, 0x00, 0x03, | |
1877 0x03, 0x00, 0x00, 0x01, // 6th Setting | |
1878 0x00, 0x00, 0x00, 0xff, | |
1879 0x04, 0x00, 0x00, 0x01, // 7th Setting | |
1880 0xff, 0x00, 0x00, 0x01, | |
1881 0x04, 0x00, 0x00, 0x01, // 8th Setting | |
1882 0xff, 0xff, 0xff, 0xff, | |
1883 }; | |
1884 scoped_ptr<SpdySettingsControlFrame> frame(framer.CreateSettings(settings)); | |
1885 CompareFrame(kDescription, | |
1886 *frame, | |
1887 kFrameData, | |
1888 arraysize(kFrameData)); | |
1889 EXPECT_EQ(SpdyFramer::kInvalidStream, | |
1890 SpdyFramer::GetControlFrameStreamId(frame.get())); | |
1891 } | |
1892 | |
1893 { | |
1894 const char kDescription[] = "Empty SETTINGS frame"; | |
1895 | |
1896 SpdySettings settings; | |
1897 | |
1898 const unsigned char kFrameData[] = { | |
1899 0x80, kVer, 0x00, 0x04, | |
1900 0x00, 0x00, 0x00, 0x04, | |
1901 0x00, 0x00, 0x00, 0x00, | |
1902 }; | |
1903 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); | |
1904 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1905 } | |
1906 } | |
1907 | |
1908 TEST_F(SpdyFramerSpdy2Test, CreatePingFrame) { | |
1909 SpdyFramer framer(kVer); | |
1910 | |
1911 { | |
1912 const char kDescription[] = "PING frame"; | |
1913 const unsigned char kFrameData[] = { | |
1914 0x80, kVer, 0x00, 0x06, | |
1915 0x00, 0x00, 0x00, 0x04, | |
1916 0x12, 0x34, 0x56, 0x78, | |
1917 }; | |
1918 scoped_ptr<SpdyPingControlFrame> frame(framer.CreatePingFrame(0x12345678u)); | |
1919 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1920 EXPECT_EQ(SpdyFramer::kInvalidStream, | |
1921 SpdyFramer::GetControlFrameStreamId(frame.get())); | |
1922 } | |
1923 } | |
1924 | |
1925 TEST_F(SpdyFramerSpdy2Test, CreateGoAway) { | |
1926 SpdyFramer framer(kVer); | |
1927 | |
1928 { | |
1929 const char kDescription[] = "GOAWAY frame"; | |
1930 const unsigned char kFrameData[] = { | |
1931 0x80, kVer, 0x00, 0x07, | |
1932 0x00, 0x00, 0x00, 0x04, | |
1933 0x00, 0x00, 0x00, 0x00, | |
1934 }; | |
1935 scoped_ptr<SpdyGoAwayControlFrame> frame(framer.CreateGoAway(0)); | |
1936 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1937 EXPECT_EQ(SpdyFramer::kInvalidStream, | |
1938 SpdyFramer::GetControlFrameStreamId(frame.get())); | |
1939 } | |
1940 | |
1941 { | |
1942 const char kDescription[] = "GOAWAY frame with max stream ID"; | |
1943 const unsigned char kFrameData[] = { | |
1944 0x80, kVer, 0x00, 0x07, | |
1945 0x00, 0x00, 0x00, 0x04, | |
1946 0x7f, 0xff, 0xff, 0xff, | |
1947 }; | |
1948 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF)); | |
1949 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
1950 } | |
1951 } | |
1952 | |
1953 TEST_F(SpdyFramerSpdy2Test, CreateHeadersUncompressed) { | |
1954 SpdyFramer framer(kVer); | |
1955 framer.set_enable_compression(false); | |
1956 | |
1957 { | |
1958 const char kDescription[] = "HEADERS frame, no FIN"; | |
1959 | |
1960 SpdyHeaderBlock headers; | |
1961 headers["bar"] = "foo"; | |
1962 headers["foo"] = "bar"; | |
1963 | |
1964 const unsigned char kV2FrameData[] = { | |
1965 0x80, kVer, 0x00, 0x08, | |
1966 0x00, 0x00, 0x00, 0x1C, | |
1967 0x00, 0x00, 0x00, 0x01, | |
1968 0x00, 0x00, 0x00, 0x02, | |
1969 0x00, 0x03, 'b', 'a', | |
1970 'r', 0x00, 0x03, 'f', | |
1971 'o', 'o', 0x00, 0x03, | |
1972 'f', 'o', 'o', 0x00, | |
1973 0x03, 'b', 'a', 'r' | |
1974 }; | |
1975 const unsigned char kV3FrameData[] = { | |
1976 0x80, kVer, 0x00, 0x08, | |
1977 0x00, 0x00, 0x00, 0x24, | |
1978 0x00, 0x00, 0x00, 0x01, | |
1979 0x00, 0x00, 0x00, 0x02, | |
1980 0x00, 0x00, 0x00, 0x03, | |
1981 'b', 'a', 'r', 0x00, | |
1982 0x00, 0x00, 0x03, 'f', | |
1983 'o', 'o', 0x00, 0x00, | |
1984 0x00, 0x03, 'f', 'o', | |
1985 'o', 0x00, 0x00, 0x00, | |
1986 0x03, 'b', 'a', 'r' | |
1987 }; | |
1988 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( | |
1989 1, CONTROL_FLAG_NONE, false, &headers)); | |
1990 CompareFrame(kDescription, | |
1991 *frame, | |
1992 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
1993 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
1994 : arraysize(kV3FrameData)); | |
1995 } | |
1996 | |
1997 { | |
1998 const char kDescription[] = | |
1999 "HEADERS frame with a 0-length header name, FIN, max stream ID"; | |
2000 | |
2001 SpdyHeaderBlock headers; | |
2002 headers[""] = "foo"; | |
2003 headers["foo"] = "bar"; | |
2004 | |
2005 const unsigned char kV2FrameData[] = { | |
2006 0x80, kVer, 0x00, 0x08, | |
2007 0x01, 0x00, 0x00, 0x19, | |
2008 0x7f, 0xff, 0xff, 0xff, | |
2009 0x00, 0x00, 0x00, 0x02, | |
2010 0x00, 0x00, 0x00, 0x03, | |
2011 'f', 'o', 'o', 0x00, | |
2012 0x03, 'f', 'o', 'o', | |
2013 0x00, 0x03, 'b', 'a', | |
2014 'r' | |
2015 }; | |
2016 const unsigned char kV3FrameData[] = { | |
2017 0x80, kVer, 0x00, 0x08, | |
2018 0x01, 0x00, 0x00, 0x21, | |
2019 0x7f, 0xff, 0xff, 0xff, | |
2020 0x00, 0x00, 0x00, 0x02, | |
2021 0x00, 0x00, 0x00, 0x00, | |
2022 0x00, 0x00, 0x00, 0x03, | |
2023 'f', 'o', 'o', 0x00, | |
2024 0x00, 0x00, 0x03, 'f', | |
2025 'o', 'o', 0x00, 0x00, | |
2026 0x00, 0x03, 'b', 'a', | |
2027 'r' | |
2028 }; | |
2029 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( | |
2030 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); | |
2031 CompareFrame(kDescription, | |
2032 *frame, | |
2033 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
2034 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
2035 : arraysize(kV3FrameData)); | |
2036 } | |
2037 | |
2038 { | |
2039 const char kDescription[] = | |
2040 "HEADERS frame with a 0-length header val, FIN, max stream ID"; | |
2041 | |
2042 SpdyHeaderBlock headers; | |
2043 headers["bar"] = "foo"; | |
2044 headers["foo"] = ""; | |
2045 | |
2046 const unsigned char kV2FrameData[] = { | |
2047 0x80, kVer, 0x00, 0x08, | |
2048 0x01, 0x00, 0x00, 0x19, | |
2049 0x7f, 0xff, 0xff, 0xff, | |
2050 0x00, 0x00, 0x00, 0x02, | |
2051 0x00, 0x03, 'b', 'a', | |
2052 'r', 0x00, 0x03, 'f', | |
2053 'o', 'o', 0x00, 0x03, | |
2054 'f', 'o', 'o', 0x00, | |
2055 0x00 | |
2056 }; | |
2057 const unsigned char kV3FrameData[] = { | |
2058 0x80, kVer, 0x00, 0x08, | |
2059 0x01, 0x00, 0x00, 0x21, | |
2060 0x7f, 0xff, 0xff, 0xff, | |
2061 0x00, 0x00, 0x00, 0x02, | |
2062 0x00, 0x00, 0x00, 0x03, | |
2063 'b', 'a', 'r', 0x00, | |
2064 0x00, 0x00, 0x03, 'f', | |
2065 'o', 'o', 0x00, 0x00, | |
2066 0x00, 0x03, 'f', 'o', | |
2067 'o', 0x00, 0x00, 0x00, | |
2068 0x00 | |
2069 }; | |
2070 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( | |
2071 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); | |
2072 CompareFrame(kDescription, | |
2073 *frame, | |
2074 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
2075 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
2076 : arraysize(kV3FrameData)); | |
2077 } | |
2078 } | |
2079 | |
2080 TEST_F(SpdyFramerSpdy2Test, CreateHeadersCompressed) { | |
2081 SpdyFramer framer(kVer); | |
2082 framer.set_enable_compression(true); | |
2083 | |
2084 { | |
2085 const char kDescription[] = "HEADERS frame, no FIN"; | |
2086 | |
2087 SpdyHeaderBlock headers; | |
2088 headers["bar"] = "foo"; | |
2089 headers["foo"] = "bar"; | |
2090 | |
2091 const unsigned char kV2FrameData[] = { | |
2092 0x80, kVer, 0x00, 0x08, | |
2093 0x00, 0x00, 0x00, 0x21, | |
2094 0x00, 0x00, 0x00, 0x01, | |
2095 0x00, 0x00, 0x38, 0xea, | |
2096 0xdf, 0xa2, 0x51, 0xb2, | |
2097 0x62, 0x60, 0x62, 0x60, | |
2098 0x4e, 0x4a, 0x2c, 0x62, | |
2099 0x60, 0x4e, 0xcb, 0xcf, | |
2100 0x87, 0x12, 0x40, 0x2e, | |
2101 0x00, 0x00, 0x00, 0xff, | |
2102 0xff | |
2103 }; | |
2104 const unsigned char kV3FrameData[] = { | |
2105 0x80, kVer, 0x00, 0x08, | |
2106 0x00, 0x00, 0x00, 0x21, | |
2107 0x00, 0x00, 0x00, 0x01, | |
2108 0x38, 0xea, 0xe3, 0xc6, | |
2109 0xa7, 0xc2, 0x02, 0xe5, | |
2110 0x0e, 0x50, 0xc2, 0x4b, | |
2111 0x4a, 0x04, 0xe5, 0x0b, | |
2112 0xe6, 0xb4, 0xfc, 0x7c, | |
2113 0x24, 0x0a, 0x28, 0x08, | |
2114 0x00, 0x00, 0x00, 0xff, | |
2115 0xff | |
2116 }; | |
2117 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( | |
2118 1, CONTROL_FLAG_NONE, true, &headers)); | |
2119 CompareFrame(kDescription, | |
2120 *frame, | |
2121 (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, | |
2122 (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) | |
2123 : arraysize(kV3FrameData)); | |
2124 } | |
2125 } | |
2126 | |
2127 TEST_F(SpdyFramerSpdy2Test, CreateWindowUpdate) { | |
2128 SpdyFramer framer(kVer); | |
2129 | |
2130 { | |
2131 const char kDescription[] = "WINDOW_UPDATE frame"; | |
2132 const unsigned char kFrameData[] = { | |
2133 0x80, kVer, 0x00, 0x09, | |
2134 0x00, 0x00, 0x00, 0x08, | |
2135 0x00, 0x00, 0x00, 0x01, | |
2136 0x00, 0x00, 0x00, 0x01, | |
2137 }; | |
2138 scoped_ptr<SpdyWindowUpdateControlFrame> frame( | |
2139 framer.CreateWindowUpdate(1, 1)); | |
2140 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
2141 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); | |
2142 } | |
2143 | |
2144 { | |
2145 const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; | |
2146 const unsigned char kFrameData[] = { | |
2147 0x80, kVer, 0x00, 0x09, | |
2148 0x00, 0x00, 0x00, 0x08, | |
2149 0x7f, 0xff, 0xff, 0xff, | |
2150 0x00, 0x00, 0x00, 0x01, | |
2151 }; | |
2152 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1)); | |
2153 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
2154 } | |
2155 | |
2156 { | |
2157 const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; | |
2158 const unsigned char kFrameData[] = { | |
2159 0x80, kVer, 0x00, 0x09, | |
2160 0x00, 0x00, 0x00, 0x08, | |
2161 0x00, 0x00, 0x00, 0x01, | |
2162 0x7f, 0xff, 0xff, 0xff, | |
2163 }; | |
2164 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF)); | |
2165 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
2166 } | |
2167 } | |
2168 | |
2169 TEST_F(SpdyFramerSpdy2Test, DuplicateFrame) { | |
2170 SpdyFramer framer(kVer); | |
2171 | |
2172 { | |
2173 const char kDescription[] = "PING frame"; | |
2174 const unsigned char kFrameData[] = { | |
2175 0x80, kVer, 0x00, 0x06, | |
2176 0x00, 0x00, 0x00, 0x04, | |
2177 0x12, 0x34, 0x56, 0x78, | |
2178 }; | |
2179 scoped_ptr<SpdyFrame> frame1(framer.CreatePingFrame(0x12345678u)); | |
2180 CompareFrame(kDescription, *frame1, kFrameData, arraysize(kFrameData)); | |
2181 | |
2182 scoped_ptr<SpdyFrame> frame2(framer.DuplicateFrame(*frame1)); | |
2183 CompareFrame(kDescription, *frame2, kFrameData, arraysize(kFrameData)); | |
2184 } | |
2185 } | |
2186 | |
2187 // This test case reproduces conditions that caused ExpandControlFrameBuffer to | |
2188 // fail to expand the buffer control frame buffer when it should have, allowing | |
2189 // the framer to overrun the buffer, and smash other heap contents. This test | |
2190 // relies on the debug version of the heap manager, which checks for buffer | |
2191 // overrun errors during delete processing. Regression test for b/2974814. | |
2192 TEST_F(SpdyFramerSpdy2Test, ExpandBuffer_HeapSmash) { | |
2193 // Sweep through the area of problematic values, to make sure we always cover | |
2194 // the danger zone, even if it moves around at bit due to SPDY changes. | |
2195 for (uint16 val2_len = SpdyFramer::kControlFrameBufferInitialSize - 50; | |
2196 val2_len < SpdyFramer::kControlFrameBufferInitialSize; | |
2197 val2_len++) { | |
2198 std::string val2 = std::string(val2_len, 'a'); | |
2199 SpdyHeaderBlock headers; | |
2200 headers["bar"] = "foo"; | |
2201 headers["foo"] = "baz"; | |
2202 headers["grue"] = val2.c_str(); | |
2203 SpdyFramer framer(kVer); | |
2204 scoped_ptr<SpdySynStreamControlFrame> template_frame( | |
2205 framer.CreateSynStream(1, // stream_id | |
2206 0, // associated_stream_id | |
2207 1, // priority | |
2208 CONTROL_FLAG_NONE, | |
2209 false, // compress | |
2210 &headers)); | |
2211 EXPECT_TRUE(template_frame.get() != NULL); | |
2212 TestSpdyVisitor visitor; | |
2213 visitor.SimulateInFramer( | |
2214 reinterpret_cast<unsigned char*>(template_frame.get()->data()), | |
2215 template_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
2216 EXPECT_EQ(1, visitor.syn_frame_count_); | |
2217 } | |
2218 } | |
2219 | |
2220 TEST_F(SpdyFramerSpdy2Test, ControlFrameSizesAreValidated) { | |
2221 // Create a GoAway frame that has a few extra bytes at the end. | |
2222 // We create enough overhead to require the framer to expand its frame buffer. | |
2223 size_t overhead = SpdyFramer::kUncompressedControlFrameBufferInitialSize; | |
2224 SpdyFramer framer(kVer); | |
2225 scoped_ptr<SpdyGoAwayControlFrame> goaway(framer.CreateGoAway(1)); | |
2226 goaway->set_length(goaway->length() + overhead); | |
2227 std::string pad('A', overhead); | |
2228 TestSpdyVisitor visitor; | |
2229 | |
2230 // First attempt without validation on. | |
2231 visitor.framer_.set_validate_control_frame_sizes(false); | |
2232 visitor.SimulateInFramer( | |
2233 reinterpret_cast<unsigned char*>(goaway->data()), | |
2234 goaway->length() - overhead + SpdyControlFrame::kHeaderSize); | |
2235 visitor.SimulateInFramer( | |
2236 reinterpret_cast<const unsigned char*>(pad.c_str()), | |
2237 overhead); | |
2238 EXPECT_EQ(0, visitor.error_count_); // Not an error. | |
2239 EXPECT_EQ(1, visitor.goaway_count_); // The goaway was parsed. | |
2240 | |
2241 // Attempt with validation on. | |
2242 visitor.framer_.set_validate_control_frame_sizes(true); | |
2243 visitor.SimulateInFramer( | |
2244 reinterpret_cast<unsigned char*>(goaway->data()), | |
2245 goaway->length() - overhead + SpdyControlFrame::kHeaderSize); | |
2246 visitor.SimulateInFramer( | |
2247 reinterpret_cast<const unsigned char*>(pad.c_str()), | |
2248 overhead); | |
2249 EXPECT_EQ(1, visitor.error_count_); // This generated an error. | |
2250 EXPECT_EQ(1, visitor.goaway_count_); // Unchanged from before. | |
2251 } | |
2252 | |
2253 TEST_F(SpdyFramerSpdy2Test, ReadZeroLenSettingsFrame) { | |
2254 SpdyFramer framer(kVer); | |
2255 SpdySettings settings; | |
2256 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); | |
2257 control_frame->set_length(0); | |
2258 TestSpdyVisitor visitor; | |
2259 visitor.use_compression_ = false; | |
2260 visitor.SimulateInFramer( | |
2261 reinterpret_cast<unsigned char*>(control_frame->data()), | |
2262 control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
2263 // Should generate an error, since zero-len settings frames are unsupported. | |
2264 EXPECT_EQ(1, visitor.error_count_); | |
2265 } | |
2266 | |
2267 // Tests handling of SETTINGS frames with invalid length. | |
2268 TEST_F(SpdyFramerSpdy2Test, ReadBogusLenSettingsFrame) { | |
2269 SpdyFramer framer(kVer); | |
2270 SpdySettings settings; | |
2271 // Add a setting to pad the frame so that we don't get a buffer overflow when | |
2272 // calling SimulateInFramer() below. | |
2273 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); | |
2274 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); | |
2275 control_frame->set_length(5); | |
2276 TestSpdyVisitor visitor; | |
2277 visitor.use_compression_ = false; | |
2278 visitor.SimulateInFramer( | |
2279 reinterpret_cast<unsigned char*>(control_frame->data()), | |
2280 control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
2281 // Should generate an error, since zero-len settings frames are unsupported. | |
2282 EXPECT_EQ(1, visitor.error_count_); | |
2283 } | |
2284 | |
2285 // Tests handling of SETTINGS frames larger than the frame buffer size. | |
2286 TEST_F(SpdyFramerSpdy2Test, ReadLargeSettingsFrame) { | |
2287 SpdyFramer framer(kVer); | |
2288 SpdySettings settings; | |
2289 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); | |
2290 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 2), 0x00000003)); | |
2291 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000004)); | |
2292 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); | |
2293 EXPECT_LT(SpdyFramer::kUncompressedControlFrameBufferInitialSize, | |
2294 control_frame->length() + SpdyControlFrame::kHeaderSize); | |
2295 TestSpdyVisitor visitor; | |
2296 visitor.use_compression_ = false; | |
2297 | |
2298 // Read all at once. | |
2299 visitor.SimulateInFramer( | |
2300 reinterpret_cast<unsigned char*>(control_frame->data()), | |
2301 control_frame->length() + SpdyControlFrame::kHeaderSize); | |
2302 EXPECT_EQ(0, visitor.error_count_); | |
2303 EXPECT_EQ(settings.size(), static_cast<unsigned>(visitor.setting_count_)); | |
2304 EXPECT_EQ(1, visitor.settings_frame_count_); | |
2305 | |
2306 // Read data in small chunks. | |
2307 size_t framed_data = 0; | |
2308 size_t unframed_data = control_frame->length() + | |
2309 SpdyControlFrame::kHeaderSize; | |
2310 size_t kReadChunkSize = 5; // Read five bytes at a time. | |
2311 while (unframed_data > 0) { | |
2312 size_t to_read = std::min(kReadChunkSize, unframed_data); | |
2313 visitor.SimulateInFramer( | |
2314 reinterpret_cast<unsigned char*>(control_frame->data() + framed_data), | |
2315 to_read); | |
2316 unframed_data -= to_read; | |
2317 framed_data += to_read; | |
2318 } | |
2319 EXPECT_EQ(0, visitor.error_count_); | |
2320 EXPECT_EQ(settings.size() * 2, static_cast<unsigned>(visitor.setting_count_)); | |
2321 EXPECT_EQ(2, visitor.settings_frame_count_); | |
2322 } | |
2323 | |
2324 // Tests handling of SETTINGS frame with duplicate entries. | |
2325 TEST_F(SpdyFramerSpdy2Test, ReadDuplicateSettings) { | |
2326 SpdyFramer framer(kVer); | |
2327 SpdySettings settings; | |
2328 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); | |
2329 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000003)); | |
2330 // This last setting should not be processed due to error above. | |
2331 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000003)); | |
2332 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); | |
2333 TestSpdyVisitor visitor; | |
2334 visitor.use_compression_ = false; | |
2335 | |
2336 visitor.SimulateInFramer( | |
2337 reinterpret_cast<unsigned char*>(control_frame->data()), | |
2338 control_frame->length() + SpdyControlFrame::kHeaderSize); | |
2339 EXPECT_EQ(1, visitor.error_count_); | |
2340 EXPECT_EQ(1, visitor.setting_count_); | |
2341 EXPECT_EQ(1, visitor.settings_frame_count_); | |
2342 } | |
2343 | |
2344 // Tests handling of SETTINGS frame with entries out of order. | |
2345 TEST_F(SpdyFramerSpdy2Test, ReadOutOfOrderSettings) { | |
2346 SpdyFramer framer(kVer); | |
2347 SpdySettings settings; | |
2348 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 2), 0x00000002)); | |
2349 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000003)); | |
2350 // This last setting should not be processed due to error above. | |
2351 settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000003)); | |
2352 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); | |
2353 TestSpdyVisitor visitor; | |
2354 visitor.use_compression_ = false; | |
2355 | |
2356 visitor.SimulateInFramer( | |
2357 reinterpret_cast<unsigned char*>(control_frame->data()), | |
2358 control_frame->length() + SpdyControlFrame::kHeaderSize); | |
2359 EXPECT_EQ(1, visitor.error_count_); | |
2360 EXPECT_EQ(1, visitor.setting_count_); | |
2361 EXPECT_EQ(1, visitor.settings_frame_count_); | |
2362 } | |
2363 | |
2364 TEST_F(SpdyFramerSpdy2Test, ReadCredentialFrame) { | |
2365 SpdyCredential credential; | |
2366 credential.slot = 3; | |
2367 credential.proof = "proof"; | |
2368 credential.certs.push_back("a cert"); | |
2369 credential.certs.push_back("another cert"); | |
2370 credential.certs.push_back("final cert"); | |
2371 SpdyFramer framer(kVer); | |
2372 scoped_ptr<SpdyFrame> control_frame( | |
2373 framer.CreateCredentialFrame(credential)); | |
2374 EXPECT_TRUE(control_frame.get() != NULL); | |
2375 TestSpdyVisitor visitor; | |
2376 visitor.use_compression_ = false; | |
2377 visitor.SimulateInFramer( | |
2378 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
2379 control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
2380 EXPECT_EQ(0, visitor.error_count_); | |
2381 EXPECT_EQ(1, visitor.credential_count_); | |
2382 EXPECT_EQ(control_frame->length(), visitor.credential_buffer_length_); | |
2383 EXPECT_EQ(credential.slot, visitor.credential_.slot); | |
2384 EXPECT_EQ(credential.proof, visitor.credential_.proof); | |
2385 EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size()); | |
2386 for (size_t i = 0; i < credential.certs.size(); i++) { | |
2387 EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]); | |
2388 } | |
2389 } | |
2390 | |
2391 TEST_F(SpdyFramerSpdy2Test, ReadCredentialFrameWithCorruptProof) { | |
2392 SpdyCredential credential; | |
2393 credential.slot = 3; | |
2394 credential.proof = "proof"; | |
2395 credential.certs.push_back("a cert"); | |
2396 credential.certs.push_back("another cert"); | |
2397 credential.certs.push_back("final cert"); | |
2398 SpdyFramer framer(kVer); | |
2399 scoped_ptr<SpdyFrame> control_frame( | |
2400 framer.CreateCredentialFrame(credential)); | |
2401 EXPECT_TRUE(control_frame.get() != NULL); | |
2402 TestSpdyVisitor visitor; | |
2403 visitor.use_compression_ = false; | |
2404 unsigned char* data = | |
2405 reinterpret_cast<unsigned char*>(control_frame.get()->data()); | |
2406 size_t offset = SpdyControlFrame::kHeaderSize + 4; | |
2407 data[offset] = 0xFF; // Proof length is past the end of the frame | |
2408 visitor.SimulateInFramer( | |
2409 data, control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
2410 EXPECT_EQ(1, visitor.error_count_); | |
2411 } | |
2412 | |
2413 TEST_F(SpdyFramerSpdy2Test, ReadCredentialFrameWithCorruptCertificate) { | |
2414 SpdyCredential credential; | |
2415 credential.slot = 3; | |
2416 credential.proof = "proof"; | |
2417 credential.certs.push_back("a cert"); | |
2418 credential.certs.push_back("another cert"); | |
2419 credential.certs.push_back("final cert"); | |
2420 SpdyFramer framer(kVer); | |
2421 scoped_ptr<SpdyFrame> control_frame( | |
2422 framer.CreateCredentialFrame(credential)); | |
2423 EXPECT_TRUE(control_frame.get() != NULL); | |
2424 TestSpdyVisitor visitor; | |
2425 visitor.use_compression_ = false; | |
2426 unsigned char* data = | |
2427 reinterpret_cast<unsigned char*>(control_frame.get()->data()); | |
2428 size_t offset = SpdyControlFrame::kHeaderSize + credential.proof.length(); | |
2429 data[offset] = 0xFF; // Certificate length is past the end of the frame | |
2430 visitor.SimulateInFramer( | |
2431 data, control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
2432 EXPECT_EQ(1, visitor.error_count_); | |
2433 } | |
2434 | |
2435 TEST_F(SpdyFramerSpdy2Test, ReadGarbage) { | |
2436 SpdyFramer framer(kVer); | |
2437 unsigned char garbage_frame[256]; | |
2438 memset(garbage_frame, ~0, sizeof(garbage_frame)); | |
2439 TestSpdyVisitor visitor; | |
2440 visitor.use_compression_ = false; | |
2441 visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame)); | |
2442 EXPECT_EQ(1, visitor.error_count_); | |
2443 } | |
2444 | |
2445 TEST_F(SpdyFramerSpdy2Test, ReadGarbageWithValidVersion) { | |
2446 SpdyFramer framer(kVer); | |
2447 char garbage_frame[256]; | |
2448 memset(garbage_frame, ~0, sizeof(garbage_frame)); | |
2449 SpdyControlFrame control_frame(&garbage_frame[0], false); | |
2450 control_frame.set_version(SPDY_VERSION_FOR_TESTS); | |
2451 TestSpdyVisitor visitor; | |
2452 visitor.use_compression_ = false; | |
2453 visitor.SimulateInFramer( | |
2454 reinterpret_cast<unsigned char*>(control_frame.data()), | |
2455 sizeof(garbage_frame)); | |
2456 EXPECT_EQ(1, visitor.error_count_); | |
2457 } | |
2458 | |
2459 TEST_F(SpdyFramerSpdy2Test, StateToStringTest) { | |
2460 EXPECT_STREQ("ERROR", | |
2461 SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR)); | |
2462 EXPECT_STREQ("DONE", | |
2463 SpdyFramer::StateToString(SpdyFramer::SPDY_DONE)); | |
2464 EXPECT_STREQ("AUTO_RESET", | |
2465 SpdyFramer::StateToString(SpdyFramer::SPDY_AUTO_RESET)); | |
2466 EXPECT_STREQ("RESET", | |
2467 SpdyFramer::StateToString(SpdyFramer::SPDY_RESET)); | |
2468 EXPECT_STREQ("READING_COMMON_HEADER", | |
2469 SpdyFramer::StateToString( | |
2470 SpdyFramer::SPDY_READING_COMMON_HEADER)); | |
2471 EXPECT_STREQ("CONTROL_FRAME_PAYLOAD", | |
2472 SpdyFramer::StateToString( | |
2473 SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD)); | |
2474 EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD", | |
2475 SpdyFramer::StateToString( | |
2476 SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD)); | |
2477 EXPECT_STREQ("FORWARD_STREAM_FRAME", | |
2478 SpdyFramer::StateToString( | |
2479 SpdyFramer::SPDY_FORWARD_STREAM_FRAME)); | |
2480 EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK", | |
2481 SpdyFramer::StateToString( | |
2482 SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK)); | |
2483 EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK", | |
2484 SpdyFramer::StateToString( | |
2485 SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK)); | |
2486 EXPECT_STREQ("SPDY_CREDENTIAL_FRAME_PAYLOAD", | |
2487 SpdyFramer::StateToString( | |
2488 SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD)); | |
2489 EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD", | |
2490 SpdyFramer::StateToString( | |
2491 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD)); | |
2492 EXPECT_STREQ("UNKNOWN_STATE", | |
2493 SpdyFramer::StateToString( | |
2494 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD + 1)); | |
2495 } | |
2496 | |
2497 TEST_F(SpdyFramerSpdy2Test, ErrorCodeToStringTest) { | |
2498 EXPECT_STREQ("NO_ERROR", | |
2499 SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR)); | |
2500 EXPECT_STREQ("INVALID_CONTROL_FRAME", | |
2501 SpdyFramer::ErrorCodeToString( | |
2502 SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); | |
2503 EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE", | |
2504 SpdyFramer::ErrorCodeToString( | |
2505 SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); | |
2506 EXPECT_STREQ("ZLIB_INIT_FAILURE", | |
2507 SpdyFramer::ErrorCodeToString( | |
2508 SpdyFramer::SPDY_ZLIB_INIT_FAILURE)); | |
2509 EXPECT_STREQ("UNSUPPORTED_VERSION", | |
2510 SpdyFramer::ErrorCodeToString( | |
2511 SpdyFramer::SPDY_UNSUPPORTED_VERSION)); | |
2512 EXPECT_STREQ("DECOMPRESS_FAILURE", | |
2513 SpdyFramer::ErrorCodeToString( | |
2514 SpdyFramer::SPDY_DECOMPRESS_FAILURE)); | |
2515 EXPECT_STREQ("COMPRESS_FAILURE", | |
2516 SpdyFramer::ErrorCodeToString( | |
2517 SpdyFramer::SPDY_COMPRESS_FAILURE)); | |
2518 EXPECT_STREQ("UNKNOWN_ERROR", | |
2519 SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR)); | |
2520 } | |
2521 | |
2522 TEST_F(SpdyFramerSpdy2Test, StatusCodeToStringTest) { | |
2523 EXPECT_STREQ("INVALID", | |
2524 SpdyFramer::StatusCodeToString(INVALID)); | |
2525 EXPECT_STREQ("PROTOCOL_ERROR", | |
2526 SpdyFramer::StatusCodeToString(PROTOCOL_ERROR)); | |
2527 EXPECT_STREQ("INVALID_STREAM", | |
2528 SpdyFramer::StatusCodeToString(INVALID_STREAM)); | |
2529 EXPECT_STREQ("REFUSED_STREAM", | |
2530 SpdyFramer::StatusCodeToString(REFUSED_STREAM)); | |
2531 EXPECT_STREQ("UNSUPPORTED_VERSION", | |
2532 SpdyFramer::StatusCodeToString(UNSUPPORTED_VERSION)); | |
2533 EXPECT_STREQ("CANCEL", | |
2534 SpdyFramer::StatusCodeToString(CANCEL)); | |
2535 EXPECT_STREQ("INTERNAL_ERROR", | |
2536 SpdyFramer::StatusCodeToString(INTERNAL_ERROR)); | |
2537 EXPECT_STREQ("FLOW_CONTROL_ERROR", | |
2538 SpdyFramer::StatusCodeToString(FLOW_CONTROL_ERROR)); | |
2539 EXPECT_STREQ("UNKNOWN_STATUS", | |
2540 SpdyFramer::StatusCodeToString(NUM_STATUS_CODES)); | |
2541 } | |
2542 | |
2543 TEST_F(SpdyFramerSpdy2Test, ControlTypeToStringTest) { | |
2544 EXPECT_STREQ("SYN_STREAM", | |
2545 SpdyFramer::ControlTypeToString(SYN_STREAM)); | |
2546 EXPECT_STREQ("SYN_REPLY", | |
2547 SpdyFramer::ControlTypeToString(SYN_REPLY)); | |
2548 EXPECT_STREQ("RST_STREAM", | |
2549 SpdyFramer::ControlTypeToString(RST_STREAM)); | |
2550 EXPECT_STREQ("SETTINGS", | |
2551 SpdyFramer::ControlTypeToString(SETTINGS)); | |
2552 EXPECT_STREQ("NOOP", | |
2553 SpdyFramer::ControlTypeToString(NOOP)); | |
2554 EXPECT_STREQ("PING", | |
2555 SpdyFramer::ControlTypeToString(PING)); | |
2556 EXPECT_STREQ("GOAWAY", | |
2557 SpdyFramer::ControlTypeToString(GOAWAY)); | |
2558 EXPECT_STREQ("HEADERS", | |
2559 SpdyFramer::ControlTypeToString(HEADERS)); | |
2560 EXPECT_STREQ("WINDOW_UPDATE", | |
2561 SpdyFramer::ControlTypeToString(WINDOW_UPDATE)); | |
2562 EXPECT_STREQ("CREDENTIAL", | |
2563 SpdyFramer::ControlTypeToString(CREDENTIAL)); | |
2564 EXPECT_STREQ("UNKNOWN_CONTROL_TYPE", | |
2565 SpdyFramer::ControlTypeToString(NUM_CONTROL_FRAME_TYPES)); | |
2566 } | |
2567 | |
2568 TEST_F(SpdyFramerSpdy2Test, GetMinimumControlFrameSizeTest) { | |
2569 EXPECT_EQ(SpdySynStreamControlFrame::size(), | |
2570 SpdyFramer::GetMinimumControlFrameSize(SYN_STREAM)); | |
2571 EXPECT_EQ(SpdySynReplyControlFrame::size(), | |
2572 SpdyFramer::GetMinimumControlFrameSize(SYN_REPLY)); | |
2573 EXPECT_EQ(SpdyRstStreamControlFrame::size(), | |
2574 SpdyFramer::GetMinimumControlFrameSize(RST_STREAM)); | |
2575 EXPECT_EQ(SpdySettingsControlFrame::size(), | |
2576 SpdyFramer::GetMinimumControlFrameSize(SETTINGS)); | |
2577 EXPECT_EQ(SpdyFrame::kHeaderSize, | |
2578 SpdyFramer::GetMinimumControlFrameSize(NOOP)); | |
2579 EXPECT_EQ(SpdyPingControlFrame::size(), | |
2580 SpdyFramer::GetMinimumControlFrameSize(PING)); | |
2581 EXPECT_EQ(SpdyGoAwayControlFrame::size(), | |
2582 SpdyFramer::GetMinimumControlFrameSize(GOAWAY)); | |
2583 EXPECT_EQ(SpdyHeadersControlFrame::size(), | |
2584 SpdyFramer::GetMinimumControlFrameSize(HEADERS)); | |
2585 EXPECT_EQ(SpdyWindowUpdateControlFrame::size(), | |
2586 SpdyFramer::GetMinimumControlFrameSize(WINDOW_UPDATE)); | |
2587 EXPECT_EQ(SpdyCredentialControlFrame::size(), | |
2588 SpdyFramer::GetMinimumControlFrameSize(CREDENTIAL)); | |
2589 EXPECT_EQ(static_cast<size_t>(0x7FFFFFFF), | |
2590 SpdyFramer::GetMinimumControlFrameSize(NUM_CONTROL_FRAME_TYPES)); | |
2591 } | |
2592 | |
2593 TEST_F(SpdyFramerSpdy2Test, CatchProbableHttpResponse) { | |
2594 SpdyFramerTestUtil::DecompressionVisitor visitor; | |
2595 visitor.set_allow_data_frames(true); | |
2596 { | |
2597 SpdyFramer framer(kVer); | |
2598 framer.set_visitor(&visitor); | |
2599 framer.ProcessInput("HTTP/1.1", 8); | |
2600 EXPECT_TRUE(framer.probable_http_response()); | |
2601 } | |
2602 { | |
2603 SpdyFramer framer(kVer); | |
2604 framer.set_visitor(&visitor); | |
2605 framer.ProcessInput("HTTP/1.0", 8); | |
2606 EXPECT_TRUE(framer.probable_http_response()); | |
2607 } | |
2608 } | |
2609 | |
2610 TEST_F(SpdyFramerSpdy2Test, SettingsFlagsAndId) { | |
2611 const uint32 kId = 0x020304; | |
2612 const uint32 kFlags = 0x01; | |
2613 const uint32 kWireFormat = | |
2614 htonl((SPDY_VERSION_FOR_TESTS < 3) ? 0x04030201 : 0x01020304); | |
2615 | |
2616 SettingsFlagsAndId id_and_flags = | |
2617 SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, kWireFormat); | |
2618 EXPECT_EQ(kId, id_and_flags.id()); | |
2619 EXPECT_EQ(kFlags, id_and_flags.flags()); | |
2620 EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(SPDY_VERSION_FOR_TESTS)); | |
2621 } | |
2622 | |
2623 } // namespace | |
OLD | NEW |