1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <algorithm> 6 #include <iostream> 7 #include <limits> 8 9 #include "base/compiler_specific.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "net/spdy/spdy_frame_builder.h" 12 #include "net/spdy/spdy_framer.h" 13 #include "net/spdy/spdy_protocol.h" 14 #include "net/spdy/spdy_test_utils.h" 15 #include "testing/gmock/include/gmock/gmock.h" 16 #include "testing/platform_test.h" 17 18 using std::string; 19 using std::max; 20 using std::min; 21 using std::numeric_limits; 22 using testing::_; 23 24 namespace net { 25 26 namespace test { 27 28 static const size_t kMaxDecompressedSize = 1024; 29 30 // TODO(akalin): Make sure expectations on mocks are set before mock 31 // functions are called, as interleaving expectations and calls is 32 // undefined. 33 class MockVisitor : public SpdyFramerVisitorInterface { 34 public: 35 MOCK_METHOD1(OnError, void(SpdyFramer* framer)); 36 MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id, 37 size_t length, 38 bool fin)); 39 MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id, 40 const char* data, 41 size_t len, 42 bool fin)); 43 MOCK_METHOD3(OnControlFrameHeaderData, bool(SpdyStreamId stream_id, 44 const char* header_data, 45 size_t len)); 46 MOCK_METHOD6(OnSynStream, void(SpdyStreamId stream_id, 47 SpdyStreamId associated_stream_id, 48 SpdyPriority priority, 49 uint8 slot, 50 bool fin, 51 bool unidirectional)); 52 MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin)); 53 MOCK_METHOD2(OnRstStream, void(SpdyStreamId stream_id, 54 SpdyRstStreamStatus status)); 55 MOCK_METHOD1(OnSettings, void(bool clear_persisted)); 56 MOCK_METHOD3(OnSetting, void(SpdySettingsIds id, uint8 flags, uint32 value)); 57 MOCK_METHOD1(OnPing, void(uint32 unique_id)); 58 MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id, 59 SpdyGoAwayStatus status)); 60 MOCK_METHOD2(OnHeaders, void(SpdyStreamId stream_id, bool fin)); 61 MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id, 62 uint32 delta_window_size)); 63 MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data, 64 size_t len)); 65 MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id)); 66 MOCK_METHOD2(OnPushPromise, void(SpdyStreamId stream_id, 67 SpdyStreamId promised_stream_id)); 68 }; 69 70 class MockDebugVisitor : public SpdyFramerDebugVisitorInterface { 71 public: 72 MOCK_METHOD4(OnSendCompressedFrame, void(SpdyStreamId stream_id, 73 SpdyFrameType type, 74 size_t payload_len, 75 size_t frame_len)); 76 77 MOCK_METHOD3(OnReceiveCompressedFrame, void(SpdyStreamId stream_id, 78 SpdyFrameType type, 79 size_t frame_len)); 80 }; 81 82 class SpdyFramerTestUtil { 83 public: 84 // Decompress a single frame using the decompression context held by 85 // the SpdyFramer. The implemention is meant for use only in tests 86 // and will CHECK fail if the input is anything other than a single, 87 // well-formed compressed frame. 88 // 89 // Returns a new decompressed SpdyFrame. 90 template<class SpdyFrameType> static SpdyFrame* DecompressFrame( 91 SpdyFramer* framer, const SpdyFrameType& frame) { 92 DecompressionVisitor visitor(framer->protocol_version()); 93 framer->set_visitor(&visitor); 94 CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size())); 95 CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state()); 96 framer->set_visitor(NULL); 97 98 char* buffer = visitor.ReleaseBuffer(); 99 CHECK(buffer != NULL); 100 SpdyFrame* decompressed_frame = new SpdyFrame(buffer, visitor.size(), true); 101 if (framer->protocol_version() == 4) { 102 SetFrameLength(decompressed_frame, 103 visitor.size(), 104 framer->protocol_version()); 105 } else { 106 SetFrameLength(decompressed_frame, 107 visitor.size() - framer->GetControlFrameHeaderSize(), 108 framer->protocol_version()); 109 } 110 return decompressed_frame; 111 } 112 113 class DecompressionVisitor : public SpdyFramerVisitorInterface { 114 public: 115 explicit DecompressionVisitor(SpdyMajorVersion version) 116 : version_(version), size_(0), finished_(false) {} 117 118 void ResetBuffer() { 119 CHECK(buffer_.get() == NULL); 120 CHECK_EQ(0u, size_); 121 CHECK(!finished_); 122 buffer_.reset(new char[kMaxDecompressedSize]); 123 } 124 125 virtual void OnError(SpdyFramer* framer) OVERRIDE { LOG(FATAL); } 126 virtual void OnDataFrameHeader(SpdyStreamId stream_id, 127 size_t length, 128 bool fin) OVERRIDE { 129 LOG(FATAL) << "Unexpected data frame header"; 130 } 131 virtual void OnStreamFrameData(SpdyStreamId stream_id, 132 const char* data, 133 size_t len, 134 bool fin) OVERRIDE { 135 LOG(FATAL); 136 } 137 138 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, 139 const char* header_data, 140 size_t len) OVERRIDE { 141 CHECK(buffer_.get() != NULL); 142 CHECK_GE(kMaxDecompressedSize, size_ + len); 143 CHECK(!finished_); 144 if (len != 0) { 145 memcpy(buffer_.get() + size_, header_data, len); 146 size_ += len; 147 } else { 148 // Done. 149 finished_ = true; 150 } 151 return true; 152 } 153 154 virtual void OnSynStream(SpdyStreamId stream_id, 155 SpdyStreamId associated_stream_id, 156 SpdyPriority priority, 157 uint8 slot, 158 bool fin, 159 bool unidirectional) OVERRIDE { 160 SpdyFramer framer(version_); 161 framer.set_enable_compression(false); 162 const SpdyHeaderBlock null_headers; 163 int flags = CONTROL_FLAG_NONE; 164 if (fin) { 165 flags &= CONTROL_FLAG_FIN; 166 } 167 if (unidirectional) { 168 flags &= CONTROL_FLAG_UNIDIRECTIONAL; 169 } 170 scoped_ptr<SpdyFrame> frame( 171 framer.CreateSynStream(stream_id, 172 associated_stream_id, 173 priority, 174 slot, 175 static_cast<SpdyControlFlags>(flags), 176 false, 177 &null_headers)); 178 ResetBuffer(); 179 memcpy(buffer_.get(), frame->data(), framer.GetSynStreamMinimumSize()); 180 size_ += framer.GetSynStreamMinimumSize(); 181 } 182 183 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE { 184 SpdyFramer framer(version_); 185 framer.set_enable_compression(false); 186 const SpdyHeaderBlock null_headers; 187 int flags = CONTROL_FLAG_NONE; 188 if (fin) { 189 flags &= CONTROL_FLAG_FIN; 190 } 191 scoped_ptr<SpdyFrame> frame( 192 framer.CreateHeaders(stream_id, 193 static_cast<SpdyControlFlags>(flags), 194 false, 195 &null_headers)); 196 ResetBuffer(); 197 memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize()); 198 size_ += framer.GetSynStreamMinimumSize(); 199 } 200 201 virtual void OnRstStream(SpdyStreamId stream_id, 202 SpdyRstStreamStatus status) OVERRIDE { 203 LOG(FATAL); 204 } 205 virtual void OnSetting(SpdySettingsIds id, 206 uint8 flags, 207 uint32 value) OVERRIDE { 208 LOG(FATAL); 209 } 210 virtual void OnPing(uint32 unique_id) OVERRIDE { 211 LOG(FATAL); 212 } 213 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, 214 SpdyGoAwayStatus status) OVERRIDE { 215 LOG(FATAL); 216 } 217 218 virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE { 219 SpdyFramer framer(version_); 220 framer.set_enable_compression(false); 221 const SpdyHeaderBlock null_headers; 222 int flags = CONTROL_FLAG_NONE; 223 if (fin) { 224 flags &= CONTROL_FLAG_FIN; 225 } 226 scoped_ptr<SpdyFrame> frame( 227 framer.CreateHeaders(stream_id, 228 static_cast<SpdyControlFlags>(flags), 229 false, 230 &null_headers)); 231 ResetBuffer(); 232 memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize()); 233 size_ += framer.GetHeadersMinimumSize(); 234 } 235 236 virtual void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) { 237 LOG(FATAL); 238 } 239 virtual bool OnCredentialFrameData(const char* /*credential_data*/, 240 size_t /*len*/) OVERRIDE { 241 LOG(FATAL) << "Unexpected CREDENTIAL Frame"; 242 return false; 243 } 244 245 virtual void OnPushPromise(SpdyStreamId stream_id, 246 SpdyStreamId promised_stream_id) OVERRIDE { 247 SpdyFramer framer(version_); 248 framer.set_enable_compression(false); 249 const SpdyHeaderBlock null_headers; 250 scoped_ptr<SpdyFrame> frame( 251 framer.CreatePushPromise(stream_id, promised_stream_id, 252 &null_headers)); 253 ResetBuffer(); 254 memcpy(buffer_.get(), frame->data(), framer.GetPushPromiseMinimumSize()); 255 size_ += framer.GetPushPromiseMinimumSize(); 256 } 257 258 char* ReleaseBuffer() { 259 CHECK(finished_); 260 return buffer_.release(); 261 } 262 263 virtual void OnWindowUpdate(SpdyStreamId stream_id, 264 uint32 delta_window_size) OVERRIDE { 265 LOG(FATAL); 266 } 267 268 size_t size() const { 269 CHECK(finished_); 270 return size_; 271 } 272 273 private: 274 SpdyMajorVersion version_; 275 scoped_ptr<char[]> buffer_; 276 size_t size_; 277 bool finished_; 278 279 DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor); 280 }; 281 282 private: 283 DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil); 284 }; 285 286 class TestSpdyVisitor : public SpdyFramerVisitorInterface, 287 public SpdyFramerDebugVisitorInterface { 288 public: 289 static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024; 290 static const size_t kDefaultCredentialBufferSize = 16 * 1024; 291 292 explicit TestSpdyVisitor(SpdyMajorVersion version) 293 : framer_(version), 294 use_compression_(false), 295 error_count_(0), 296 syn_frame_count_(0), 297 syn_reply_frame_count_(0), 298 headers_frame_count_(0), 299 goaway_count_(0), 300 setting_count_(0), 301 last_window_update_stream_(0), 302 last_window_update_delta_(0), 303 last_push_promise_stream_(0), 304 last_push_promise_promised_stream_(0), 305 data_bytes_(0), 306 fin_frame_count_(0), 307 fin_flag_count_(0), 308 zero_length_data_frame_count_(0), 309 control_frame_header_data_count_(0), 310 zero_length_control_frame_header_data_count_(0), 311 data_frame_count_(0), 312 last_payload_len_(0), 313 last_frame_len_(0), 314 header_buffer_(new char[kDefaultHeaderBufferSize]), 315 header_buffer_length_(0), 316 header_buffer_size_(kDefaultHeaderBufferSize), 317 header_stream_id_(-1), 318 header_control_type_(DATA), 319 header_buffer_valid_(false), 320 credential_buffer_(new char[kDefaultCredentialBufferSize]), 321 credential_buffer_length_(0), 322 credential_buffer_size_(kDefaultCredentialBufferSize) { 323 } 324 325 virtual void OnError(SpdyFramer* f) OVERRIDE { 326 LOG(INFO) << "SpdyFramer Error: " 327 << SpdyFramer::ErrorCodeToString(f->error_code()); 328 error_count_++; 329 } 330 331 virtual void OnDataFrameHeader(SpdyStreamId stream_id, 332 size_t length, 333 bool fin) OVERRIDE { 334 data_frame_count_++; 335 header_stream_id_ = stream_id; 336 } 337 338 virtual void OnStreamFrameData(SpdyStreamId stream_id, 339 const char* data, 340 size_t len, 341 bool fin) OVERRIDE { 342 EXPECT_EQ(header_stream_id_, stream_id); 343 if (len == 0) 344 ++zero_length_data_frame_count_; 345 346 data_bytes_ += len; 347 std::cerr << "OnStreamFrameData(" << stream_id << ", \""; 348 if (len > 0) { 349 for (size_t i = 0 ; i < len; ++i) { 350 std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec; 351 } 352 } 353 std::cerr << "\", " << len << ")\n"; 354 } 355 356 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, 357 const char* header_data, 358 size_t len) OVERRIDE { 359 ++control_frame_header_data_count_; 360 CHECK_EQ(header_stream_id_, stream_id); 361 if (len == 0) { 362 ++zero_length_control_frame_header_data_count_; 363 // Indicates end-of-header-block. 364 CHECK(header_buffer_valid_); 365 size_t parsed_length = framer_.ParseHeaderBlockInBuffer( 366 header_buffer_.get(), header_buffer_length_, &headers_); 367 DCHECK_EQ(header_buffer_length_, parsed_length); 368 return true; 369 } 370 const size_t available = header_buffer_size_ - header_buffer_length_; 371 if (len > available) { 372 header_buffer_valid_ = false; 373 return false; 374 } 375 memcpy(header_buffer_.get() + header_buffer_length_, header_data, len); 376 header_buffer_length_ += len; 377 return true; 378 } 379 380 virtual void OnSynStream(SpdyStreamId stream_id, 381 SpdyStreamId associated_stream_id, 382 SpdyPriority priority, 383 uint8 credential_slot, 384 bool fin, 385 bool unidirectional) OVERRIDE { 386 syn_frame_count_++; 387 InitHeaderStreaming(SYN_STREAM, stream_id); 388 if (fin) { 389 fin_flag_count_++; 390 } 391 } 392 393 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE { 394 syn_reply_frame_count_++; 395 InitHeaderStreaming(SYN_REPLY, stream_id); 396 if (fin) { 397 fin_flag_count_++; 398 } 399 } 400 401 virtual void OnRstStream(SpdyStreamId stream_id, 402 SpdyRstStreamStatus status) OVERRIDE { 403 fin_frame_count_++; 404 } 405 406 virtual void OnSetting(SpdySettingsIds id, 407 uint8 flags, 408 uint32 value) OVERRIDE { 409 setting_count_++; 410 } 411 412 virtual void OnPing(uint32 unique_id) OVERRIDE { 413 DLOG(FATAL); 414 } 415 416 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, 417 SpdyGoAwayStatus status) OVERRIDE { 418 goaway_count_++; 419 } 420 421 virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE { 422 headers_frame_count_++; 423 InitHeaderStreaming(HEADERS, stream_id); 424 if (fin) { 425 fin_flag_count_++; 426 } 427 } 428 429 virtual void OnWindowUpdate(SpdyStreamId stream_id, 430 uint32 delta_window_size) OVERRIDE { 431 last_window_update_stream_ = stream_id; 432 last_window_update_delta_ = delta_window_size; 433 } 434 435 virtual bool OnCredentialFrameData(const char* credential_data, 436 size_t len) OVERRIDE { 437 if (len == 0) { 438 if (!framer_.ParseCredentialData(credential_buffer_.get(), 439 credential_buffer_length_, 440 &credential_)) { 441 LOG(INFO) << "Error parsing credential data."; 442 ++error_count_; 443 } 444 return true; 445 } 446 const size_t available = 447 credential_buffer_size_ - credential_buffer_length_; 448 if (len > available) { 449 return false; 450 } 451 memcpy(credential_buffer_.get() + credential_buffer_length_, 452 credential_data, len); 453 credential_buffer_length_ += len; 454 return true; 455 } 456 457 virtual void OnPushPromise(SpdyStreamId stream_id, 458 SpdyStreamId promised_stream_id) OVERRIDE { 459 InitHeaderStreaming(PUSH_PROMISE, stream_id); 460 last_push_promise_stream_ = stream_id; 461 last_push_promise_promised_stream_ = promised_stream_id; 462 } 463 464 virtual void OnSendCompressedFrame(SpdyStreamId stream_id, 465 SpdyFrameType type, 466 size_t payload_len, 467 size_t frame_len) OVERRIDE { 468 last_payload_len_ = payload_len; 469 last_frame_len_ = frame_len; 470 } 471 472 virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id, 473 SpdyFrameType type, 474 size_t frame_len) OVERRIDE { 475 last_frame_len_ = frame_len; 476 } 477 478 // Convenience function which runs a framer simulation with particular input. 479 void SimulateInFramer(const unsigned char* input, size_t size) { 480 framer_.set_enable_compression(use_compression_); 481 framer_.set_visitor(this); 482 size_t input_remaining = size; 483 const char* input_ptr = reinterpret_cast<const char*>(input); 484 while (input_remaining > 0 && 485 framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) { 486 // To make the tests more interesting, we feed random (amd small) chunks 487 // into the framer. This simulates getting strange-sized reads from 488 // the socket. 489 const size_t kMaxReadSize = 32; 490 size_t bytes_read = 491 (rand() % min(input_remaining, kMaxReadSize)) + 1; 492 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read); 493 input_remaining -= bytes_processed; 494 input_ptr += bytes_processed; 495 } 496 } 497 498 void InitHeaderStreaming(SpdyFrameType header_control_type, 499 SpdyStreamId stream_id) { 500 DCHECK_GE(header_control_type, FIRST_CONTROL_TYPE); 501 DCHECK_LE(header_control_type, LAST_CONTROL_TYPE); 502 memset(header_buffer_.get(), 0, header_buffer_size_); 503 header_buffer_length_ = 0; 504 header_stream_id_ = stream_id; 505 header_control_type_ = header_control_type; 506 header_buffer_valid_ = true; 507 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); 508 } 509 510 // Override the default buffer size (16K). Call before using the framer! 511 void set_header_buffer_size(size_t header_buffer_size) { 512 header_buffer_size_ = header_buffer_size; 513 header_buffer_.reset(new char[header_buffer_size]); 514 } 515 516 static size_t header_data_chunk_max_size() { 517 return SpdyFramer::kHeaderDataChunkMaxSize; 518 } 519 520 SpdyFramer framer_; 521 bool use_compression_; 522 523 // Counters from the visitor callbacks. 524 int error_count_; 525 int syn_frame_count_; 526 int syn_reply_frame_count_; 527 int headers_frame_count_; 528 int goaway_count_; 529 int setting_count_; 530 SpdyStreamId last_window_update_stream_; 531 uint32 last_window_update_delta_; 532 SpdyStreamId last_push_promise_stream_; 533 SpdyStreamId last_push_promise_promised_stream_; 534 int data_bytes_; 535 int fin_frame_count_; // The count of RST_STREAM type frames received. 536 int fin_flag_count_; // The count of frames with the FIN flag set. 537 int zero_length_data_frame_count_; // The count of zero-length data frames. 538 int control_frame_header_data_count_; // The count of chunks received. 539 // The count of zero-length control frame header data chunks received. 540 int zero_length_control_frame_header_data_count_; 541 int data_frame_count_; 542 size_t last_payload_len_; 543 size_t last_frame_len_; 544 545 // Header block streaming state: 546 scoped_ptr<char[]> header_buffer_; 547 size_t header_buffer_length_; 548 size_t header_buffer_size_; 549 SpdyStreamId header_stream_id_; 550 SpdyFrameType header_control_type_; 551 bool header_buffer_valid_; 552 SpdyHeaderBlock headers_; 553 554 scoped_ptr<char[]> credential_buffer_; 555 size_t credential_buffer_length_; 556 size_t credential_buffer_size_; 557 SpdyCredential credential_; 558 }; 559 560 // Retrieves serialized headers from SYN_STREAM frame. 561 // Does not check that the given frame is a SYN_STREAM. 562 base::StringPiece GetSerializedHeaders(const SpdyFrame* frame, 563 const SpdyFramer& framer) { 564 return base::StringPiece(frame->data() + framer.GetSynStreamMinimumSize(), 565 frame->size() - framer.GetSynStreamMinimumSize()); 566 } 567 568 } // namespace test 569 570 } // namespace net 571 572 using net::test::SetFrameLength; 573 using net::test::SetFrameFlags; 574 using net::test::CompareCharArraysWithHexError; 575 using net::test::SpdyFramerTestUtil; 576 using net::test::TestSpdyVisitor; 577 using net::test::GetSerializedHeaders; 578 579 namespace net { 580 581 class SpdyFramerTest : public ::testing::TestWithParam<SpdyMajorVersion> { 582 protected: 583 virtual void SetUp() { 584 spdy_version_ = GetParam(); 585 spdy_version_ch_ = static_cast<unsigned char>(spdy_version_); 586 } 587 588 void CompareFrame(const string& description, 589 const SpdyFrame& actual_frame, 590 const unsigned char* expected, 591 const int expected_len) { 592 const unsigned char* actual = 593 reinterpret_cast<const unsigned char*>(actual_frame.data()); 594 CompareCharArraysWithHexError( 595 description, actual, actual_frame.size(), expected, expected_len); 596 } 597 598 void CompareFrames(const string& description, 599 const SpdyFrame& expected_frame, 600 const SpdyFrame& actual_frame) { 601 CompareCharArraysWithHexError( 602 description, 603 reinterpret_cast<const unsigned char*>(expected_frame.data()), 604 expected_frame.size(), 605 reinterpret_cast<const unsigned char*>(actual_frame.data()), 606 actual_frame.size()); 607 } 608 609 // Returns true if the two header blocks have equivalent content. 610 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected, 611 const SpdyHeaderBlock* actual) { 612 if (expected->size() != actual->size()) { 613 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got " 614 << actual->size() << "."; 615 return false; 616 } 617 for (SpdyHeaderBlock::const_iterator it = expected->begin(); 618 it != expected->end(); 619 ++it) { 620 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first); 621 if (it2 == actual->end()) { 622 LOG(ERROR) << "Expected header name '" << it->first << "'."; 623 return false; 624 } 625 if (it->second.compare(it2->second) != 0) { 626 LOG(ERROR) << "Expected header named '" << it->first 627 << "' to have a value of '" << it->second 628 << "'. The actual value received was '" << it2->second 629 << "'."; 630 return false; 631 } 632 } 633 return true; 634 } 635 636 void AddSpdySettingFromWireFormat(SettingsMap* settings, 637 uint32 key, 638 uint32 value) { 639 SettingsFlagsAndId flags_and_id = 640 SettingsFlagsAndId::FromWireFormat(spdy_version_, key); 641 SpdySettingsIds id = static_cast<SpdySettingsIds>(flags_and_id.id()); 642 SpdySettingsFlags flags = 643 static_cast<SpdySettingsFlags>(flags_and_id.flags()); 644 CHECK(settings->find(id) == settings->end()); 645 settings->insert(std::make_pair(id, SettingsFlagsAndValue(flags, value))); 646 } 647 648 bool IsSpdy2() { return spdy_version_ == SPDY2; } 649 bool IsSpdy3() { return spdy_version_ == SPDY3; } 650 bool IsSpdy4() { return spdy_version_ == SPDY4; } 651 652 // Version of SPDY protocol to be used. 653 SpdyMajorVersion spdy_version_; 654 unsigned char spdy_version_ch_; 655 }; 656 657 // All tests are run with 3 different SPDY versions: SPDY/2, SPDY/3, SPDY/4. 658 INSTANTIATE_TEST_CASE_P(SpdyFramerTests, 659 SpdyFramerTest, 660 ::testing::Values(SPDY2, SPDY3, SPDY4)); 661 662 // Test that we can encode and decode a SpdyHeaderBlock in serialized form. 663 TEST_P(SpdyFramerTest, HeaderBlockInBuffer) { 664 SpdyHeaderBlock headers; 665 headers["alpha"] = "beta"; 666 headers["gamma"] = "charlie"; 667 SpdyFramer framer(spdy_version_); 668 framer.set_enable_compression(false); 669 670 // Encode the header block into a SynStream frame. 671 scoped_ptr<SpdyFrame> frame( 672 framer.CreateSynStream(1, // stream id 673 0, // associated stream id 674 1, // priority 675 0, // credential slot 676 CONTROL_FLAG_NONE, 677 false, // compress 678 &headers)); 679 EXPECT_TRUE(frame.get() != NULL); 680 base::StringPiece serialized_headers = 681 GetSerializedHeaders(frame.get(), framer); 682 SpdyHeaderBlock new_headers; 683 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(), 684 serialized_headers.size(), 685 &new_headers)); 686 687 EXPECT_EQ(headers.size(), new_headers.size()); 688 EXPECT_EQ(headers["alpha"], new_headers["alpha"]); 689 EXPECT_EQ(headers["gamma"], new_headers["gamma"]); 690 } 691 692 // Test that if there's not a full frame, we fail to parse it. 693 TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) { 694 SpdyHeaderBlock headers; 695 headers["alpha"] = "beta"; 696 headers["gamma"] = "charlie"; 697 SpdyFramer framer(spdy_version_); 698 framer.set_enable_compression(false); 699 700 // Encode the header block into a SynStream frame. 701 scoped_ptr<SpdyFrame> frame( 702 framer.CreateSynStream(1, // stream id 703 0, // associated stream id 704 1, // priority 705 0, // credential slot 706 CONTROL_FLAG_NONE, 707 false, // compress 708 &headers)); 709 EXPECT_TRUE(frame.get() != NULL); 710 711 base::StringPiece serialized_headers = 712 GetSerializedHeaders(frame.get(), framer); 713 SpdyHeaderBlock new_headers; 714 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(), 715 serialized_headers.size() - 2, 716 &new_headers)); 717 } 718 719 TEST_P(SpdyFramerTest, OutOfOrderHeaders) { 720 SpdyFramer framer(spdy_version_); 721 framer.set_enable_compression(false); 722 723 // Frame builder with plentiful buffer size. 724 SpdyFrameBuilder frame(1024); 725 if (spdy_version_ < 4) { 726 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE); 727 frame.WriteUInt32(3); // stream_id 728 } else { 729 frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3); 730 } 731 732 frame.WriteUInt32(0); // Associated stream id 733 frame.WriteUInt16(0); // Priority. 734 735 if (IsSpdy2()) { 736 frame.WriteUInt16(2); // Number of headers. 737 frame.WriteString("gamma"); 738 frame.WriteString("gamma"); 739 frame.WriteString("alpha"); 740 frame.WriteString("alpha"); 741 } else { 742 frame.WriteUInt32(2); // Number of headers. 743 frame.WriteStringPiece32("gamma"); 744 frame.WriteStringPiece32("gamma"); 745 frame.WriteStringPiece32("alpha"); 746 frame.WriteStringPiece32("alpha"); 747 } 748 // write the length 749 frame.RewriteLength(framer); 750 751 SpdyHeaderBlock new_headers; 752 scoped_ptr<SpdyFrame> control_frame(frame.take()); 753 base::StringPiece serialized_headers = 754 GetSerializedHeaders(control_frame.get(), framer); 755 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(), 756 serialized_headers.size(), 757 &new_headers)); 758 } 759 760 // Test that if we receive a SYN_STREAM with stream ID zero, we signal an error 761 // (but don't crash). 762 TEST_P(SpdyFramerTest, SynStreamWithStreamIdZero) { 763 testing::StrictMock<net::test::MockVisitor> visitor; 764 SpdyFramer framer(spdy_version_); 765 framer.set_visitor(&visitor); 766 767 SpdyHeaderBlock headers; 768 headers["alpha"] = "beta"; 769 scoped_ptr<SpdySerializedFrame> frame( 770 framer.CreateSynStream(0, // stream id 771 0, // associated stream id 772 1, // priority 773 0, // credential slot 774 CONTROL_FLAG_NONE, 775 true, // compress 776 &headers)); 777 ASSERT_TRUE(frame.get() != NULL); 778 779 // We shouldn't have to read the whole frame before we signal an error. 780 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); 781 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); 782 EXPECT_TRUE(framer.HasError()); 783 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) 784 << SpdyFramer::ErrorCodeToString(framer.error_code()); 785 } 786 787 // Test that if we receive a SYN_REPLY with stream ID zero, we signal an error 788 // (but don't crash). 789 TEST_P(SpdyFramerTest, SynReplyWithStreamIdZero) { 790 testing::StrictMock<net::test::MockVisitor> visitor; 791 SpdyFramer framer(spdy_version_); 792 framer.set_visitor(&visitor); 793 794 SpdyHeaderBlock headers; 795 headers["alpha"] = "beta"; 796 scoped_ptr<SpdySerializedFrame> frame( 797 framer.CreateSynReply(0, // stream id 798 CONTROL_FLAG_NONE, 799 true, // compress 800 &headers)); 801 ASSERT_TRUE(frame.get() != NULL); 802 803 // We shouldn't have to read the whole frame before we signal an error. 804 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); 805 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); 806 EXPECT_TRUE(framer.HasError()); 807 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) 808 << SpdyFramer::ErrorCodeToString(framer.error_code()); 809 } 810 811 // Test that if we receive a HEADERS with stream ID zero, we signal an error 812 // (but don't crash). 813 TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) { 814 testing::StrictMock<net::test::MockVisitor> visitor; 815 SpdyFramer framer(spdy_version_); 816 framer.set_visitor(&visitor); 817 818 SpdyHeaderBlock headers; 819 headers["alpha"] = "beta"; 820 scoped_ptr<SpdySerializedFrame> frame( 821 framer.CreateHeaders(0, // stream id 822 CONTROL_FLAG_NONE, 823 true, // compress 824 &headers)); 825 ASSERT_TRUE(frame.get() != NULL); 826 827 // We shouldn't have to read the whole frame before we signal an error. 828 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); 829 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); 830 EXPECT_TRUE(framer.HasError()); 831 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) 832 << SpdyFramer::ErrorCodeToString(framer.error_code()); 833 } 834 835 // Test that if we receive a PUSH_PROMISE with stream ID zero, we signal an 836 // error (but don't crash). 837 TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) { 838 if (spdy_version_ < SPDY4) { 839 return; 840 } 841 842 testing::StrictMock<net::test::MockVisitor> visitor; 843 SpdyFramer framer(spdy_version_); 844 framer.set_visitor(&visitor); 845 846 SpdyHeaderBlock headers; 847 headers["alpha"] = "beta"; 848 scoped_ptr<SpdySerializedFrame> frame( 849 framer.CreatePushPromise(0, // stream id 850 4, // promised stream id 851 &headers)); 852 ASSERT_TRUE(frame.get() != NULL); 853 854 // We shouldn't have to read the whole frame before we signal an error. 855 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); 856 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); 857 EXPECT_TRUE(framer.HasError()); 858 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) 859 << SpdyFramer::ErrorCodeToString(framer.error_code()); 860 } 861 862 // Test that if we receive a PUSH_PROMISE with promised stream ID zero, we 863 // signal an error (but don't crash). 864 TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) { 865 if (spdy_version_ < SPDY4) { 866 return; 867 } 868 869 testing::StrictMock<net::test::MockVisitor> visitor; 870 SpdyFramer framer(spdy_version_); 871 framer.set_visitor(&visitor); 872 873 SpdyHeaderBlock headers; 874 headers["alpha"] = "beta"; 875 scoped_ptr<SpdySerializedFrame> frame( 876 framer.CreatePushPromise(3, // stream id 877 0, // promised stream id 878 &headers)); 879 ASSERT_TRUE(frame.get() != NULL); 880 881 // We shouldn't have to read the whole frame before we signal an error. 882 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); 883 EXPECT_GT(frame->size(), framer.ProcessInput(frame->data(), frame->size())); 884 EXPECT_TRUE(framer.HasError()); 885 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code()) 886 << SpdyFramer::ErrorCodeToString(framer.error_code()); 887 } 888 889 TEST_P(SpdyFramerTest, CreateCredential) { 890 SpdyFramer framer(spdy_version_); 891 892 { 893 const char kDescription[] = "CREDENTIAL frame"; 894 const unsigned char kV3FrameData[] = { // Also applies for V2. 895 0x80, spdy_version_ch_, 0x00, 0x0A, 896 0x00, 0x00, 0x00, 0x33, 897 0x00, 0x03, 0x00, 0x00, 898 0x00, 0x05, 'p', 'r', 899 'o', 'o', 'f', 0x00, 900 0x00, 0x00, 0x06, 'a', 901 ' ', 'c', 'e', 'r', 902 't', 0x00, 0x00, 0x00, 903 0x0C, 'a', 'n', 'o', 904 't', 'h', 'e', 'r', 905 ' ', 'c', 'e', 'r', 906 't', 0x00, 0x00, 0x00, 907 0x0A, 'f', 'i', 'n', 908 'a', 'l', ' ', 'c', 909 'e', 'r', 't', 910 }; 911 const unsigned char kV4FrameData[] = { 912 0x00, 0x3b, 0x0A, 0x00, 913 0x00, 0x00, 0x00, 0x00, 914 0x00, 0x03, 0x00, 0x00, 915 0x00, 0x05, 'p', 'r', 916 'o', 'o', 'f', 0x00, 917 0x00, 0x00, 0x06, 'a', 918 ' ', 'c', 'e', 'r', 919 't', 0x00, 0x00, 0x00, 920 0x0C, 'a', 'n', 'o', 921 't', 'h', 'e', 'r', 922 ' ', 'c', 'e', 'r', 923 't', 0x00, 0x00, 0x00, 924 0x0A, 'f', 'i', 'n', 925 'a', 'l', ' ', 'c', 926 'e', 'r', 't', 927 }; 928 SpdyCredential credential; 929 credential.slot = 3; 930 credential.proof = "proof"; 931 credential.certs.push_back("a cert"); 932 credential.certs.push_back("another cert"); 933 credential.certs.push_back("final cert"); 934 scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential)); 935 if (IsSpdy4()) { 936 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 937 } else { 938 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 939 } 940 } 941 } 942 943 TEST_P(SpdyFramerTest, ParseCredentialFrameData) { 944 SpdyFramer framer(spdy_version_); 945 946 { 947 const unsigned char kV3FrameData[] = { // Also applies for V2. 948 0x80, spdy_version_ch_, 0x00, 0x0A, 949 0x00, 0x00, 0x00, 0x33, 950 0x00, 0x03, 0x00, 0x00, 951 0x00, 0x05, 'p', 'r', 952 'o', 'o', 'f', 0x00, 953 0x00, 0x00, 0x06, 'a', 954 ' ', 'c', 'e', 'r', 955 't', 0x00, 0x00, 0x00, 956 0x0C, 'a', 'n', 'o', 957 't', 'h', 'e', 'r', 958 ' ', 'c', 'e', 'r', 959 't', 0x00, 0x00, 0x00, 960 0x0A, 'f', 'i', 'n', 961 'a', 'l', ' ', 'c', 962 'e', 'r', 't', 963 }; 964 const unsigned char kV4FrameData[] = { 965 0x00, 0x37, 0x0A, 0x00, 966 0x00, 0x00, 0x00, 0x00, 967 0x00, 0x03, 0x00, 0x00, 968 0x00, 0x05, 'p', 'r', 969 'o', 'o', 'f', 0x00, 970 0x00, 0x00, 0x06, 'a', 971 ' ', 'c', 'e', 'r', 972 't', 0x00, 0x00, 0x00, 973 0x0C, 'a', 'n', 'o', 974 't', 'h', 'e', 'r', 975 ' ', 'c', 'e', 'r', 976 't', 0x00, 0x00, 0x00, 977 0x0A, 'f', 'i', 'n', 978 'a', 'l', ' ', 'c', 979 'e', 'r', 't', 980 }; 981 982 SpdyCredential credential; 983 if (IsSpdy4()) { 984 EXPECT_TRUE(SpdyFramer::ParseCredentialData( 985 reinterpret_cast<const char*>(kV4FrameData) + 986 framer.GetControlFrameHeaderSize(), 987 arraysize(kV4FrameData) - framer.GetControlFrameHeaderSize(), 988 &credential)); 989 } else { 990 EXPECT_TRUE(SpdyFramer::ParseCredentialData( 991 reinterpret_cast<const char*>(kV3FrameData) + 992 framer.GetControlFrameHeaderSize(), 993 arraysize(kV3FrameData) - framer.GetControlFrameHeaderSize(), 994 &credential)); 995 } 996 EXPECT_EQ(3u, credential.slot); 997 EXPECT_EQ("proof", credential.proof); 998 EXPECT_EQ("a cert", credential.certs.front()); 999 credential.certs.erase(credential.certs.begin()); 1000 EXPECT_EQ("another cert", credential.certs.front()); 1001 credential.certs.erase(credential.certs.begin()); 1002 EXPECT_EQ("final cert", credential.certs.front()); 1003 credential.certs.erase(credential.certs.begin()); 1004 EXPECT_TRUE(credential.certs.empty()); 1005 } 1006 } 1007 1008 TEST_P(SpdyFramerTest, DuplicateHeader) { 1009 SpdyFramer framer(spdy_version_); 1010 // Frame builder with plentiful buffer size. 1011 SpdyFrameBuilder frame(1024); 1012 if (spdy_version_ < 4) { 1013 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE); 1014 frame.WriteUInt32(3); // stream_id 1015 } else { 1016 frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3); 1017 } 1018 1019 frame.WriteUInt32(0); // associated stream id 1020 frame.WriteUInt16(0); // Priority. 1021 1022 if (IsSpdy2()) { 1023 frame.WriteUInt16(2); // Number of headers. 1024 frame.WriteString("name"); 1025 frame.WriteString("value1"); 1026 frame.WriteString("name"); 1027 frame.WriteString("value2"); 1028 } else { 1029 frame.WriteUInt32(2); // Number of headers. 1030 frame.WriteStringPiece32("name"); 1031 frame.WriteStringPiece32("value1"); 1032 frame.WriteStringPiece32("name"); 1033 frame.WriteStringPiece32("value2"); 1034 } 1035 // write the length 1036 frame.RewriteLength(framer); 1037 1038 SpdyHeaderBlock new_headers; 1039 framer.set_enable_compression(false); 1040 scoped_ptr<SpdyFrame> control_frame(frame.take()); 1041 base::StringPiece serialized_headers = 1042 GetSerializedHeaders(control_frame.get(), framer); 1043 // This should fail because duplicate headers are verboten by the spec. 1044 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(), 1045 serialized_headers.size(), 1046 &new_headers)); 1047 } 1048 1049 TEST_P(SpdyFramerTest, MultiValueHeader) { 1050 SpdyFramer framer(spdy_version_); 1051 // Frame builder with plentiful buffer size. 1052 SpdyFrameBuilder frame(1024); 1053 if (spdy_version_ < 4) { 1054 frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE); 1055 frame.WriteUInt32(3); // stream_id 1056 } else { 1057 frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3); 1058 } 1059 1060 frame.WriteUInt32(0); // associated stream id 1061 frame.WriteUInt16(0); // Priority. 1062 1063 string value("value1\0value2"); 1064 if (IsSpdy2()) { 1065 frame.WriteUInt16(1); // Number of headers. 1066 frame.WriteString("name"); 1067 frame.WriteString(value); 1068 } else { 1069 frame.WriteUInt32(1); // Number of headers. 1070 frame.WriteStringPiece32("name"); 1071 frame.WriteStringPiece32(value); 1072 } 1073 // write the length 1074 frame.RewriteLength(framer); 1075 1076 SpdyHeaderBlock new_headers; 1077 framer.set_enable_compression(false); 1078 scoped_ptr<SpdyFrame> control_frame(frame.take()); 1079 base::StringPiece serialized_headers = 1080 GetSerializedHeaders(control_frame.get(), framer); 1081 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(), 1082 serialized_headers.size(), 1083 &new_headers)); 1084 EXPECT_TRUE(new_headers.find("name") != new_headers.end()); 1085 EXPECT_EQ(value, new_headers.find("name")->second); 1086 } 1087 1088 TEST_P(SpdyFramerTest, BasicCompression) { 1089 SpdyHeaderBlock headers; 1090 headers["server"] = "SpdyServer 1.0"; 1091 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; 1092 headers["status"] = "200"; 1093 headers["version"] = "HTTP/1.1"; 1094 headers["content-type"] = "text/html"; 1095 headers["content-length"] = "12"; 1096 1097 scoped_ptr<TestSpdyVisitor> visitor(new TestSpdyVisitor(spdy_version_)); 1098 SpdyFramer framer(spdy_version_); 1099 framer.set_debug_visitor(visitor.get()); 1100 scoped_ptr<SpdyFrame> frame1( 1101 framer.CreateSynStream(1, // stream id 1102 0, // associated stream id 1103 1, // priority 1104 0, // credential slot 1105 CONTROL_FLAG_NONE, 1106 true, // compress 1107 &headers)); 1108 size_t uncompressed_size1 = visitor->last_payload_len_; 1109 size_t compressed_size1 = 1110 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize(); 1111 if (IsSpdy2()) { 1112 EXPECT_EQ(139u, uncompressed_size1); 1113 #if defined(USE_SYSTEM_ZLIB) 1114 EXPECT_EQ(155u, compressed_size1); 1115 #else // !defined(USE_SYSTEM_ZLIB) 1116 EXPECT_EQ(135u, compressed_size1); 1117 #endif // !defined(USE_SYSTEM_ZLIB) 1118 } else { 1119 EXPECT_EQ(165u, uncompressed_size1); 1120 #if defined(USE_SYSTEM_ZLIB) 1121 EXPECT_EQ(181u, compressed_size1); 1122 #else // !defined(USE_SYSTEM_ZLIB) 1123 EXPECT_EQ(117u, compressed_size1); 1124 #endif // !defined(USE_SYSTEM_ZLIB) 1125 } 1126 scoped_ptr<SpdyFrame> frame2( 1127 framer.CreateSynStream(1, // stream id 1128 0, // associated stream id 1129 1, // priority 1130 0, // credential slot 1131 CONTROL_FLAG_NONE, 1132 true, // compress 1133 &headers)); 1134 size_t uncompressed_size2 = visitor->last_payload_len_; 1135 size_t compressed_size2 = 1136 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize(); 1137 1138 // Expect the second frame to be more compact than the first. 1139 EXPECT_LE(frame2->size(), frame1->size()); 1140 1141 // Decompress the first frame 1142 scoped_ptr<SpdyFrame> frame3(SpdyFramerTestUtil::DecompressFrame( 1143 &framer, *frame1.get())); 1144 1145 // Decompress the second frame 1146 visitor.reset(new TestSpdyVisitor(spdy_version_)); 1147 framer.set_debug_visitor(visitor.get()); 1148 scoped_ptr<SpdyFrame> frame4(SpdyFramerTestUtil::DecompressFrame( 1149 &framer, *frame2.get())); 1150 size_t uncompressed_size4 = 1151 frame4->size() - framer.GetSynStreamMinimumSize(); 1152 size_t compressed_size4 = 1153 visitor->last_frame_len_ - framer.GetSynStreamMinimumSize(); 1154 if (IsSpdy2()) { 1155 EXPECT_EQ(139u, uncompressed_size4); 1156 #if defined(USE_SYSTEM_ZLIB) 1157 EXPECT_EQ(149u, compressed_size4); 1158 #else // !defined(USE_SYSTEM_ZLIB) 1159 EXPECT_EQ(101u, compressed_size4); 1160 #endif // !defined(USE_SYSTEM_ZLIB) 1161 } else { 1162 EXPECT_EQ(165u, uncompressed_size4); 1163 #if defined(USE_SYSTEM_ZLIB) 1164 EXPECT_EQ(175u, compressed_size4); 1165 #else // !defined(USE_SYSTEM_ZLIB) 1166 EXPECT_EQ(102u, compressed_size4); 1167 #endif // !defined(USE_SYSTEM_ZLIB) 1168 } 1169 1170 EXPECT_EQ(uncompressed_size1, uncompressed_size2); 1171 EXPECT_EQ(uncompressed_size1, uncompressed_size4); 1172 EXPECT_EQ(compressed_size2, compressed_size4); 1173 1174 // Expect frames 3 & 4 to be the same. 1175 CompareFrames("Uncompressed SYN_STREAM", *frame3, *frame4); 1176 1177 // Expect frames 3 to be the same as a uncompressed frame created 1178 // from scratch. 1179 framer.set_enable_compression(false); 1180 scoped_ptr<SpdyFrame> uncompressed_frame( 1181 framer.CreateSynStream(1, // stream id 1182 0, // associated stream id 1183 1, // priority 1184 0, // credential slot 1185 CONTROL_FLAG_NONE, 1186 false, // compress 1187 &headers)); 1188 CompareFrames("Uncompressed SYN_STREAM", *frame3, *uncompressed_frame); 1189 } 1190 1191 TEST_P(SpdyFramerTest, CompressEmptyHeaders) { 1192 // See crbug.com/172383 1193 SpdyHeaderBlock headers; 1194 headers["server"] = "SpdyServer 1.0"; 1195 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; 1196 headers["status"] = "200"; 1197 headers["version"] = "HTTP/1.1"; 1198 headers["content-type"] = "text/html"; 1199 headers["content-length"] = "12"; 1200 headers["x-empty-header"] = ""; 1201 1202 SpdyFramer framer(spdy_version_); 1203 framer.set_enable_compression(true); 1204 scoped_ptr<SpdyFrame> frame1( 1205 framer.CreateSynStream(1, // stream id 1206 0, // associated stream id 1207 1, // priority 1208 0, // credential slot 1209 CONTROL_FLAG_NONE, 1210 true, // compress 1211 &headers)); 1212 } 1213 1214 TEST_P(SpdyFramerTest, Basic) { 1215 const unsigned char kV2Input[] = { 1216 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 1217 0x00, 0x00, 0x00, 0x14, 1218 0x00, 0x00, 0x00, 0x01, 1219 0x00, 0x00, 0x00, 0x00, 1220 0x00, 0x00, 0x00, 0x01, 1221 0x00, 0x02, 'h', 'h', 1222 0x00, 0x02, 'v', 'v', 1223 1224 0x80, spdy_version_ch_, 0x00, 0x08, // HEADERS on Stream #1 1225 0x00, 0x00, 0x00, 0x18, 1226 0x00, 0x00, 0x00, 0x01, 1227 0x00, 0x00, 0x00, 0x02, 1228 0x00, 0x02, 'h', '2', 1229 0x00, 0x02, 'v', '2', 1230 0x00, 0x02, 'h', '3', 1231 0x00, 0x02, 'v', '3', 1232 1233 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 1234 0x00, 0x00, 0x00, 0x0c, 1235 0xde, 0xad, 0xbe, 0xef, 1236 0xde, 0xad, 0xbe, 0xef, 1237 0xde, 0xad, 0xbe, 0xef, 1238 1239 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #3 1240 0x00, 0x00, 0x00, 0x0c, 1241 0x00, 0x00, 0x00, 0x03, 1242 0x00, 0x00, 0x00, 0x00, 1243 0x00, 0x00, 0x00, 0x00, 1244 1245 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 1246 0x00, 0x00, 0x00, 0x08, 1247 0xde, 0xad, 0xbe, 0xef, 1248 0xde, 0xad, 0xbe, 0xef, 1249 1250 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 1251 0x00, 0x00, 0x00, 0x04, 1252 0xde, 0xad, 0xbe, 0xef, 1253 1254 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #1 1255 0x00, 0x00, 0x00, 0x08, 1256 0x00, 0x00, 0x00, 0x01, 1257 0x00, 0x00, 0x00, 0x00, 1258 1259 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 1260 0x00, 0x00, 0x00, 0x00, 1261 1262 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #3 1263 0x00, 0x00, 0x00, 0x08, 1264 0x00, 0x00, 0x00, 0x03, 1265 0x00, 0x00, 0x00, 0x00, 1266 }; 1267 1268 const unsigned char kV3Input[] = { 1269 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 1270 0x00, 0x00, 0x00, 0x1a, 1271 0x00, 0x00, 0x00, 0x01, 1272 0x00, 0x00, 0x00, 0x00, 1273 0x00, 0x00, 0x00, 0x00, 1274 0x00, 0x01, 0x00, 0x00, 1275 0x00, 0x02, 'h', 'h', 1276 0x00, 0x00, 0x00, 0x02, 1277 'v', 'v', 1278 1279 0x80, spdy_version_ch_, 0x00, 0x08, // HEADERS on Stream #1 1280 0x00, 0x00, 0x00, 0x20, 1281 0x00, 0x00, 0x00, 0x01, 1282 0x00, 0x00, 0x00, 0x02, 1283 0x00, 0x00, 0x00, 0x02, 1284 'h', '2', 1285 0x00, 0x00, 0x00, 0x02, 1286 'v', '2', 0x00, 0x00, 1287 0x00, 0x02, 'h', '3', 1288 0x00, 0x00, 0x00, 0x02, 1289 'v', '3', 1290 1291 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 1292 0x00, 0x00, 0x00, 0x0c, 1293 0xde, 0xad, 0xbe, 0xef, 1294 0xde, 0xad, 0xbe, 0xef, 1295 0xde, 0xad, 0xbe, 0xef, 1296 1297 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #3 1298 0x00, 0x00, 0x00, 0x0e, 1299 0x00, 0x00, 0x00, 0x03, 1300 0x00, 0x00, 0x00, 0x00, 1301 0x00, 0x00, 0x00, 0x00, 1302 0x00, 0x00, 1303 1304 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 1305 0x00, 0x00, 0x00, 0x08, 1306 0xde, 0xad, 0xbe, 0xef, 1307 0xde, 0xad, 0xbe, 0xef, 1308 1309 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 1310 0x00, 0x00, 0x00, 0x04, 1311 0xde, 0xad, 0xbe, 0xef, 1312 1313 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #1 1314 0x00, 0x00, 0x00, 0x08, 1315 0x00, 0x00, 0x00, 0x01, 1316 0x00, 0x00, 0x00, 0x00, 1317 1318 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 1319 0x00, 0x00, 0x00, 0x00, 1320 1321 0x80, spdy_version_ch_, 0x00, 0x03, // RST_STREAM on Stream #3 1322 0x00, 0x00, 0x00, 0x08, 1323 0x00, 0x00, 0x00, 0x03, 1324 0x00, 0x00, 0x00, 0x00, 1325 }; 1326 1327 const unsigned char kV4Input[] = { 1328 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1 1329 0x00, 0x00, 0x00, 0x01, 1330 0x00, 0x00, 0x00, 0x00, 1331 0x00, 0x00, 0x00, 0x00, 1332 0x00, 0x01, 0x00, 0x00, 1333 0x00, 0x02, 'h', 'h', 1334 0x00, 0x00, 0x00, 0x02, 1335 'v', 'v', 1336 1337 0x00, 0x24, 0x08, 0x00, // HEADERS on Stream #1 1338 0x00, 0x00, 0x00, 0x01, 1339 0x00, 0x00, 0x00, 0x02, 1340 0x00, 0x00, 0x00, 0x02, 1341 'h', '2', 0x00, 0x00, 1342 0x00, 0x02, 'v', '2', 1343 0x00, 0x00, 0x00, 0x02, 1344 'h', '3', 0x00, 0x00, 1345 0x00, 0x02, 'v', '3', 1346 1347 0x00, 0x14, 0x00, 0x00, // DATA on Stream #1 1348 0x00, 0x00, 0x00, 0x01, 1349 0xde, 0xad, 0xbe, 0xef, 1350 0xde, 0xad, 0xbe, 0xef, 1351 0xde, 0xad, 0xbe, 0xef, 1352 1353 0x00, 0x12, 0x01, 0x00, // SYN Stream #3 1354 0x00, 0x00, 0x00, 0x03, 1355 0x00, 0x00, 0x00, 0x00, 1356 0x00, 0x00, 0x00, 0x00, 1357 0x00, 0x00, 1358 1359 0x00, 0x10, 0x00, 0x00, // DATA on Stream #3 1360 0x00, 0x00, 0x00, 0x03, 1361 0xde, 0xad, 0xbe, 0xef, 1362 0xde, 0xad, 0xbe, 0xef, 1363 1364 0x00, 0x0c, 0x00, 0x00, // DATA on Stream #1 1365 0x00, 0x00, 0x00, 0x01, 1366 0xde, 0xad, 0xbe, 0xef, 1367 1368 0x00, 0x0c, 0x03, 0x00, // RST_STREAM on Stream #1 1369 0x00, 0x00, 0x00, 0x01, 1370 0x00, 0x00, 0x00, 0x00, 1371 1372 0x00, 0x08, 0x00, 0x00, // DATA on Stream #3 1373 0x00, 0x00, 0x00, 0x03, 1374 1375 0x00, 0x0c, 0x03, 0x00, // RST_STREAM on Stream #3 1376 0x00, 0x00, 0x00, 0x03, 1377 0x00, 0x00, 0x00, 0x00, 1378 }; 1379 1380 TestSpdyVisitor visitor(spdy_version_); 1381 if (IsSpdy2()) { 1382 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); 1383 } else if (IsSpdy3()) { 1384 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); 1385 } else { 1386 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input)); 1387 } 1388 1389 EXPECT_EQ(0, visitor.error_count_); 1390 EXPECT_EQ(2, visitor.syn_frame_count_); 1391 EXPECT_EQ(0, visitor.syn_reply_frame_count_); 1392 EXPECT_EQ(1, visitor.headers_frame_count_); 1393 EXPECT_EQ(24, visitor.data_bytes_); 1394 EXPECT_EQ(2, visitor.fin_frame_count_); 1395 EXPECT_EQ(0, visitor.fin_flag_count_); 1396 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); 1397 EXPECT_EQ(4, visitor.data_frame_count_); 1398 } 1399 1400 // Test that the FIN flag on a data frame signifies EOF. 1401 TEST_P(SpdyFramerTest, FinOnDataFrame) { 1402 const unsigned char kV2Input[] = { 1403 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 1404 0x00, 0x00, 0x00, 0x14, 1405 0x00, 0x00, 0x00, 0x01, 1406 0x00, 0x00, 0x00, 0x00, 1407 0x00, 0x00, 0x00, 0x01, 1408 0x00, 0x02, 'h', 'h', 1409 0x00, 0x02, 'v', 'v', 1410 1411 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1 1412 0x00, 0x00, 0x00, 0x10, 1413 0x00, 0x00, 0x00, 0x01, 1414 0x00, 0x00, 0x00, 0x01, 1415 0x00, 0x02, 'a', 'a', 1416 0x00, 0x02, 'b', 'b', 1417 1418 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 1419 0x00, 0x00, 0x00, 0x0c, 1420 0xde, 0xad, 0xbe, 0xef, 1421 0xde, 0xad, 0xbe, 0xef, 1422 0xde, 0xad, 0xbe, 0xef, 1423 1424 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF 1425 0x01, 0x00, 0x00, 0x04, 1426 0xde, 0xad, 0xbe, 0xef, 1427 }; 1428 const unsigned char kV3Input[] = { 1429 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 1430 0x00, 0x00, 0x00, 0x1a, 1431 0x00, 0x00, 0x00, 0x01, 1432 0x00, 0x00, 0x00, 0x00, 1433 0x00, 0x00, 0x00, 0x00, 1434 0x00, 0x01, 0x00, 0x00, 1435 0x00, 0x02, 'h', 'h', 1436 0x00, 0x00, 0x00, 0x02, 1437 'v', 'v', 1438 1439 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1 1440 0x00, 0x00, 0x00, 0x14, 1441 0x00, 0x00, 0x00, 0x01, 1442 0x00, 0x00, 0x00, 0x01, 1443 0x00, 0x00, 0x00, 0x02, 1444 'a', 'a', 0x00, 0x00, 1445 0x00, 0x02, 'b', 'b', 1446 1447 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 1448 0x00, 0x00, 0x00, 0x0c, 1449 0xde, 0xad, 0xbe, 0xef, 1450 0xde, 0xad, 0xbe, 0xef, 1451 0xde, 0xad, 0xbe, 0xef, 1452 1453 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF 1454 0x01, 0x00, 0x00, 0x04, 1455 0xde, 0xad, 0xbe, 0xef, 1456 }; 1457 const unsigned char kV4Input[] = { 1458 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1 1459 0x00, 0x00, 0x00, 0x01, 1460 0x00, 0x00, 0x00, 0x00, 1461 0x00, 0x00, 0x00, 0x00, 1462 0x00, 0x01, 0x00, 0x00, 1463 0x00, 0x02, 'h', 'h', 1464 0x00, 0x00, 0x00, 0x02, 1465 'v', 'v', 1466 1467 0x00, 0x18, 0x02, 0x00, // SYN REPLY Stream #1 1468 0x00, 0x00, 0x00, 0x01, 1469 0x00, 0x00, 0x00, 0x01, 1470 0x00, 0x00, 0x00, 0x02, 1471 'a', 'a', 0x00, 0x00, 1472 0x00, 0x02, 'b', 'b', 1473 1474 0x00, 0x14, 0x00, 0x00, // DATA on Stream #1 1475 0x00, 0x00, 0x00, 0x01, 1476 0xde, 0xad, 0xbe, 0xef, 1477 0xde, 0xad, 0xbe, 0xef, 1478 0xde, 0xad, 0xbe, 0xef, 1479 1480 0x00, 0x0c, 0x00, 0x01, // DATA on Stream #1, with FIN 1481 0x00, 0x00, 0x00, 0x01, 1482 0xde, 0xad, 0xbe, 0xef, 1483 }; 1484 1485 TestSpdyVisitor visitor(spdy_version_); 1486 if (IsSpdy2()) { 1487 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); 1488 } else if (IsSpdy3()) { 1489 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); 1490 } else { 1491 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input)); 1492 } 1493 1494 EXPECT_EQ(0, visitor.error_count_); 1495 EXPECT_EQ(1, visitor.syn_frame_count_); 1496 EXPECT_EQ(1, visitor.syn_reply_frame_count_); 1497 EXPECT_EQ(0, visitor.headers_frame_count_); 1498 EXPECT_EQ(16, visitor.data_bytes_); 1499 EXPECT_EQ(0, visitor.fin_frame_count_); 1500 EXPECT_EQ(0, visitor.fin_flag_count_); 1501 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); 1502 EXPECT_EQ(2, visitor.data_frame_count_); 1503 } 1504 1505 // Test that the FIN flag on a SYN reply frame signifies EOF. 1506 TEST_P(SpdyFramerTest, FinOnSynReplyFrame) { 1507 const unsigned char kV2Input[] = { 1508 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 1509 0x00, 0x00, 0x00, 0x14, 1510 0x00, 0x00, 0x00, 0x01, 1511 0x00, 0x00, 0x00, 0x00, 1512 0x00, 0x00, 0x00, 0x01, 1513 0x00, 0x02, 'h', 'h', 1514 0x00, 0x02, 'v', 'v', 1515 1516 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1 1517 0x01, 0x00, 0x00, 0x10, 1518 0x00, 0x00, 0x00, 0x01, 1519 0x00, 0x00, 0x00, 0x01, 1520 0x00, 0x02, 'a', 'a', 1521 0x00, 0x02, 'b', 'b', 1522 }; 1523 const unsigned char kV3Input[] = { 1524 0x80, spdy_version_ch_, 0x00, 0x01, // SYN Stream #1 1525 0x00, 0x00, 0x00, 0x1a, 1526 0x00, 0x00, 0x00, 0x01, 1527 0x00, 0x00, 0x00, 0x00, 1528 0x00, 0x00, 0x00, 0x00, 1529 0x00, 0x01, 0x00, 0x00, 1530 0x00, 0x02, 'h', 'h', 1531 0x00, 0x00, 0x00, 0x02, 1532 'v', 'v', 1533 1534 0x80, spdy_version_ch_, 0x00, 0x02, // SYN REPLY Stream #1 1535 0x01, 0x00, 0x00, 0x14, 1536 0x00, 0x00, 0x00, 0x01, 1537 0x00, 0x00, 0x00, 0x01, 1538 0x00, 0x00, 0x00, 0x02, 1539 'a', 'a', 0x00, 0x00, 1540 0x00, 0x02, 'b', 'b', 1541 }; 1542 const unsigned char kV4Input[] = { 1543 0x00, 0x1e, 0x01, 0x00, // SYN_STREAM #1 1544 0x00, 0x00, 0x00, 0x01, 1545 0x00, 0x00, 0x00, 0x00, 1546 0x00, 0x00, 0x00, 0x00, 1547 0x00, 0x01, 0x00, 0x00, 1548 0x00, 0x02, 'h', 'h', 1549 0x00, 0x00, 0x00, 0x02, 1550 'v', 'v', 1551 1552 0x00, 0x18, 0x02, 0x01, // SYN_REPLY #1, with FIN 1553 0x00, 0x00, 0x00, 0x01, 1554 0x00, 0x00, 0x00, 0x01, 1555 0x00, 0x00, 0x00, 0x02, 1556 'a', 'a', 0x00, 0x00, 1557 0x00, 0x02, 'b', 'b', 1558 }; 1559 1560 TestSpdyVisitor visitor(spdy_version_); 1561 if (IsSpdy2()) { 1562 visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); 1563 } else if (IsSpdy3()) { 1564 visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); 1565 } else { 1566 visitor.SimulateInFramer(kV4Input, sizeof(kV4Input)); 1567 } 1568 1569 EXPECT_EQ(0, visitor.error_count_); 1570 EXPECT_EQ(1, visitor.syn_frame_count_); 1571 EXPECT_EQ(1, visitor.syn_reply_frame_count_); 1572 EXPECT_EQ(0, visitor.headers_frame_count_); 1573 EXPECT_EQ(0, visitor.data_bytes_); 1574 EXPECT_EQ(0, visitor.fin_frame_count_); 1575 EXPECT_EQ(1, visitor.fin_flag_count_); 1576 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); 1577 EXPECT_EQ(0, visitor.data_frame_count_); 1578 } 1579 1580 TEST_P(SpdyFramerTest, HeaderCompression) { 1581 SpdyFramer send_framer(spdy_version_); 1582 SpdyFramer recv_framer(spdy_version_); 1583 1584 send_framer.set_enable_compression(true); 1585 recv_framer.set_enable_compression(true); 1586 1587 const char kHeader1[] = "header1"; 1588 const char kHeader2[] = "header2"; 1589 const char kHeader3[] = "header3"; 1590 const char kValue1[] = "value1"; 1591 const char kValue2[] = "value2"; 1592 const char kValue3[] = "value3"; 1593 1594 // SYN_STREAM #1 1595 SpdyHeaderBlock block; 1596 block[kHeader1] = kValue1; 1597 block[kHeader2] = kValue2; 1598 SpdyControlFlags flags(CONTROL_FLAG_NONE); 1599 SpdySynStreamIR syn_ir_1(1); 1600 syn_ir_1.SetHeader(kHeader1, kValue1); 1601 syn_ir_1.SetHeader(kHeader2, kValue2); 1602 scoped_ptr<SpdyFrame> syn_frame_1(send_framer.SerializeFrame(syn_ir_1)); 1603 EXPECT_TRUE(syn_frame_1.get() != NULL); 1604 1605 // SYN_STREAM #2 1606 block[kHeader3] = kValue3; 1607 scoped_ptr<SpdyFrame> syn_frame_2( 1608 send_framer.CreateSynStream(3, // stream id 1609 0, // associated stream id 1610 0, // priority 1611 0, // credential slot 1612 flags, 1613 true, // compress 1614 &block)); 1615 EXPECT_TRUE(syn_frame_2.get() != NULL); 1616 1617 // Now start decompressing 1618 scoped_ptr<SpdyFrame> decompressed; 1619 scoped_ptr<SpdyFrame> uncompressed; 1620 base::StringPiece serialized_headers; 1621 SpdyHeaderBlock decompressed_headers; 1622 1623 // Decompress SYN_STREAM #1 1624 decompressed.reset(SpdyFramerTestUtil::DecompressFrame( 1625 &recv_framer, *syn_frame_1.get())); 1626 EXPECT_TRUE(decompressed.get() != NULL); 1627 serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer); 1628 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(), 1629 serialized_headers.size(), 1630 &decompressed_headers)); 1631 EXPECT_EQ(2u, decompressed_headers.size()); 1632 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); 1633 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); 1634 1635 // Decompress SYN_STREAM #2 1636 decompressed.reset(SpdyFramerTestUtil::DecompressFrame( 1637 &recv_framer, *syn_frame_2.get())); 1638 EXPECT_TRUE(decompressed.get() != NULL); 1639 serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer); 1640 decompressed_headers.clear(); 1641 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(), 1642 serialized_headers.size(), 1643 &decompressed_headers)); 1644 EXPECT_EQ(3u, decompressed_headers.size()); 1645 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); 1646 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); 1647 EXPECT_EQ(kValue3, decompressed_headers[kHeader3]); 1648 } 1649 1650 // Verify we don't leak when we leave streams unclosed 1651 TEST_P(SpdyFramerTest, UnclosedStreamDataCompressors) { 1652 SpdyFramer send_framer(spdy_version_); 1653 1654 send_framer.set_enable_compression(true); 1655 1656 const char kHeader1[] = "header1"; 1657 const char kHeader2[] = "header2"; 1658 const char kValue1[] = "value1"; 1659 const char kValue2[] = "value2"; 1660 1661 SpdyHeaderBlock block; 1662 block[kHeader1] = kValue1; 1663 block[kHeader2] = kValue2; 1664 SpdyControlFlags flags(CONTROL_FLAG_NONE); 1665 scoped_ptr<SpdyFrame> syn_frame( 1666 send_framer.CreateSynStream(1, // stream id 1667 0, // associated stream id 1668 0, // priority 1669 0, // credential slot 1670 flags, 1671 true, // compress 1672 &block)); 1673 EXPECT_TRUE(syn_frame.get() != NULL); 1674 1675 const char bytes[] = "this is a test test test test test!"; 1676 scoped_ptr<SpdyFrame> send_frame( 1677 send_framer.CreateDataFrame( 1678 1, bytes, arraysize(bytes), 1679 static_cast<SpdyDataFlags>(DATA_FLAG_FIN))); 1680 EXPECT_TRUE(send_frame.get() != NULL); 1681 1682 // Run the inputs through the framer. 1683 TestSpdyVisitor visitor(spdy_version_); 1684 visitor.use_compression_ = true; 1685 const unsigned char* data; 1686 data = reinterpret_cast<const unsigned char*>(syn_frame->data()); 1687 visitor.SimulateInFramer(data, syn_frame->size()); 1688 data = reinterpret_cast<const unsigned char*>(send_frame->data()); 1689 visitor.SimulateInFramer(data, send_frame->size()); 1690 1691 EXPECT_EQ(0, visitor.error_count_); 1692 EXPECT_EQ(1, visitor.syn_frame_count_); 1693 EXPECT_EQ(0, visitor.syn_reply_frame_count_); 1694 EXPECT_EQ(0, visitor.headers_frame_count_); 1695 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); 1696 EXPECT_EQ(0, visitor.fin_frame_count_); 1697 EXPECT_EQ(0, visitor.fin_flag_count_); 1698 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); 1699 EXPECT_EQ(1, visitor.data_frame_count_); 1700 } 1701 1702 // Verify we can decompress the stream even if handed over to the 1703 // framer 1 byte at a time. 1704 TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) { 1705 SpdyFramer send_framer(spdy_version_); 1706 1707 send_framer.set_enable_compression(true); 1708 1709 const char kHeader1[] = "header1"; 1710 const char kHeader2[] = "header2"; 1711 const char kValue1[] = "value1"; 1712 const char kValue2[] = "value2"; 1713 1714 SpdyHeaderBlock block; 1715 block[kHeader1] = kValue1; 1716 block[kHeader2] = kValue2; 1717 SpdyControlFlags flags(CONTROL_FLAG_NONE); 1718 scoped_ptr<SpdyFrame> syn_frame( 1719 send_framer.CreateSynStream(1, // stream id 1720 0, // associated stream id 1721 0, // priority 1722 0, // credential slot 1723 flags, 1724 true, // compress 1725 &block)); 1726 EXPECT_TRUE(syn_frame.get() != NULL); 1727 1728 const char bytes[] = "this is a test test test test test!"; 1729 scoped_ptr<SpdyFrame> send_frame( 1730 send_framer.CreateDataFrame( 1731 1, bytes, arraysize(bytes), 1732 static_cast<SpdyDataFlags>(DATA_FLAG_FIN))); 1733 EXPECT_TRUE(send_frame.get() != NULL); 1734 1735 // Run the inputs through the framer. 1736 TestSpdyVisitor visitor(spdy_version_); 1737 visitor.use_compression_ = true; 1738 const unsigned char* data; 1739 data = reinterpret_cast<const unsigned char*>(syn_frame->data()); 1740 for (size_t idx = 0; idx < syn_frame->size(); ++idx) { 1741 visitor.SimulateInFramer(data + idx, 1); 1742 ASSERT_EQ(0, visitor.error_count_); 1743 } 1744 data = reinterpret_cast<const unsigned char*>(send_frame->data()); 1745 for (size_t idx = 0; idx < send_frame->size(); ++idx) { 1746 visitor.SimulateInFramer(data + idx, 1); 1747 ASSERT_EQ(0, visitor.error_count_); 1748 } 1749 1750 EXPECT_EQ(0, visitor.error_count_); 1751 EXPECT_EQ(1, visitor.syn_frame_count_); 1752 EXPECT_EQ(0, visitor.syn_reply_frame_count_); 1753 EXPECT_EQ(0, visitor.headers_frame_count_); 1754 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); 1755 EXPECT_EQ(0, visitor.fin_frame_count_); 1756 EXPECT_EQ(0, visitor.fin_flag_count_); 1757 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); 1758 EXPECT_EQ(1, visitor.data_frame_count_); 1759 } 1760 1761 TEST_P(SpdyFramerTest, WindowUpdateFrame) { 1762 SpdyFramer framer(spdy_version_); 1763 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x12345678)); 1764 1765 const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678"; 1766 const unsigned char kV3FrameData[] = { // Also applies for V2. 1767 0x80, spdy_version_ch_, 0x00, 0x09, 1768 0x00, 0x00, 0x00, 0x08, 1769 0x00, 0x00, 0x00, 0x01, 1770 0x12, 0x34, 0x56, 0x78 1771 }; 1772 const unsigned char kV4FrameData[] = { 1773 0x00, 0x0c, 0x09, 0x00, 1774 0x00, 0x00, 0x00, 0x01, 1775 0x12, 0x34, 0x56, 0x78 1776 }; 1777 1778 if (IsSpdy4()) { 1779 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 1780 } else { 1781 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 1782 } 1783 } 1784 1785 TEST_P(SpdyFramerTest, CreateDataFrame) { 1786 SpdyFramer framer(spdy_version_); 1787 1788 { 1789 const char kDescription[] = "'hello' data frame, no FIN"; 1790 const unsigned char kV3FrameData[] = { // Also applies for V2. 1791 0x00, 0x00, 0x00, 0x01, 1792 0x00, 0x00, 0x00, 0x05, 1793 'h', 'e', 'l', 'l', 1794 'o' 1795 }; 1796 const unsigned char kV4FrameData[] = { 1797 0x00, 0x0d, 0x00, 0x00, 1798 0x00, 0x00, 0x00, 0x01, 1799 'h', 'e', 'l', 'l', 1800 'o' 1801 }; 1802 const char bytes[] = "hello"; 1803 1804 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( 1805 1, bytes, strlen(bytes), DATA_FLAG_NONE)); 1806 if (IsSpdy4()) { 1807 CompareFrame( 1808 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 1809 } else { 1810 CompareFrame( 1811 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 1812 } 1813 1814 SpdyDataIR data_ir(1); 1815 data_ir.SetDataShallow(base::StringPiece(bytes, strlen(bytes))); 1816 frame.reset(framer.SerializeDataFrameHeader(data_ir)); 1817 CompareCharArraysWithHexError( 1818 kDescription, 1819 reinterpret_cast<const unsigned char*>(frame->data()), 1820 framer.GetDataFrameMinimumSize(), 1821 IsSpdy4() ? kV4FrameData : kV3FrameData, 1822 framer.GetDataFrameMinimumSize()); 1823 } 1824 1825 { 1826 const char kDescription[] = "Data frame with negative data byte, no FIN"; 1827 const unsigned char kV3FrameData[] = { // Also applies for V2. 1828 0x00, 0x00, 0x00, 0x01, 1829 0x00, 0x00, 0x00, 0x01, 1830 0xff 1831 }; 1832 const unsigned char kV4FrameData[] = { 1833 0x00, 0x09, 0x00, 0x00, 1834 0x00, 0x00, 0x00, 0x01, 1835 0xff 1836 }; 1837 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( 1838 1, "\xff", 1, DATA_FLAG_NONE)); 1839 if (IsSpdy4()) { 1840 CompareFrame( 1841 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 1842 } else { 1843 CompareFrame( 1844 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 1845 } 1846 } 1847 1848 { 1849 const char kDescription[] = "'hello' data frame, with FIN"; 1850 const unsigned char kV3FrameData[] = { // Also applies for V2. 1851 0x00, 0x00, 0x00, 0x01, 1852 0x01, 0x00, 0x00, 0x05, 1853 'h', 'e', 'l', 'l', 1854 'o' 1855 }; 1856 const unsigned char kV4FrameData[] = { 1857 0x00, 0x0d, 0x00, 0x01, 1858 0x00, 0x00, 0x00, 0x01, 1859 'h', 'e', 'l', 'l', 1860 'o' 1861 }; 1862 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( 1863 1, "hello", 5, DATA_FLAG_FIN)); 1864 if (IsSpdy4()) { 1865 CompareFrame( 1866 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 1867 } else { 1868 CompareFrame( 1869 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 1870 } 1871 } 1872 1873 { 1874 const char kDescription[] = "Empty data frame"; 1875 const unsigned char kV3FrameData[] = { // Also applies for V2. 1876 0x00, 0x00, 0x00, 0x01, 1877 0x00, 0x00, 0x00, 0x00, 1878 }; 1879 const unsigned char kV4FrameData[] = { 1880 0x00, 0x08, 0x00, 0x00, 1881 0x00, 0x00, 0x00, 0x01, 1882 }; 1883 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( 1884 1, "", 0, DATA_FLAG_NONE)); 1885 if (IsSpdy4()) { 1886 CompareFrame( 1887 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 1888 } else { 1889 CompareFrame( 1890 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 1891 } 1892 } 1893 1894 { 1895 const char kDescription[] = "Data frame with max stream ID"; 1896 const unsigned char kV3FrameData[] = { // Also applies for V2. 1897 0x7f, 0xff, 0xff, 0xff, 1898 0x01, 0x00, 0x00, 0x05, 1899 'h', 'e', 'l', 'l', 1900 'o' 1901 }; 1902 const unsigned char kV4FrameData[] = { 1903 0x00, 0x0d, 0x00, 0x01, 1904 0x7f, 0xff, 0xff, 0xff, 1905 'h', 'e', 'l', 'l', 1906 'o' 1907 }; 1908 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( 1909 0x7fffffff, "hello", 5, DATA_FLAG_FIN)); 1910 if (IsSpdy4()) { 1911 CompareFrame( 1912 kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 1913 } else { 1914 CompareFrame( 1915 kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 1916 } 1917 } 1918 1919 if (!IsSpdy4()) { 1920 // This test does not apply to SPDY 4 because the max frame size is smaller 1921 // than 4MB. 1922 const char kDescription[] = "Large data frame"; 1923 const int kDataSize = 4 * 1024 * 1024; // 4 MB 1924 const string kData(kDataSize, 'A'); 1925 const unsigned char kFrameHeader[] = { 1926 0x00, 0x00, 0x00, 0x01, 1927 0x01, 0x40, 0x00, 0x00, 1928 }; 1929 1930 const int kFrameSize = arraysize(kFrameHeader) + kDataSize; 1931 scoped_ptr<unsigned char[]> expected_frame_data( 1932 new unsigned char[kFrameSize]); 1933 memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader)); 1934 memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize); 1935 1936 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( 1937 1, kData.data(), kData.size(), DATA_FLAG_FIN)); 1938 CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize); 1939 } 1940 } 1941 1942 TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) { 1943 SpdyFramer framer(spdy_version_); 1944 framer.set_enable_compression(false); 1945 1946 { 1947 const char kDescription[] = "SYN_STREAM frame, lowest pri, slot 2, no FIN"; 1948 1949 SpdyHeaderBlock headers; 1950 headers["bar"] = "foo"; 1951 headers["foo"] = "bar"; 1952 1953 const unsigned char kPri = IsSpdy2() ? 0xC0 : 0xE0; 1954 const unsigned char kCre = IsSpdy2() ? 0 : 2; 1955 const unsigned char kV2FrameData[] = { 1956 0x80, spdy_version_ch_, 0x00, 0x01, 1957 0x00, 0x00, 0x00, 0x20, 1958 0x00, 0x00, 0x00, 0x01, 1959 0x00, 0x00, 0x00, 0x00, 1960 kPri, 0x00, 0x00, 0x02, 1961 0x00, 0x03, 'b', 'a', 1962 'r', 0x00, 0x03, 'f', 1963 'o', 'o', 0x00, 0x03, 1964 'f', 'o', 'o', 0x00, 1965 0x03, 'b', 'a', 'r' 1966 }; 1967 const unsigned char kV3FrameData[] = { 1968 0x80, spdy_version_ch_, 0x00, 0x01, 1969 0x00, 0x00, 0x00, 0x2a, 1970 0x00, 0x00, 0x00, 0x01, 1971 0x00, 0x00, 0x00, 0x00, 1972 kPri, kCre, 0x00, 0x00, 1973 0x00, 0x02, 0x00, 0x00, 1974 0x00, 0x03, 'b', 'a', 1975 'r', 0x00, 0x00, 0x00, 1976 0x03, 'f', 'o', 'o', 1977 0x00, 0x00, 0x00, 0x03, 1978 'f', 'o', 'o', 0x00, 1979 0x00, 0x00, 0x03, 'b', 1980 'a', 'r' 1981 }; 1982 const unsigned char kV4FrameData[] = { 1983 0x00, 0x2e, 0x01, 0x00, 1984 0x00, 0x00, 0x00, 0x01, 1985 0x00, 0x00, 0x00, 0x00, 1986 kPri, kCre, 0x00, 0x00, 1987 0x00, 0x02, 0x00, 0x00, 1988 0x00, 0x03, 'b', 'a', 1989 'r', 0x00, 0x00, 0x00, 1990 0x03, 'f', 'o', 'o', 1991 0x00, 0x00, 0x00, 0x03, 1992 'f', 'o', 'o', 0x00, 1993 0x00, 0x00, 0x03, 'b', 1994 'a', 'r' 1995 }; 1996 scoped_ptr<SpdyFrame> frame( 1997 framer.CreateSynStream(1, // stream id 1998 0, // associated stream id 1999 framer.GetLowestPriority(), 2000 kCre, // credential slot 2001 CONTROL_FLAG_NONE, 2002 false, // compress 2003 &headers)); 2004 if (IsSpdy2()) { 2005 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2006 } else if (IsSpdy3()) { 2007 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2008 } else { 2009 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2010 } 2011 } 2012 2013 { 2014 const char kDescription[] = 2015 "SYN_STREAM frame with a 0-length header name, highest pri, FIN, " 2016 "max stream ID"; 2017 2018 SpdyHeaderBlock headers; 2019 headers[std::string()] = "foo"; 2020 headers["foo"] = "bar"; 2021 2022 const unsigned char kV2FrameData[] = { 2023 0x80, spdy_version_ch_, 0x00, 0x01, 2024 0x01, 0x00, 0x00, 0x1D, 2025 0x7f, 0xff, 0xff, 0xff, 2026 0x7f, 0xff, 0xff, 0xff, 2027 0x00, 0x00, 0x00, 0x02, 2028 0x00, 0x00, 0x00, 0x03, 2029 'f', 'o', 'o', 0x00, 2030 0x03, 'f', 'o', 'o', 2031 0x00, 0x03, 'b', 'a', 2032 'r' 2033 }; 2034 const unsigned char kV3FrameData[] = { 2035 0x80, spdy_version_ch_, 0x00, 0x01, 2036 0x01, 0x00, 0x00, 0x27, 2037 0x7f, 0xff, 0xff, 0xff, 2038 0x7f, 0xff, 0xff, 0xff, 2039 0x00, 0x00, 0x00, 0x00, 2040 0x00, 0x02, 0x00, 0x00, 2041 0x00, 0x00, 0x00, 0x00, 2042 0x00, 0x03, 'f', 'o', 2043 'o', 0x00, 0x00, 0x00, 2044 0x03, 'f', 'o', 'o', 2045 0x00, 0x00, 0x00, 0x03, 2046 'b', 'a', 'r' 2047 }; 2048 const unsigned char kV4FrameData[] = { 2049 0x00, 0x2b, 0x01, 0x01, 2050 0x7f, 0xff, 0xff, 0xff, 2051 0x7f, 0xff, 0xff, 0xff, 2052 0x00, 0x00, 0x00, 0x00, 2053 0x00, 0x02, 0x00, 0x00, 2054 0x00, 0x00, 0x00, 0x00, 2055 0x00, 0x03, 'f', 'o', 2056 'o', 0x00, 0x00, 0x00, 2057 0x03, 'f', 'o', 'o', 2058 0x00, 0x00, 0x00, 0x03, 2059 'b', 'a', 'r' 2060 }; 2061 scoped_ptr<SpdyFrame> frame( 2062 framer.CreateSynStream(0x7fffffff, // stream id 2063 0x7fffffff, // associated stream id 2064 framer.GetHighestPriority(), 2065 0, // credential slot 2066 CONTROL_FLAG_FIN, 2067 false, // compress 2068 &headers)); 2069 if (IsSpdy2()) { 2070 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2071 } else if (IsSpdy3()) { 2072 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2073 } else { 2074 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2075 } 2076 } 2077 2078 { 2079 const char kDescription[] = 2080 "SYN_STREAM frame with a 0-length header val, high pri, FIN, " 2081 "max stream ID"; 2082 2083 SpdyHeaderBlock headers; 2084 headers["bar"] = "foo"; 2085 headers["foo"] = ""; 2086 2087 const unsigned char kPri = IsSpdy2() ? 0x40 : 0x20; 2088 const unsigned char kV2FrameData[] = { 2089 0x80, spdy_version_ch_, 0x00, 0x01, 2090 0x01, 0x00, 0x00, 0x1D, 2091 0x7f, 0xff, 0xff, 0xff, 2092 0x7f, 0xff, 0xff, 0xff, 2093 kPri, 0x00, 0x00, 0x02, 2094 0x00, 0x03, 'b', 'a', 2095 'r', 0x00, 0x03, 'f', 2096 'o', 'o', 0x00, 0x03, 2097 'f', 'o', 'o', 0x00, 2098 0x00 2099 }; 2100 const unsigned char kV3FrameData[] = { 2101 0x80, spdy_version_ch_, 0x00, 0x01, 2102 0x01, 0x00, 0x00, 0x27, 2103 0x7f, 0xff, 0xff, 0xff, 2104 0x7f, 0xff, 0xff, 0xff, 2105 kPri, 0x00, 0x00, 0x00, 2106 0x00, 0x02, 0x00, 0x00, 2107 0x00, 0x03, 'b', 'a', 2108 'r', 0x00, 0x00, 0x00, 2109 0x03, 'f', 'o', 'o', 2110 0x00, 0x00, 0x00, 0x03, 2111 'f', 'o', 'o', 0x00, 2112 0x00, 0x00, 0x00 2113 }; 2114 const unsigned char kV4FrameData[] = { 2115 0x00, 0x2b, 0x01, 0x01, 2116 0x7f, 0xff, 0xff, 0xff, 2117 0x7f, 0xff, 0xff, 0xff, 2118 kPri, 0x00, 0x00, 0x00, 2119 0x00, 0x02, 0x00, 0x00, 2120 0x00, 0x03, 'b', 'a', 2121 'r', 0x00, 0x00, 0x00, 2122 0x03, 'f', 'o', 'o', 2123 0x00, 0x00, 0x00, 0x03, 2124 'f', 'o', 'o', 0x00, 2125 0x00, 0x00, 0x00 2126 }; 2127 scoped_ptr<SpdyFrame> frame( 2128 framer.CreateSynStream(0x7fffffff, // stream id 2129 0x7fffffff, // associated stream id 2130 1, // priority 2131 0, // credential slot 2132 CONTROL_FLAG_FIN, 2133 false, // compress 2134 &headers)); 2135 if (IsSpdy2()) { 2136 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2137 } else if (IsSpdy3()) { 2138 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2139 } else { 2140 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2141 } 2142 } 2143 } 2144 2145 // TODO(phajdan.jr): Clean up after we no longer need 2146 // to workaround http://crbug.com/139744. 2147 #if !defined(USE_SYSTEM_ZLIB) 2148 TEST_P(SpdyFramerTest, CreateSynStreamCompressed) { 2149 SpdyFramer framer(spdy_version_); 2150 framer.set_enable_compression(true); 2151 2152 { 2153 const char kDescription[] = 2154 "SYN_STREAM frame, low pri, no FIN"; 2155 2156 SpdyHeaderBlock headers; 2157 headers["bar"] = "foo"; 2158 headers["foo"] = "bar"; 2159 2160 const SpdyPriority priority = IsSpdy2() ? 2 : 4; 2161 const unsigned char kV2FrameData[] = { 2162 0x80, spdy_version_ch_, 0x00, 0x01, 2163 0x00, 0x00, 0x00, 0x36, 2164 0x00, 0x00, 0x00, 0x01, 2165 0x00, 0x00, 0x00, 0x00, 2166 0x80, 0x00, 0x38, 0xea, 2167 0xdf, 0xa2, 0x51, 0xb2, 2168 0x62, 0x60, 0x62, 0x60, 2169 0x4e, 0x4a, 0x2c, 0x62, 2170 0x60, 0x06, 0x08, 0xa0, 2171 0xb4, 0xfc, 0x7c, 0x80, 2172 0x00, 0x62, 0x60, 0x4e, 2173 0xcb, 0xcf, 0x67, 0x60, 2174 0x06, 0x08, 0xa0, 0xa4, 2175 0xc4, 0x22, 0x80, 0x00, 2176 0x02, 0x00, 0x00, 0x00, 2177 0xff, 0xff, 2178 }; 2179 const unsigned char kV3FrameData[] = { 2180 0x80, spdy_version_ch_, 0x00, 0x01, 2181 0x00, 0x00, 0x00, 0x37, 2182 0x00, 0x00, 0x00, 0x01, 2183 0x00, 0x00, 0x00, 0x00, 2184 0x80, 0x00, 0x38, 0xEA, 2185 0xE3, 0xC6, 0xA7, 0xC2, 2186 0x02, 0xE5, 0x0E, 0x50, 2187 0xC2, 0x4B, 0x4A, 0x04, 2188 0xE5, 0x0B, 0x66, 0x80, 2189 0x00, 0x4A, 0xCB, 0xCF, 2190 0x07, 0x08, 0x20, 0x10, 2191 0x95, 0x96, 0x9F, 0x0F, 2192 0xA2, 0x00, 0x02, 0x28, 2193 0x29, 0xB1, 0x08, 0x20, 2194 0x80, 0x00, 0x00, 0x00, 2195 0x00, 0xFF, 0xFF, 2196 }; 2197 const unsigned char kV4FrameData[] = { 2198 0x00, 0x3b, 0x01, 0x00, 2199 0x00, 0x00, 0x00, 0x01, 2200 0x00, 0x00, 0x00, 0x00, 2201 0x80, 0x00, 0x38, 0xea, 2202 0xe3, 0xc6, 0xa7, 0xc2, 2203 0x02, 0xe5, 0x0e, 0x50, 2204 0xc2, 0x4b, 0x4a, 0x04, 2205 0xe5, 0x0b, 0x66, 0x80, 2206 0x00, 0x4a, 0xcb, 0xcf, 2207 0x07, 0x08, 0x20, 0x10, 2208 0x95, 0x96, 0x9f, 0x0f, 2209 0xa2, 0x00, 0x02, 0x28, 2210 0x29, 0xb1, 0x08, 0x20, 2211 0x80, 0x00, 0x00, 0x00, 2212 0x00, 0xff, 0xff, 2213 }; 2214 scoped_ptr<SpdyFrame> frame( 2215 framer.CreateSynStream(1, // stream id 2216 0, // associated stream id 2217 priority, 2218 0, // credential slot 2219 CONTROL_FLAG_NONE, 2220 true, // compress 2221 &headers)); 2222 if (IsSpdy2()) { 2223 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2224 } else if (IsSpdy3()) { 2225 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2226 } else { 2227 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2228 } 2229 } 2230 } 2231 #endif // !defined(USE_SYSTEM_ZLIB) 2232 2233 TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) { 2234 SpdyFramer framer(spdy_version_); 2235 framer.set_enable_compression(false); 2236 2237 { 2238 const char kDescription[] = "SYN_REPLY frame, no FIN"; 2239 2240 SpdyHeaderBlock headers; 2241 headers["bar"] = "foo"; 2242 headers["foo"] = "bar"; 2243 2244 const unsigned char kV2FrameData[] = { 2245 0x80, spdy_version_ch_, 0x00, 0x02, 2246 0x00, 0x00, 0x00, 0x1C, 2247 0x00, 0x00, 0x00, 0x01, 2248 0x00, 0x00, 0x00, 0x02, 2249 0x00, 0x03, 'b', 'a', 2250 'r', 0x00, 0x03, 'f', 2251 'o', 'o', 0x00, 0x03, 2252 'f', 'o', 'o', 0x00, 2253 0x03, 'b', 'a', 'r' 2254 }; 2255 const unsigned char kV3FrameData[] = { 2256 0x80, spdy_version_ch_, 0x00, 0x02, 2257 0x00, 0x00, 0x00, 0x24, 2258 0x00, 0x00, 0x00, 0x01, 2259 0x00, 0x00, 0x00, 0x02, 2260 0x00, 0x00, 0x00, 0x03, 2261 'b', 'a', 'r', 0x00, 2262 0x00, 0x00, 0x03, 'f', 2263 'o', 'o', 0x00, 0x00, 2264 0x00, 0x03, 'f', 'o', 2265 'o', 0x00, 0x00, 0x00, 2266 0x03, 'b', 'a', 'r' 2267 }; 2268 const unsigned char kV4FrameData[] = { 2269 0x00, 0x28, 0x02, 0x00, 2270 0x00, 0x00, 0x00, 0x01, 2271 0x00, 0x00, 0x00, 0x02, 2272 0x00, 0x00, 0x00, 0x03, 2273 'b', 'a', 'r', 0x00, 2274 0x00, 0x00, 0x03, 'f', 2275 'o', 'o', 0x00, 0x00, 2276 0x00, 0x03, 'f', 'o', 2277 'o', 0x00, 0x00, 0x00, 2278 0x03, 'b', 'a', 'r' 2279 }; 2280 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( 2281 1, CONTROL_FLAG_NONE, false, &headers)); 2282 if (IsSpdy2()) { 2283 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2284 } else if (IsSpdy3()) { 2285 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2286 } else { 2287 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2288 } 2289 } 2290 2291 { 2292 const char kDescription[] = 2293 "SYN_REPLY frame with a 0-length header name, FIN, max stream ID"; 2294 2295 SpdyHeaderBlock headers; 2296 headers[std::string()] = "foo"; 2297 headers["foo"] = "bar"; 2298 2299 const unsigned char kV2FrameData[] = { 2300 0x80, spdy_version_ch_, 0x00, 0x02, 2301 0x01, 0x00, 0x00, 0x19, 2302 0x7f, 0xff, 0xff, 0xff, 2303 0x00, 0x00, 0x00, 0x02, 2304 0x00, 0x00, 0x00, 0x03, 2305 'f', 'o', 'o', 0x00, 2306 0x03, 'f', 'o', 'o', 2307 0x00, 0x03, 'b', 'a', 2308 'r' 2309 }; 2310 const unsigned char kV3FrameData[] = { 2311 0x80, spdy_version_ch_, 0x00, 0x02, 2312 0x01, 0x00, 0x00, 0x21, 2313 0x7f, 0xff, 0xff, 0xff, 2314 0x00, 0x00, 0x00, 0x02, 2315 0x00, 0x00, 0x00, 0x00, 2316 0x00, 0x00, 0x00, 0x03, 2317 'f', 'o', 'o', 0x00, 2318 0x00, 0x00, 0x03, 'f', 2319 'o', 'o', 0x00, 0x00, 2320 0x00, 0x03, 'b', 'a', 2321 'r' 2322 }; 2323 const unsigned char kV4FrameData[] = { 2324 0x00, 0x25, 0x02, 0x01, 2325 0x7f, 0xff, 0xff, 0xff, 2326 0x00, 0x00, 0x00, 0x02, 2327 0x00, 0x00, 0x00, 0x00, 2328 0x00, 0x00, 0x00, 0x03, 2329 'f', 'o', 'o', 0x00, 2330 0x00, 0x00, 0x03, 'f', 2331 'o', 'o', 0x00, 0x00, 2332 0x00, 0x03, 'b', 'a', 2333 'r' 2334 }; 2335 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( 2336 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); 2337 if (IsSpdy2()) { 2338 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2339 } else if (IsSpdy3()) { 2340 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2341 } else { 2342 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2343 } 2344 } 2345 2346 { 2347 const char kDescription[] = 2348 "SYN_REPLY frame with a 0-length header val, FIN, max stream ID"; 2349 2350 SpdyHeaderBlock headers; 2351 headers["bar"] = "foo"; 2352 headers["foo"] = ""; 2353 2354 const unsigned char kV2FrameData[] = { 2355 0x80, spdy_version_ch_, 0x00, 0x02, 2356 0x01, 0x00, 0x00, 0x19, 2357 0x7f, 0xff, 0xff, 0xff, 2358 0x00, 0x00, 0x00, 0x02, 2359 0x00, 0x03, 'b', 'a', 2360 'r', 0x00, 0x03, 'f', 2361 'o', 'o', 0x00, 0x03, 2362 'f', 'o', 'o', 0x00, 2363 0x00 2364 }; 2365 const unsigned char kV3FrameData[] = { 2366 0x80, spdy_version_ch_, 0x00, 0x02, 2367 0x01, 0x00, 0x00, 0x21, 2368 0x7f, 0xff, 0xff, 0xff, 2369 0x00, 0x00, 0x00, 0x02, 2370 0x00, 0x00, 0x00, 0x03, 2371 'b', 'a', 'r', 0x00, 2372 0x00, 0x00, 0x03, 'f', 2373 'o', 'o', 0x00, 0x00, 2374 0x00, 0x03, 'f', 'o', 2375 'o', 0x00, 0x00, 0x00, 2376 0x00 2377 }; 2378 const unsigned char kV4FrameData[] = { 2379 0x00, 0x25, 0x02, 0x01, 2380 0x7f, 0xff, 0xff, 0xff, 2381 0x00, 0x00, 0x00, 0x02, 2382 0x00, 0x00, 0x00, 0x03, 2383 'b', 'a', 'r', 0x00, 2384 0x00, 0x00, 0x03, 'f', 2385 'o', 'o', 0x00, 0x00, 2386 0x00, 0x03, 'f', 'o', 2387 'o', 0x00, 0x00, 0x00, 2388 0x00 2389 }; 2390 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( 2391 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); 2392 if (IsSpdy2()) { 2393 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2394 } else if (IsSpdy3()) { 2395 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2396 } else { 2397 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2398 } 2399 } 2400 } 2401 2402 // TODO(phajdan.jr): Clean up after we no longer need 2403 // to workaround http://crbug.com/139744. 2404 #if !defined(USE_SYSTEM_ZLIB) 2405 TEST_P(SpdyFramerTest, CreateSynReplyCompressed) { 2406 SpdyFramer framer(spdy_version_); 2407 framer.set_enable_compression(true); 2408 2409 { 2410 const char kDescription[] = "SYN_REPLY frame, no FIN"; 2411 2412 SpdyHeaderBlock headers; 2413 headers["bar"] = "foo"; 2414 headers["foo"] = "bar"; 2415 2416 const unsigned char kV2FrameData[] = { 2417 0x80, spdy_version_ch_, 0x00, 0x02, 2418 0x00, 0x00, 0x00, 0x32, 2419 0x00, 0x00, 0x00, 0x01, 2420 0x00, 0x00, 0x38, 0xea, 2421 0xdf, 0xa2, 0x51, 0xb2, 2422 0x62, 0x60, 0x62, 0x60, 2423 0x4e, 0x4a, 0x2c, 0x62, 2424 0x60, 0x06, 0x08, 0xa0, 2425 0xb4, 0xfc, 0x7c, 0x80, 2426 0x00, 0x62, 0x60, 0x4e, 2427 0xcb, 0xcf, 0x67, 0x60, 2428 0x06, 0x08, 0xa0, 0xa4, 2429 0xc4, 0x22, 0x80, 0x00, 2430 0x02, 0x00, 0x00, 0x00, 2431 0xff, 0xff, 2432 }; 2433 const unsigned char kV3FrameData[] = { 2434 0x80, spdy_version_ch_, 0x00, 0x02, 2435 0x00, 0x00, 0x00, 0x31, 2436 0x00, 0x00, 0x00, 0x01, 2437 0x38, 0xea, 0xe3, 0xc6, 2438 0xa7, 0xc2, 0x02, 0xe5, 2439 0x0e, 0x50, 0xc2, 0x4b, 2440 0x4a, 0x04, 0xe5, 0x0b, 2441 0x66, 0x80, 0x00, 0x4a, 2442 0xcb, 0xcf, 0x07, 0x08, 2443 0x20, 0x10, 0x95, 0x96, 2444 0x9f, 0x0f, 0xa2, 0x00, 2445 0x02, 0x28, 0x29, 0xb1, 2446 0x08, 0x20, 0x80, 0x00, 2447 0x00, 0x00, 0x00, 0xff, 2448 0xff, 2449 }; 2450 const unsigned char kV4FrameData[] = { 2451 0x00, 0x35, 0x02, 0x00, 2452 0x00, 0x00, 0x00, 0x01, 2453 0x38, 0xea, 0xe3, 0xc6, 2454 0xa7, 0xc2, 0x02, 0xe5, 2455 0x0e, 0x50, 0xc2, 0x4b, 2456 0x4a, 0x04, 0xe5, 0x0b, 2457 0x66, 0x80, 0x00, 0x4a, 2458 0xcb, 0xcf, 0x07, 0x08, 2459 0x20, 0x10, 0x95, 0x96, 2460 0x9f, 0x0f, 0xa2, 0x00, 2461 0x02, 0x28, 0x29, 0xb1, 2462 0x08, 0x20, 0x80, 0x00, 2463 0x00, 0x00, 0x00, 0xff, 2464 0xff, 2465 }; 2466 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( 2467 1, CONTROL_FLAG_NONE, true, &headers)); 2468 if (IsSpdy2()) { 2469 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2470 } else if (IsSpdy3()) { 2471 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2472 } else { 2473 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2474 } 2475 } 2476 } 2477 #endif // !defined(USE_SYSTEM_ZLIB) 2478 2479 TEST_P(SpdyFramerTest, CreateRstStream) { 2480 SpdyFramer framer(spdy_version_); 2481 2482 { 2483 const char kDescription[] = "RST_STREAM frame"; 2484 const unsigned char kV3FrameData[] = { // Also applies for V2. 2485 0x80, spdy_version_ch_, 0x00, 0x03, 2486 0x00, 0x00, 0x00, 0x08, 2487 0x00, 0x00, 0x00, 0x01, 2488 0x00, 0x00, 0x00, 0x01, 2489 }; 2490 const unsigned char kV4FrameData[] = { 2491 0x00, 0x0c, 0x03, 0x00, 2492 0x00, 0x00, 0x00, 0x01, 2493 0x00, 0x00, 0x00, 0x01, 2494 }; 2495 scoped_ptr<SpdyFrame> frame( 2496 framer.CreateRstStream(1, RST_STREAM_PROTOCOL_ERROR)); 2497 if (IsSpdy4()) { 2498 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2499 } else { 2500 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2501 } 2502 } 2503 2504 { 2505 const char kDescription[] = "RST_STREAM frame with max stream ID"; 2506 const unsigned char kV3FrameData[] = { // Also applies for V2. 2507 0x80, spdy_version_ch_, 0x00, 0x03, 2508 0x00, 0x00, 0x00, 0x08, 2509 0x7f, 0xff, 0xff, 0xff, 2510 0x00, 0x00, 0x00, 0x01, 2511 }; 2512 const unsigned char kV4FrameData[] = { 2513 0x00, 0x0c, 0x03, 0x00, 2514 0x7f, 0xff, 0xff, 0xff, 2515 0x00, 0x00, 0x00, 0x01, 2516 }; 2517 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream( 2518 0x7FFFFFFF, RST_STREAM_PROTOCOL_ERROR)); 2519 if (IsSpdy4()) { 2520 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2521 } else { 2522 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2523 } 2524 } 2525 2526 { 2527 const char kDescription[] = "RST_STREAM frame with max status code"; 2528 const unsigned char kV3FrameData[] = { // Also applies for V2. 2529 0x80, spdy_version_ch_, 0x00, 0x03, 2530 0x00, 0x00, 0x00, 0x08, 2531 0x7f, 0xff, 0xff, 0xff, 2532 0x00, 0x00, 0x00, 0x06, 2533 }; 2534 const unsigned char kV4FrameData[] = { 2535 0x00, 0x0c, 0x03, 0x00, 2536 0x7f, 0xff, 0xff, 0xff, 2537 0x00, 0x00, 0x00, 0x06, 2538 }; 2539 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream( 2540 0x7FFFFFFF, RST_STREAM_INTERNAL_ERROR)); 2541 if (IsSpdy4()) { 2542 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2543 } else { 2544 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2545 } 2546 } 2547 } 2548 2549 TEST_P(SpdyFramerTest, CreateSettings) { 2550 SpdyFramer framer(spdy_version_); 2551 2552 { 2553 const char kDescription[] = "Network byte order SETTINGS frame"; 2554 2555 uint32 kValue = 0x0a0b0c0d; 2556 SpdySettingsFlags kFlags = static_cast<SpdySettingsFlags>(0x01); 2557 SpdySettingsIds kId = static_cast<SpdySettingsIds>(0x020304); 2558 2559 SettingsMap settings; 2560 settings[kId] = SettingsFlagsAndValue(kFlags, kValue); 2561 2562 EXPECT_EQ(kFlags, settings[kId].first); 2563 EXPECT_EQ(kValue, settings[kId].second); 2564 2565 const unsigned char kV2FrameData[] = { 2566 0x80, spdy_version_ch_, 0x00, 0x04, 2567 0x00, 0x00, 0x00, 0x0c, 2568 0x00, 0x00, 0x00, 0x01, 2569 0x04, 0x03, 0x02, 0x01, 2570 0x0a, 0x0b, 0x0c, 0x0d, 2571 }; 2572 const unsigned char kV3FrameData[] = { 2573 0x80, spdy_version_ch_, 0x00, 0x04, 2574 0x00, 0x00, 0x00, 0x0c, 2575 0x00, 0x00, 0x00, 0x01, 2576 0x01, 0x02, 0x03, 0x04, 2577 0x0a, 0x0b, 0x0c, 0x0d, 2578 }; 2579 const unsigned char kV4FrameData[] = { 2580 0x00, 0x14, 0x04, 0x00, 2581 0x00, 0x00, 0x00, 0x00, 2582 0x00, 0x00, 0x00, 0x01, 2583 0x01, 0x02, 0x03, 0x04, 2584 0x0a, 0x0b, 0x0c, 0x0d, 2585 }; 2586 2587 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); 2588 if (IsSpdy2()) { 2589 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2590 } else if (IsSpdy3()) { 2591 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2592 } else { 2593 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2594 } 2595 } 2596 2597 { 2598 const char kDescription[] = "Basic SETTINGS frame"; 2599 2600 SettingsMap settings; 2601 AddSpdySettingFromWireFormat( 2602 &settings, 0x00000000, 0x00000001); // 1st Setting 2603 AddSpdySettingFromWireFormat( 2604 &settings, 0x01000001, 0x00000002); // 2nd Setting 2605 AddSpdySettingFromWireFormat( 2606 &settings, 0x02000002, 0x00000003); // 3rd Setting 2607 AddSpdySettingFromWireFormat( 2608 &settings, 0x03000003, 0xff000004); // 4th Setting 2609 2610 const unsigned char kV3FrameData[] = { // Also applies for V2. 2611 0x80, spdy_version_ch_, 0x00, 0x04, 2612 0x00, 0x00, 0x00, 0x24, 2613 0x00, 0x00, 0x00, 0x04, 2614 0x00, 0x00, 0x00, 0x00, // 1st Setting 2615 0x00, 0x00, 0x00, 0x01, 2616 0x01, 0x00, 0x00, 0x01, // 2nd Setting 2617 0x00, 0x00, 0x00, 0x02, 2618 0x02, 0x00, 0x00, 0x02, // 3rd Setting 2619 0x00, 0x00, 0x00, 0x03, 2620 0x03, 0x00, 0x00, 0x03, // 4th Setting 2621 0xff, 0x00, 0x00, 0x04, 2622 }; 2623 const unsigned char kV4FrameData[] = { 2624 0x00, 0x2c, 0x04, 0x00, 2625 0x00, 0x00, 0x00, 0x00, 2626 0x00, 0x00, 0x00, 0x04, 2627 0x00, 0x00, 0x00, 0x00, // 1st Setting 2628 0x00, 0x00, 0x00, 0x01, 2629 0x01, 0x00, 0x00, 0x01, // 2nd Setting 2630 0x00, 0x00, 0x00, 0x02, 2631 0x02, 0x00, 0x00, 0x02, // 3rd Setting 2632 0x00, 0x00, 0x00, 0x03, 2633 0x03, 0x00, 0x00, 0x03, // 4th Setting 2634 0xff, 0x00, 0x00, 0x04, 2635 }; 2636 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); 2637 if (IsSpdy4()) { 2638 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2639 } else { 2640 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2641 } 2642 } 2643 2644 { 2645 const char kDescription[] = "Empty SETTINGS frame"; 2646 2647 SettingsMap settings; 2648 2649 const unsigned char kV3FrameData[] = { // Also applies for V2. 2650 0x80, spdy_version_ch_, 0x00, 0x04, 2651 0x00, 0x00, 0x00, 0x04, 2652 0x00, 0x00, 0x00, 0x00, 2653 }; 2654 const unsigned char kV4FrameData[] = { 2655 0x00, 0x0c, 0x04, 0x00, 2656 0x00, 0x00, 0x00, 0x00, 2657 0x00, 0x00, 0x00, 0x00, 2658 }; 2659 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); 2660 if (IsSpdy4()) { 2661 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2662 } else { 2663 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2664 } 2665 } 2666 } 2667 2668 TEST_P(SpdyFramerTest, CreatePingFrame) { 2669 SpdyFramer framer(spdy_version_); 2670 2671 { 2672 const char kDescription[] = "PING frame"; 2673 const unsigned char kV3FrameData[] = { // Also applies for V2. 2674 0x80, spdy_version_ch_, 0x00, 0x06, 2675 0x00, 0x00, 0x00, 0x04, 2676 0x12, 0x34, 0x56, 0x78, 2677 }; 2678 const unsigned char kV4FrameData[] = { 2679 0x00, 0x0c, 0x06, 0x00, 2680 0x00, 0x00, 0x00, 0x00, 2681 0x12, 0x34, 0x56, 0x78, 2682 }; 2683 scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(0x12345678u)); 2684 if (IsSpdy4()) { 2685 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2686 } else { 2687 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2688 } 2689 } 2690 } 2691 2692 TEST_P(SpdyFramerTest, CreateGoAway) { 2693 SpdyFramer framer(spdy_version_); 2694 2695 { 2696 const char kDescription[] = "GOAWAY frame"; 2697 const unsigned char kV2FrameData[] = { 2698 0x80, spdy_version_ch_, 0x00, 0x07, 2699 0x00, 0x00, 0x00, 0x04, 2700 0x00, 0x00, 0x00, 0x00, 2701 }; 2702 const unsigned char kV3FrameData[] = { 2703 0x80, spdy_version_ch_, 0x00, 0x07, 2704 0x00, 0x00, 0x00, 0x08, 2705 0x00, 0x00, 0x00, 0x00, 2706 0x00, 0x00, 0x00, 0x00, 2707 }; 2708 const unsigned char kV4FrameData[] = { 2709 0x00, 0x10, 0x07, 0x00, 2710 0x00, 0x00, 0x00, 0x00, 2711 0x00, 0x00, 0x00, 0x00, 2712 0x00, 0x00, 0x00, 0x00, 2713 }; 2714 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0, GOAWAY_OK)); 2715 if (IsSpdy2()) { 2716 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2717 } else if (IsSpdy3()) { 2718 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2719 } else { 2720 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2721 } 2722 } 2723 2724 { 2725 const char kDescription[] = "GOAWAY frame with max stream ID, status"; 2726 const unsigned char kV2FrameData[] = { 2727 0x80, spdy_version_ch_, 0x00, 0x07, 2728 0x00, 0x00, 0x00, 0x04, 2729 0x7f, 0xff, 0xff, 0xff, 2730 }; 2731 const unsigned char kV3FrameData[] = { 2732 0x80, spdy_version_ch_, 0x00, 0x07, 2733 0x00, 0x00, 0x00, 0x08, 2734 0x7f, 0xff, 0xff, 0xff, 2735 0x00, 0x00, 0x00, 0x02, 2736 }; 2737 const unsigned char kV4FrameData[] = { 2738 0x00, 0x10, 0x07, 0x00, 2739 0x00, 0x00, 0x00, 0x00, 2740 0x7f, 0xff, 0xff, 0xff, 2741 0x00, 0x00, 0x00, 0x02, 2742 }; 2743 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF, 2744 GOAWAY_INTERNAL_ERROR)); 2745 if (IsSpdy2()) { 2746 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2747 } else if (IsSpdy3()) { 2748 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2749 } else { 2750 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2751 } 2752 } 2753 } 2754 2755 TEST_P(SpdyFramerTest, CreateHeadersUncompressed) { 2756 SpdyFramer framer(spdy_version_); 2757 framer.set_enable_compression(false); 2758 2759 { 2760 const char kDescription[] = "HEADERS frame, no FIN"; 2761 2762 SpdyHeaderBlock headers; 2763 headers["bar"] = "foo"; 2764 headers["foo"] = "bar"; 2765 2766 const unsigned char kV2FrameData[] = { 2767 0x80, spdy_version_ch_, 0x00, 0x08, 2768 0x00, 0x00, 0x00, 0x1C, 2769 0x00, 0x00, 0x00, 0x01, 2770 0x00, 0x00, 0x00, 0x02, 2771 0x00, 0x03, 'b', 'a', 2772 'r', 0x00, 0x03, 'f', 2773 'o', 'o', 0x00, 0x03, 2774 'f', 'o', 'o', 0x00, 2775 0x03, 'b', 'a', 'r' 2776 }; 2777 const unsigned char kV3FrameData[] = { 2778 0x80, spdy_version_ch_, 0x00, 0x08, 2779 0x00, 0x00, 0x00, 0x24, 2780 0x00, 0x00, 0x00, 0x01, 2781 0x00, 0x00, 0x00, 0x02, 2782 0x00, 0x00, 0x00, 0x03, 2783 'b', 'a', 'r', 0x00, 2784 0x00, 0x00, 0x03, 'f', 2785 'o', 'o', 0x00, 0x00, 2786 0x00, 0x03, 'f', 'o', 2787 'o', 0x00, 0x00, 0x00, 2788 0x03, 'b', 'a', 'r' 2789 }; 2790 const unsigned char kV4FrameData[] = { 2791 0x00, 0x28, 0x08, 0x00, 2792 0x00, 0x00, 0x00, 0x01, 2793 0x00, 0x00, 0x00, 0x02, 2794 0x00, 0x00, 0x00, 0x03, 2795 'b', 'a', 'r', 0x00, 2796 0x00, 0x00, 0x03, 'f', 2797 'o', 'o', 0x00, 0x00, 2798 0x00, 0x03, 'f', 'o', 2799 'o', 0x00, 0x00, 0x00, 2800 0x03, 'b', 'a', 'r' 2801 }; 2802 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( 2803 1, CONTROL_FLAG_NONE, false, &headers)); 2804 if (IsSpdy2()) { 2805 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2806 } else if (IsSpdy3()) { 2807 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2808 } else { 2809 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2810 } 2811 } 2812 2813 { 2814 const char kDescription[] = 2815 "HEADERS frame with a 0-length header name, FIN, max stream ID"; 2816 2817 SpdyHeaderBlock headers; 2818 headers[std::string()] = "foo"; 2819 headers["foo"] = "bar"; 2820 2821 const unsigned char kV2FrameData[] = { 2822 0x80, spdy_version_ch_, 0x00, 0x08, 2823 0x01, 0x00, 0x00, 0x19, 2824 0x7f, 0xff, 0xff, 0xff, 2825 0x00, 0x00, 0x00, 0x02, 2826 0x00, 0x00, 0x00, 0x03, 2827 'f', 'o', 'o', 0x00, 2828 0x03, 'f', 'o', 'o', 2829 0x00, 0x03, 'b', 'a', 2830 'r' 2831 }; 2832 const unsigned char kV3FrameData[] = { 2833 0x80, spdy_version_ch_, 0x00, 0x08, 2834 0x01, 0x00, 0x00, 0x21, 2835 0x7f, 0xff, 0xff, 0xff, 2836 0x00, 0x00, 0x00, 0x02, 2837 0x00, 0x00, 0x00, 0x00, 2838 0x00, 0x00, 0x00, 0x03, 2839 'f', 'o', 'o', 0x00, 2840 0x00, 0x00, 0x03, 'f', 2841 'o', 'o', 0x00, 0x00, 2842 0x00, 0x03, 'b', 'a', 2843 'r' 2844 }; 2845 const unsigned char kV4FrameData[] = { 2846 0x00, 0x25, 0x08, 0x01, 2847 0x7f, 0xff, 0xff, 0xff, 2848 0x00, 0x00, 0x00, 0x02, 2849 0x00, 0x00, 0x00, 0x00, 2850 0x00, 0x00, 0x00, 0x03, 2851 'f', 'o', 'o', 0x00, 2852 0x00, 0x00, 0x03, 'f', 2853 'o', 'o', 0x00, 0x00, 2854 0x00, 0x03, 'b', 'a', 2855 'r' 2856 }; 2857 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( 2858 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); 2859 if (IsSpdy2()) { 2860 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2861 } else if (IsSpdy3()) { 2862 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2863 } else { 2864 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2865 } 2866 } 2867 2868 { 2869 const char kDescription[] = 2870 "HEADERS frame with a 0-length header val, FIN, max stream ID"; 2871 2872 SpdyHeaderBlock headers; 2873 headers["bar"] = "foo"; 2874 headers["foo"] = ""; 2875 2876 const unsigned char kV2FrameData[] = { 2877 0x80, spdy_version_ch_, 0x00, 0x08, 2878 0x01, 0x00, 0x00, 0x19, 2879 0x7f, 0xff, 0xff, 0xff, 2880 0x00, 0x00, 0x00, 0x02, 2881 0x00, 0x03, 'b', 'a', 2882 'r', 0x00, 0x03, 'f', 2883 'o', 'o', 0x00, 0x03, 2884 'f', 'o', 'o', 0x00, 2885 0x00 2886 }; 2887 const unsigned char kV3FrameData[] = { 2888 0x80, spdy_version_ch_, 0x00, 0x08, 2889 0x01, 0x00, 0x00, 0x21, 2890 0x7f, 0xff, 0xff, 0xff, 2891 0x00, 0x00, 0x00, 0x02, 2892 0x00, 0x00, 0x00, 0x03, 2893 'b', 'a', 'r', 0x00, 2894 0x00, 0x00, 0x03, 'f', 2895 'o', 'o', 0x00, 0x00, 2896 0x00, 0x03, 'f', 'o', 2897 'o', 0x00, 0x00, 0x00, 2898 0x00 2899 }; 2900 const unsigned char kV4FrameData[] = { 2901 0x00, 0x25, 0x08, 0x01, 2902 0x7f, 0xff, 0xff, 0xff, 2903 0x00, 0x00, 0x00, 0x02, 2904 0x00, 0x00, 0x00, 0x03, 2905 'b', 'a', 'r', 0x00, 2906 0x00, 0x00, 0x03, 'f', 2907 'o', 'o', 0x00, 0x00, 2908 0x00, 0x03, 'f', 'o', 2909 'o', 0x00, 0x00, 0x00, 2910 0x00 2911 }; 2912 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( 2913 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); 2914 if (IsSpdy2()) { 2915 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2916 } else if (IsSpdy3()) { 2917 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2918 } else { 2919 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2920 } 2921 } 2922 } 2923 2924 // TODO(phajdan.jr): Clean up after we no longer need 2925 // to workaround http://crbug.com/139744. 2926 #if !defined(USE_SYSTEM_ZLIB) 2927 TEST_P(SpdyFramerTest, CreateHeadersCompressed) { 2928 SpdyFramer framer(spdy_version_); 2929 framer.set_enable_compression(true); 2930 2931 { 2932 const char kDescription[] = "HEADERS frame, no FIN"; 2933 2934 SpdyHeaderBlock headers; 2935 headers["bar"] = "foo"; 2936 headers["foo"] = "bar"; 2937 2938 const unsigned char kV2FrameData[] = { 2939 0x80, spdy_version_ch_, 0x00, 0x08, 2940 0x00, 0x00, 0x00, 0x32, 2941 0x00, 0x00, 0x00, 0x01, 2942 0x00, 0x00, 0x38, 0xea, 2943 0xdf, 0xa2, 0x51, 0xb2, 2944 0x62, 0x60, 0x62, 0x60, 2945 0x4e, 0x4a, 0x2c, 0x62, 2946 0x60, 0x06, 0x08, 0xa0, 2947 0xb4, 0xfc, 0x7c, 0x80, 2948 0x00, 0x62, 0x60, 0x4e, 2949 0xcb, 0xcf, 0x67, 0x60, 2950 0x06, 0x08, 0xa0, 0xa4, 2951 0xc4, 0x22, 0x80, 0x00, 2952 0x02, 0x00, 0x00, 0x00, 2953 0xff, 0xff, 2954 }; 2955 const unsigned char kV3FrameData[] = { 2956 0x80, spdy_version_ch_, 0x00, 0x08, 2957 0x00, 0x00, 0x00, 0x31, 2958 0x00, 0x00, 0x00, 0x01, 2959 0x38, 0xea, 0xe3, 0xc6, 2960 0xa7, 0xc2, 0x02, 0xe5, 2961 0x0e, 0x50, 0xc2, 0x4b, 2962 0x4a, 0x04, 0xe5, 0x0b, 2963 0x66, 0x80, 0x00, 0x4a, 2964 0xcb, 0xcf, 0x07, 0x08, 2965 0x20, 0x10, 0x95, 0x96, 2966 0x9f, 0x0f, 0xa2, 0x00, 2967 0x02, 0x28, 0x29, 0xb1, 2968 0x08, 0x20, 0x80, 0x00, 2969 0x00, 0x00, 0x00, 0xff, 2970 0xff, 2971 }; 2972 const unsigned char kV4FrameData[] = { 2973 0x00, 0x35, 0x08, 0x00, 2974 0x00, 0x00, 0x00, 0x01, 2975 0x38, 0xea, 0xe3, 0xc6, 2976 0xa7, 0xc2, 0x02, 0xe5, 2977 0x0e, 0x50, 0xc2, 0x4b, 2978 0x4a, 0x04, 0xe5, 0x0b, 2979 0x66, 0x80, 0x00, 0x4a, 2980 0xcb, 0xcf, 0x07, 0x08, 2981 0x20, 0x10, 0x95, 0x96, 2982 0x9f, 0x0f, 0xa2, 0x00, 2983 0x02, 0x28, 0x29, 0xb1, 2984 0x08, 0x20, 0x80, 0x00, 2985 0x00, 0x00, 0x00, 0xff, 2986 0xff 2987 }; 2988 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( 2989 1, CONTROL_FLAG_NONE, true, &headers)); 2990 if (IsSpdy2()) { 2991 CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData)); 2992 } else if (IsSpdy3()) { 2993 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 2994 } else { 2995 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 2996 } 2997 } 2998 } 2999 #endif // !defined(USE_SYSTEM_ZLIB) 3000 3001 TEST_P(SpdyFramerTest, CreateWindowUpdate) { 3002 SpdyFramer framer(spdy_version_); 3003 3004 { 3005 const char kDescription[] = "WINDOW_UPDATE frame"; 3006 const unsigned char kV3FrameData[] = { // Also applies for V2. 3007 0x80, spdy_version_ch_, 0x00, 0x09, 3008 0x00, 0x00, 0x00, 0x08, 3009 0x00, 0x00, 0x00, 0x01, 3010 0x00, 0x00, 0x00, 0x01, 3011 }; 3012 const unsigned char kV4FrameData[] = { 3013 0x00, 0x0c, 0x09, 0x00, 3014 0x00, 0x00, 0x00, 0x01, 3015 0x00, 0x00, 0x00, 0x01, 3016 }; 3017 scoped_ptr<SpdyFrame> frame( 3018 framer.CreateWindowUpdate(1, 1)); 3019 if (IsSpdy4()) { 3020 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 3021 } else { 3022 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 3023 } 3024 } 3025 3026 { 3027 const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; 3028 const unsigned char kV3FrameData[] = { // Also applies for V2. 3029 0x80, spdy_version_ch_, 0x00, 0x09, 3030 0x00, 0x00, 0x00, 0x08, 3031 0x7f, 0xff, 0xff, 0xff, 3032 0x00, 0x00, 0x00, 0x01, 3033 }; 3034 const unsigned char kV4FrameData[] = { 3035 0x00, 0x0c, 0x09, 0x00, 3036 0x7f, 0xff, 0xff, 0xff, 3037 0x00, 0x00, 0x00, 0x01, 3038 }; 3039 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1)); 3040 if (IsSpdy4()) { 3041 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 3042 } else { 3043 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 3044 } 3045 } 3046 3047 { 3048 const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; 3049 const unsigned char kV3FrameData[] = { // Also applies for V2. 3050 0x80, spdy_version_ch_, 0x00, 0x09, 3051 0x00, 0x00, 0x00, 0x08, 3052 0x00, 0x00, 0x00, 0x01, 3053 0x7f, 0xff, 0xff, 0xff, 3054 }; 3055 const unsigned char kV4FrameData[] = { 3056 0x00, 0x0c, 0x09, 0x00, 3057 0x00, 0x00, 0x00, 0x01, 3058 0x7f, 0xff, 0xff, 0xff, 3059 }; 3060 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF)); 3061 if (IsSpdy4()) { 3062 CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData)); 3063 } else { 3064 CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData)); 3065 } 3066 } 3067 } 3068 3069 TEST_P(SpdyFramerTest, SerializeBlocked) { 3070 if (spdy_version_ < SPDY4) { 3071 return; 3072 } 3073 3074 SpdyFramer framer(spdy_version_); 3075 3076 const char kDescription[] = "BLOCKED frame"; 3077 const unsigned char kFrameData[] = { 3078 0x00, 0x08, 0x0b, 0x00, 3079 0x00, 0x00, 0x00, 0x00, 3080 }; 3081 SpdyBlockedIR blocked_ir(0); 3082 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(blocked_ir)); 3083 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); 3084 3085 } 3086 3087 TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) { 3088 if (spdy_version_ < SPDY4) { 3089 return; 3090 } 3091 3092 SpdyFramer framer(spdy_version_); 3093 framer.set_enable_compression(false); 3094 3095 const char kDescription[] = "PUSH_PROMISE frame"; 3096 SpdyHeaderBlock headers; 3097 headers["bar"] = "foo"; 3098 headers["foo"] = "bar"; 3099 3100 const unsigned char kFrameData[] = { 3101 0x00, 0x2C, 0x0C, 0x00, // length = 44, type = 12, flags = 0 3102 0x00, 0x00, 0x00, 0x2A, // stream id = 42 3103 0x00, 0x00, 0x00, 0x39, // promised stream id = 57 3104 0x00, 0x00, 0x00, 0x02, // start of uncompressed header block 3105 0x00, 0x00, 0x00, 0x03, 3106 'b', 'a', 'r', 0x00, 3107 0x00, 0x00, 0x03, 'f', 3108 'o', 'o', 0x00, 0x00, 3109 0x00, 0x03, 'f', 'o', 3110 'o', 0x00, 0x00, 0x00, 3111 0x03, 'b', 'a', 'r' // end of uncompressed header block 3112 }; 3113 3114 scoped_ptr<SpdySerializedFrame> frame(framer.CreatePushPromise( 3115 42, 57, &headers)); 3116 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); 3117 } 3118 3119 TEST_P(SpdyFramerTest, CreatePushPromiseCompressed) { 3120 if (spdy_version_ < SPDY4) { 3121 return; 3122 } 3123 3124 SpdyFramer framer(spdy_version_); 3125 framer.set_enable_compression(true); 3126 3127 const char kDescription[] = "PUSH_PROMISE frame"; 3128 SpdyHeaderBlock headers; 3129 headers["bar"] = "foo"; 3130 headers["foo"] = "bar"; 3131 3132 const unsigned char kFrameData[] = { 3133 0x00, 0x39, 0x0C, 0x00, // length = 57, type = 12, flags = 0 3134 0x00, 0x00, 0x00, 0x2A, // stream id = 42 3135 0x00, 0x00, 0x00, 0x39, // promised stream id = 57 3136 0x38, 0xea, 0xe3, 0xc6, // start of compressed header block 3137 0xa7, 0xc2, 0x02, 0xe5, 3138 0x0e, 0x50, 0xc2, 0x4b, 3139 0x4a, 0x04, 0xe5, 0x0b, 3140 0x66, 0x80, 0x00, 0x4a, 3141 0xcb, 0xcf, 0x07, 0x08, 3142 0x20, 0x10, 0x95, 0x96, 3143 0x9f, 0x0f, 0xa2, 0x00, 3144 0x02, 0x28, 0x29, 0xb1, 3145 0x08, 0x20, 0x80, 0x00, 3146 0x00, 0x00, 0x00, 0xff, 3147 0xff // end of compressed header block 3148 }; 3149 3150 scoped_ptr<SpdySerializedFrame> frame(framer.CreatePushPromise( 3151 42, 57, &headers)); 3152 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); 3153 } 3154 3155 TEST_P(SpdyFramerTest, ReadCompressedSynStreamHeaderBlock) { 3156 SpdyHeaderBlock headers; 3157 headers["aa"] = "vv"; 3158 headers["bb"] = "ww"; 3159 SpdyFramer framer(spdy_version_); 3160 scoped_ptr<SpdyFrame> control_frame( 3161 framer.CreateSynStream(1, // stream_id 3162 0, // associated_stream_id 3163 1, // priority 3164 0, // credential_slot 3165 CONTROL_FLAG_NONE, 3166 true, // compress 3167 &headers)); 3168 EXPECT_TRUE(control_frame.get() != NULL); 3169 TestSpdyVisitor visitor(spdy_version_); 3170 visitor.use_compression_ = true; 3171 visitor.SimulateInFramer( 3172 reinterpret_cast<unsigned char*>(control_frame->data()), 3173 control_frame->size()); 3174 EXPECT_EQ(1, visitor.syn_frame_count_); 3175 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); 3176 } 3177 3178 TEST_P(SpdyFramerTest, ReadCompressedSynReplyHeaderBlock) { 3179 SpdyHeaderBlock headers; 3180 headers["alpha"] = "beta"; 3181 headers["gamma"] = "delta"; 3182 SpdyFramer framer(spdy_version_); 3183 scoped_ptr<SpdyFrame> control_frame( 3184 framer.CreateSynReply(1, // stream_id 3185 CONTROL_FLAG_NONE, 3186 true, // compress 3187 &headers)); 3188 EXPECT_TRUE(control_frame.get() != NULL); 3189 TestSpdyVisitor visitor(spdy_version_); 3190 visitor.use_compression_ = true; 3191 visitor.SimulateInFramer( 3192 reinterpret_cast<unsigned char*>(control_frame->data()), 3193 control_frame->size()); 3194 EXPECT_EQ(1, visitor.syn_reply_frame_count_); 3195 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); 3196 } 3197 3198 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) { 3199 SpdyHeaderBlock headers; 3200 headers["alpha"] = "beta"; 3201 headers["gamma"] = "delta"; 3202 SpdyFramer framer(spdy_version_); 3203 scoped_ptr<SpdyFrame> control_frame( 3204 framer.CreateHeaders(1, // stream_id 3205 CONTROL_FLAG_NONE, 3206 true, // compress 3207 &headers)); 3208 EXPECT_TRUE(control_frame.get() != NULL); 3209 TestSpdyVisitor visitor(spdy_version_); 3210 visitor.use_compression_ = true; 3211 visitor.SimulateInFramer( 3212 reinterpret_cast<unsigned char*>(control_frame->data()), 3213 control_frame->size()); 3214 EXPECT_EQ(1, visitor.headers_frame_count_); 3215 // control_frame_header_data_count_ depends on the random sequence 3216 // produced by rand(), so adding, removing or running single tests 3217 // alters this value. The best we can do is assert that it happens 3218 // at least twice. 3219 EXPECT_LE(2, visitor.control_frame_header_data_count_); 3220 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); 3221 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); 3222 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); 3223 } 3224 3225 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) { 3226 SpdyHeaderBlock headers; 3227 headers["alpha"] = "beta"; 3228 headers["gamma"] = "delta"; 3229 SpdyFramer framer(spdy_version_); 3230 scoped_ptr<SpdyFrame> control_frame( 3231 framer.CreateHeaders(1, // stream_id 3232 CONTROL_FLAG_FIN, 3233 true, // compress 3234 &headers)); 3235 EXPECT_TRUE(control_frame.get() != NULL); 3236 TestSpdyVisitor visitor(spdy_version_); 3237 visitor.use_compression_ = true; 3238 visitor.SimulateInFramer( 3239 reinterpret_cast<unsigned char*>(control_frame->data()), 3240 control_frame->size()); 3241 EXPECT_EQ(1, visitor.headers_frame_count_); 3242 // control_frame_header_data_count_ depends on the random sequence 3243 // produced by rand(), so adding, removing or running single tests 3244 // alters this value. The best we can do is assert that it happens 3245 // at least twice. 3246 EXPECT_LE(2, visitor.control_frame_header_data_count_); 3247 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); 3248 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); 3249 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); 3250 } 3251 3252 TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) { 3253 // First find the size of the header value in order to just reach the control 3254 // frame max size. 3255 SpdyFramer framer(spdy_version_); 3256 framer.set_enable_compression(false); 3257 SpdyHeaderBlock headers; 3258 headers["aa"] = ""; 3259 scoped_ptr<SpdyFrame> control_frame( 3260 framer.CreateSynStream(1, // stream_id 3261 0, // associated_stream_id 3262 1, // priority 3263 0, // credential_slot 3264 CONTROL_FLAG_NONE, 3265 false, // compress 3266 &headers)); 3267 const size_t kBigValueSize = 3268 framer.GetControlFrameBufferMaxSize() - control_frame->size(); 3269 3270 // Create a frame at exatly that size. 3271 string big_value(kBigValueSize, 'x'); 3272 headers["aa"] = big_value.c_str(); 3273 control_frame.reset( 3274 framer.CreateSynStream(1, // stream_id 3275 0, // associated_stream_id 3276 1, // priority 3277 0, // credential_slot 3278 CONTROL_FLAG_NONE, 3279 false, // compress 3280 &headers)); 3281 EXPECT_TRUE(control_frame.get() != NULL); 3282 EXPECT_EQ(framer.GetControlFrameBufferMaxSize(), control_frame->size()); 3283 3284 TestSpdyVisitor visitor(spdy_version_); 3285 visitor.SimulateInFramer( 3286 reinterpret_cast<unsigned char*>(control_frame->data()), 3287 control_frame->size()); 3288 EXPECT_TRUE(visitor.header_buffer_valid_); 3289 EXPECT_EQ(0, visitor.error_count_); 3290 EXPECT_EQ(1, visitor.syn_frame_count_); 3291 EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); 3292 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); 3293 EXPECT_LT(kBigValueSize, visitor.header_buffer_length_); 3294 } 3295 3296 TEST_P(SpdyFramerTest, ControlFrameTooLarge) { 3297 // First find the size of the header value in order to just reach the control 3298 // frame max size. 3299 SpdyFramer framer(spdy_version_); 3300 framer.set_enable_compression(false); 3301 SpdyHeaderBlock headers; 3302 headers["aa"] = ""; 3303 scoped_ptr<SpdyFrame> control_frame( 3304 framer.CreateSynStream(1, // stream_id 3305 0, // associated_stream_id 3306 1, // priority 3307 0, // credential_slot 3308 CONTROL_FLAG_NONE, 3309 false, // compress 3310 &headers)); 3311 const size_t kBigValueSize = 3312 framer.GetControlFrameBufferMaxSize() - control_frame->size() + 1; 3313 3314 // Create a frame at exatly that size. 3315 string big_value(kBigValueSize, 'x'); 3316 headers["aa"] = big_value.c_str(); 3317 control_frame.reset( 3318 framer.CreateSynStream(1, // stream_id 3319 0, // associated_stream_id 3320 1, // priority 3321 0, // credential_slot 3322 CONTROL_FLAG_NONE, 3323 false, // compress 3324 &headers)); 3325 EXPECT_TRUE(control_frame.get() != NULL); 3326 EXPECT_EQ(framer.GetControlFrameBufferMaxSize() + 1, 3327 control_frame->size()); 3328 3329 TestSpdyVisitor visitor(spdy_version_); 3330 visitor.SimulateInFramer( 3331 reinterpret_cast<unsigned char*>(control_frame->data()), 3332 control_frame->size()); 3333 EXPECT_FALSE(visitor.header_buffer_valid_); 3334 EXPECT_EQ(1, visitor.error_count_); 3335 EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE, 3336 visitor.framer_.error_code()) 3337 << SpdyFramer::ErrorCodeToString(framer.error_code()); 3338 EXPECT_EQ(0, visitor.syn_frame_count_); 3339 EXPECT_EQ(0u, visitor.header_buffer_length_); 3340 } 3341 3342 // Check that the framer stops delivering header data chunks once the visitor 3343 // declares it doesn't want any more. This is important to guard against 3344 // "zip bomb" types of attacks. 3345 TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) { 3346 SpdyHeaderBlock headers; 3347 const size_t kHeaderBufferChunks = 4; 3348 const size_t kHeaderBufferSize = 3349 TestSpdyVisitor::header_data_chunk_max_size() * kHeaderBufferChunks; 3350 const size_t kBigValueSize = kHeaderBufferSize * 2; 3351 string big_value(kBigValueSize, 'x'); 3352 headers["aa"] = big_value.c_str(); 3353 SpdyFramer framer(spdy_version_); 3354 scoped_ptr<SpdyFrame> control_frame( 3355 framer.CreateSynStream(1, // stream_id 3356 0, // associated_stream_id 3357 1, // priority 3358 0, // credential_slot 3359 CONTROL_FLAG_FIN, // half close 3360 true, // compress 3361 &headers)); 3362 EXPECT_TRUE(control_frame.get() != NULL); 3363 TestSpdyVisitor visitor(spdy_version_); 3364 visitor.set_header_buffer_size(kHeaderBufferSize); 3365 visitor.use_compression_ = true; 3366 visitor.SimulateInFramer( 3367 reinterpret_cast<unsigned char*>(control_frame->data()), 3368 control_frame->size()); 3369 EXPECT_FALSE(visitor.header_buffer_valid_); 3370 EXPECT_EQ(1, visitor.error_count_); 3371 EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE, 3372 visitor.framer_.error_code()) 3373 << SpdyFramer::ErrorCodeToString(framer.error_code()); 3374 3375 // The framer should have stoped delivering chunks after the visitor 3376 // signaled "stop" by returning false from OnControlFrameHeaderData(). 3377 // 3378 // control_frame_header_data_count_ depends on the random sequence 3379 // produced by rand(), so adding, removing or running single tests 3380 // alters this value. The best we can do is assert that it happens 3381 // at least kHeaderBufferChunks + 1. 3382 EXPECT_LE(kHeaderBufferChunks + 1, 3383 static_cast<unsigned>(visitor.control_frame_header_data_count_)); 3384 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); 3385 3386 // The framer should not have sent half-close to the visitor. 3387 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); 3388 } 3389 3390 TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) { 3391 SpdyHeaderBlock headers; 3392 headers["aa"] = "alpha beta gamma delta"; 3393 SpdyFramer framer(spdy_version_); 3394 framer.set_enable_compression(false); 3395 // Construct a SYN_STREAM control frame without compressing the header block, 3396 // and have the framer try to decompress it. This will cause the framer to 3397 // deal with a decompression error. 3398 scoped_ptr<SpdyFrame> control_frame( 3399 framer.CreateSynStream(1, // stream_id 3400 0, // associated_stream_id 3401 1, // priority 3402 0, // credential_slot 3403 CONTROL_FLAG_NONE, 3404 false, // compress 3405 &headers)); 3406 TestSpdyVisitor visitor(spdy_version_); 3407 visitor.use_compression_ = true; 3408 visitor.SimulateInFramer( 3409 reinterpret_cast<unsigned char*>(control_frame->data()), 3410 control_frame->size()); 3411 EXPECT_EQ(1, visitor.error_count_); 3412 EXPECT_EQ(SpdyFramer::SPDY_DECOMPRESS_FAILURE, visitor.framer_.error_code()) 3413 << SpdyFramer::ErrorCodeToString(framer.error_code()); 3414 EXPECT_EQ(0u, visitor.header_buffer_length_); 3415 } 3416 3417 TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) { 3418 // Create a GoAway frame that has a few extra bytes at the end. 3419 // We create enough overhead to overflow the framer's control frame buffer. 3420 ASSERT_GE(250u, SpdyFramer::kControlFrameBufferSize); 3421 const unsigned char length = 1 + SpdyFramer::kControlFrameBufferSize; 3422 const unsigned char kV3FrameData[] = { // Also applies for V2. 3423 0x80, spdy_version_ch_, 0x00, 0x07, 3424 0x00, 0x00, 0x00, length, 3425 0x00, 0x00, 0x00, 0x00, 3426 0x00, 0x00, 0x00, 0x00, 3427 }; 3428 const unsigned char kV4FrameData[] = { 3429 0x00, static_cast<uint8>(length + 4), 0x07, 0x00, 3430 0x00, 0x00, 0x00, 0x00, 3431 0x00, 0x00, 0x00, 0x00, 3432 }; 3433 SpdyFramer framer(spdy_version_); 3434 const size_t pad_length = 3435 length + framer.GetControlFrameHeaderSize() - 3436 (IsSpdy4() ? sizeof(kV4FrameData) : sizeof(kV3FrameData)); 3437 string pad('A', pad_length); 3438 TestSpdyVisitor visitor(spdy_version_); 3439 3440 if (IsSpdy4()) { 3441 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData)); 3442 } else { 3443 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData)); 3444 } 3445 visitor.SimulateInFramer( 3446 reinterpret_cast<const unsigned char*>(pad.c_str()), 3447 pad.length()); 3448 3449 EXPECT_EQ(1, visitor.error_count_); // This generated an error. 3450 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, 3451 visitor.framer_.error_code()) 3452 << SpdyFramer::ErrorCodeToString(framer.error_code()); 3453 EXPECT_EQ(0, visitor.goaway_count_); // Frame not parsed. 3454 } 3455 3456 TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) { 3457 SpdyFramer framer(spdy_version_); 3458 SettingsMap settings; 3459 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); 3460 SetFrameLength(control_frame.get(), 0, spdy_version_); 3461 TestSpdyVisitor visitor(spdy_version_); 3462 visitor.use_compression_ = false; 3463 visitor.SimulateInFramer( 3464 reinterpret_cast<unsigned char*>(control_frame->data()), 3465 framer.GetControlFrameHeaderSize()); 3466 // Should generate an error, since zero-len settings frames are unsupported. 3467 EXPECT_EQ(1, visitor.error_count_); 3468 } 3469 3470 // Tests handling of SETTINGS frames with invalid length. 3471 TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) { 3472 SpdyFramer framer(spdy_version_); 3473 SettingsMap settings; 3474 // Add a setting to pad the frame so that we don't get a buffer overflow when 3475 // calling SimulateInFramer() below. 3476 settings[SETTINGS_UPLOAD_BANDWIDTH] = 3477 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, 0x00000002); 3478 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); 3479 const size_t kNewLength = 5; 3480 SetFrameLength(control_frame.get(), kNewLength, spdy_version_); 3481 TestSpdyVisitor visitor(spdy_version_); 3482 visitor.use_compression_ = false; 3483 visitor.SimulateInFramer( 3484 reinterpret_cast<unsigned char*>(control_frame->data()), 3485 framer.GetControlFrameHeaderSize() + kNewLength); 3486 // Should generate an error, since zero-len settings frames are unsupported. 3487 EXPECT_EQ(1, visitor.error_count_); 3488 } 3489 3490 // Tests handling of SETTINGS frames larger than the frame buffer size. 3491 TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) { 3492 SpdyFramer framer(spdy_version_); 3493 SettingsMap settings; 3494 SpdySettingsFlags flags = SETTINGS_FLAG_PLEASE_PERSIST; 3495 settings[SETTINGS_UPLOAD_BANDWIDTH] = 3496 SettingsFlagsAndValue(flags, 0x00000002); 3497 settings[SETTINGS_DOWNLOAD_BANDWIDTH] = 3498 SettingsFlagsAndValue(flags, 0x00000003); 3499 settings[SETTINGS_ROUND_TRIP_TIME] = SettingsFlagsAndValue(flags, 0x00000004); 3500 scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); 3501 EXPECT_LT(SpdyFramer::kControlFrameBufferSize, 3502 control_frame->size()); 3503 TestSpdyVisitor visitor(spdy_version_); 3504 visitor.use_compression_ = false; 3505 3506 // Read all at once. 3507 visitor.SimulateInFramer( 3508 reinterpret_cast<unsigned char*>(control_frame->data()), 3509 control_frame->size()); 3510 EXPECT_EQ(0, visitor.error_count_); 3511 EXPECT_EQ(settings.size(), static_cast<unsigned>(visitor.setting_count_)); 3512 3513 // Read data in small chunks. 3514 size_t framed_data = 0; 3515 size_t unframed_data = control_frame->size(); 3516 size_t kReadChunkSize = 5; // Read five bytes at a time. 3517 while (unframed_data > 0) { 3518 size_t to_read = min(kReadChunkSize, unframed_data); 3519 visitor.SimulateInFramer( 3520 reinterpret_cast<unsigned char*>(control_frame->data() + framed_data), 3521 to_read); 3522 unframed_data -= to_read; 3523 framed_data += to_read; 3524 } 3525 EXPECT_EQ(0, visitor.error_count_); 3526 EXPECT_EQ(settings.size() * 2, static_cast<unsigned>(visitor.setting_count_)); 3527 } 3528 3529 // Tests handling of SETTINGS frame with duplicate entries. 3530 TEST_P(SpdyFramerTest, ReadDuplicateSettings) { 3531 SpdyFramer framer(spdy_version_); 3532 3533 const unsigned char kV2FrameData[] = { 3534 0x80, spdy_version_ch_, 0x00, 0x04, 3535 0x00, 0x00, 0x00, 0x1C, 3536 0x00, 0x00, 0x00, 0x03, 3537 0x01, 0x00, 0x00, 0x00, // 1st Setting 3538 0x00, 0x00, 0x00, 0x02, 3539 0x01, 0x00, 0x00, 0x00, // 2nd (duplicate) Setting 3540 0x00, 0x00, 0x00, 0x03, 3541 0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting 3542 0x00, 0x00, 0x00, 0x03, 3543 }; 3544 const unsigned char kV3FrameData[] = { 3545 0x80, spdy_version_ch_, 0x00, 0x04, 3546 0x00, 0x00, 0x00, 0x1C, 3547 0x00, 0x00, 0x00, 0x03, 3548 0x00, 0x00, 0x00, 0x01, // 1st Setting 3549 0x00, 0x00, 0x00, 0x02, 3550 0x00, 0x00, 0x00, 0x01, // 2nd (duplicate) Setting 3551 0x00, 0x00, 0x00, 0x03, 3552 0x00, 0x00, 0x00, 0x03, // 3rd (unprocessed) Setting 3553 0x00, 0x00, 0x00, 0x03, 3554 }; 3555 const unsigned char kV4FrameData[] = { 3556 0x00, 0x24, 0x04, 0x00, 3557 0x00, 0x00, 0x00, 0x00, 3558 0x00, 0x00, 0x00, 0x03, 3559 0x00, 0x00, 0x00, 0x01, // 1st Setting 3560 0x00, 0x00, 0x00, 0x02, 3561 0x00, 0x00, 0x00, 0x01, // 2nd (duplicate) Setting 3562 0x00, 0x00, 0x00, 0x03, 3563 0x00, 0x00, 0x00, 0x03, // 3rd (unprocessed) Setting 3564 0x00, 0x00, 0x00, 0x03, 3565 }; 3566 3567 TestSpdyVisitor visitor(spdy_version_); 3568 visitor.use_compression_ = false; 3569 if (IsSpdy2()) { 3570 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData)); 3571 } else if (IsSpdy3()) { 3572 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData)); 3573 } else { 3574 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData)); 3575 } 3576 EXPECT_EQ(1, visitor.error_count_); 3577 EXPECT_EQ(1, visitor.setting_count_); 3578 } 3579 3580 // Tests handling of SETTINGS frame with entries out of order. 3581 TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) { 3582 SpdyFramer framer(spdy_version_); 3583 3584 const unsigned char kV2FrameData[] = { 3585 0x80, spdy_version_ch_, 0x00, 0x04, 3586 0x00, 0x00, 0x00, 0x1C, 3587 0x00, 0x00, 0x00, 0x03, 3588 0x02, 0x00, 0x00, 0x00, // 1st Setting 3589 0x00, 0x00, 0x00, 0x02, 3590 0x01, 0x00, 0x00, 0x00, // 2nd (out of order) Setting 3591 0x00, 0x00, 0x00, 0x03, 3592 0x03, 0x00, 0x00, 0x00, // 3rd (unprocessed) Setting 3593 0x00, 0x00, 0x00, 0x03, 3594 }; 3595 const unsigned char kV3FrameData[] = { 3596 0x80, spdy_version_ch_, 0x00, 0x04, 3597 0x00, 0x00, 0x00, 0x1C, 3598 0x00, 0x00, 0x00, 0x03, 3599 0x00, 0x00, 0x00, 0x02, // 1st Setting 3600 0x00, 0x00, 0x00, 0x02, 3601 0x00, 0x00, 0x00, 0x01, // 2nd (out of order) Setting 3602 0x00, 0x00, 0x00, 0x03, 3603 0x00, 0x00, 0x01, 0x03, // 3rd (unprocessed) Setting 3604 0x00, 0x00, 0x00, 0x03, 3605 }; 3606 const unsigned char kV4FrameData[] = { 3607 0x00, 0x24, 0x04, 0x00, 3608 0x00, 0x00, 0x00, 0x00, 3609 0x00, 0x00, 0x00, 0x03, 3610 0x00, 0x00, 0x00, 0x02, // 1st Setting 3611 0x00, 0x00, 0x00, 0x02, 3612 0x00, 0x00, 0x00, 0x01, // 2nd (out of order) Setting 3613 0x00, 0x00, 0x00, 0x03, 3614 0x00, 0x00, 0x01, 0x03, // 3rd (unprocessed) Setting 3615 0x00, 0x00, 0x00, 0x03, 3616 }; 3617 3618 TestSpdyVisitor visitor(spdy_version_); 3619 visitor.use_compression_ = false; 3620 if (IsSpdy2()) { 3621 visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData)); 3622 } else if (IsSpdy3()) { 3623 visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData)); 3624 } else { 3625 visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData)); 3626 } 3627 EXPECT_EQ(1, visitor.error_count_); 3628 EXPECT_EQ(1, visitor.setting_count_); 3629 } 3630 3631 TEST_P(SpdyFramerTest, ReadWindowUpdate) { 3632 SpdyFramer framer(spdy_version_); 3633 scoped_ptr<SpdyFrame> control_frame( 3634 framer.CreateWindowUpdate(1, 2)); 3635 TestSpdyVisitor visitor(spdy_version_); 3636 visitor.SimulateInFramer( 3637 reinterpret_cast<unsigned char*>(control_frame->data()), 3638 control_frame->size()); 3639 EXPECT_EQ(1u, visitor.last_window_update_stream_); 3640 EXPECT_EQ(2u, visitor.last_window_update_delta_); 3641 } 3642 3643 TEST_P(SpdyFramerTest, ReadCredentialFrame) { 3644 SpdyCredential credential; 3645 credential.slot = 3; 3646 credential.proof = "proof"; 3647 credential.certs.push_back("a cert"); 3648 credential.certs.push_back("another cert"); 3649 credential.certs.push_back("final cert"); 3650 SpdyFramer framer(spdy_version_); 3651 scoped_ptr<SpdyFrame> control_frame( 3652 framer.CreateCredentialFrame(credential)); 3653 EXPECT_TRUE(control_frame.get() != NULL); 3654 TestSpdyVisitor visitor(spdy_version_); 3655 visitor.use_compression_ = false; 3656 visitor.SimulateInFramer( 3657 reinterpret_cast<unsigned char*>(control_frame->data()), 3658 control_frame->size()); 3659 EXPECT_EQ(0, visitor.error_count_); 3660 EXPECT_EQ(control_frame->size() - framer.GetControlFrameHeaderSize(), 3661 visitor.credential_buffer_length_); 3662 EXPECT_EQ(credential.slot, visitor.credential_.slot); 3663 EXPECT_EQ(credential.proof, visitor.credential_.proof); 3664 EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size()); 3665 for (size_t i = 0; i < credential.certs.size(); i++) { 3666 EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]); 3667 } 3668 } 3669 3670 TEST_P(SpdyFramerTest, ReadCredentialFrameOneByteAtATime) { 3671 SpdyCredential credential; 3672 credential.slot = 3; 3673 credential.proof = "proof"; 3674 credential.certs.push_back("a cert"); 3675 credential.certs.push_back("another cert"); 3676 credential.certs.push_back("final cert"); 3677 SpdyFramer framer(spdy_version_); 3678 scoped_ptr<SpdyFrame> control_frame( 3679 framer.CreateCredentialFrame(credential)); 3680 EXPECT_TRUE(control_frame.get() != NULL); 3681 TestSpdyVisitor visitor(spdy_version_); 3682 visitor.use_compression_ = false; 3683 // Read one byte at a time to make sure we handle edge cases 3684 unsigned char* data = 3685 reinterpret_cast<unsigned char*>(control_frame->data()); 3686 for (size_t idx = 0; idx < control_frame->size(); ++idx) { 3687 visitor.SimulateInFramer(data + idx, 1); 3688 ASSERT_EQ(0, visitor.error_count_); 3689 } 3690 EXPECT_EQ(0, visitor.error_count_); 3691 EXPECT_EQ(control_frame->size() - framer.GetControlFrameHeaderSize(), 3692 visitor.credential_buffer_length_); 3693 EXPECT_EQ(credential.slot, visitor.credential_.slot); 3694 EXPECT_EQ(credential.proof, visitor.credential_.proof); 3695 EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size()); 3696 for (size_t i = 0; i < credential.certs.size(); i++) { 3697 EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]); 3698 } 3699 } 3700 3701 TEST_P(SpdyFramerTest, ReadCredentialFrameWithNoPayload) { 3702 SpdyCredential credential; 3703 credential.slot = 3; 3704 credential.proof = "proof"; 3705 credential.certs.push_back("a cert"); 3706 credential.certs.push_back("another cert"); 3707 credential.certs.push_back("final cert"); 3708 SpdyFramer framer(spdy_version_); 3709 scoped_ptr<SpdyFrame> control_frame( 3710 framer.CreateCredentialFrame(credential)); 3711 EXPECT_TRUE(control_frame.get() != NULL); 3712 TestSpdyVisitor visitor(spdy_version_); 3713 visitor.use_compression_ = false; 3714 SetFrameLength(control_frame.get(), 0, spdy_version_); 3715 unsigned char* data = 3716 reinterpret_cast<unsigned char*>(control_frame->data()); 3717 visitor.SimulateInFramer(data, framer.GetControlFrameHeaderSize()); 3718 EXPECT_EQ(1, visitor.error_count_); 3719 } 3720 3721 TEST_P(SpdyFramerTest, ReadCredentialFrameWithCorruptProof) { 3722 SpdyCredential credential; 3723 credential.slot = 3; 3724 credential.proof = "proof"; 3725 credential.certs.push_back("a cert"); 3726 credential.certs.push_back("another cert"); 3727 credential.certs.push_back("final cert"); 3728 SpdyFramer framer(spdy_version_); 3729 scoped_ptr<SpdyFrame> control_frame( 3730 framer.CreateCredentialFrame(credential)); 3731 EXPECT_TRUE(control_frame.get() != NULL); 3732 TestSpdyVisitor visitor(spdy_version_); 3733 visitor.use_compression_ = false; 3734 unsigned char* data = 3735 reinterpret_cast<unsigned char*>(control_frame->data()); 3736 size_t offset = framer.GetControlFrameHeaderSize() + 4; 3737 data[offset] = 0xFF; // Proof length is past the end of the frame 3738 visitor.SimulateInFramer( 3739 data, control_frame->size()); 3740 EXPECT_EQ(1, visitor.error_count_); 3741 } 3742 3743 TEST_P(SpdyFramerTest, ReadCredentialFrameWithCorruptCertificate) { 3744 SpdyCredential credential; 3745 credential.slot = 3; 3746 credential.proof = "proof"; 3747 credential.certs.push_back("a cert"); 3748 credential.certs.push_back("another cert"); 3749 credential.certs.push_back("final cert"); 3750 SpdyFramer framer(spdy_version_); 3751 scoped_ptr<SpdyFrame> control_frame( 3752 framer.CreateCredentialFrame(credential)); 3753 EXPECT_TRUE(control_frame.get() != NULL); 3754 TestSpdyVisitor visitor(spdy_version_); 3755 visitor.use_compression_ = false; 3756 unsigned char* data = 3757 reinterpret_cast<unsigned char*>(control_frame->data()); 3758 size_t offset = framer.GetCredentialMinimumSize() + 1; 3759 data[offset] = 0xFF; // Proof length is past the end of the frame 3760 visitor.SimulateInFramer( 3761 data, control_frame->size()); 3762 EXPECT_EQ(1, visitor.error_count_); 3763 } 3764 3765 // Regression test for parsing issue found in b/8278897. 3766 TEST_P(SpdyFramerTest, ReadCredentialFrameFollowedByAnotherFrame) { 3767 SpdyCredential credential; 3768 credential.slot = 3; 3769 credential.proof = "proof"; 3770 credential.certs.push_back("a cert"); 3771 credential.certs.push_back("another cert"); 3772 credential.certs.push_back("final cert"); 3773 SpdyFramer framer(spdy_version_); 3774 scoped_ptr<SpdyFrame> credential_frame( 3775 framer.CreateCredentialFrame(credential)); 3776 EXPECT_TRUE(credential_frame.get() != NULL); 3777 TestSpdyVisitor visitor(spdy_version_); 3778 visitor.use_compression_ = false; 3779 string multiple_frame_data(credential_frame->data(), 3780 credential_frame->size()); 3781 scoped_ptr<SpdyFrame> goaway_frame(framer.CreateGoAway(0, GOAWAY_OK)); 3782 multiple_frame_data.append(string(goaway_frame->data(), 3783 goaway_frame->size())); 3784 visitor.SimulateInFramer( 3785 reinterpret_cast<unsigned const char*>(multiple_frame_data.data()), 3786 multiple_frame_data.length()); 3787 EXPECT_EQ(0, visitor.error_count_); 3788 EXPECT_EQ(credential_frame->size() - framer.GetControlFrameHeaderSize(), 3789 visitor.credential_buffer_length_); 3790 EXPECT_EQ(credential.slot, visitor.credential_.slot); 3791 EXPECT_EQ(credential.proof, visitor.credential_.proof); 3792 EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size()); 3793 for (size_t i = 0; i < credential.certs.size(); i++) { 3794 EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]); 3795 } 3796 } 3797 3798 TEST_P(SpdyFramerTest, ReadCompressedPushPromise) { 3799 if (spdy_version_ < 4) { 3800 return; 3801 } 3802 3803 SpdyHeaderBlock headers; 3804 headers["foo"] = "bar"; 3805 headers["bar"] = "foofoo"; 3806 SpdyFramer framer(spdy_version_); 3807 scoped_ptr<SpdyFrame> frame(framer.CreatePushPromise(42, 57, &headers)); 3808 EXPECT_TRUE(frame.get() != NULL); 3809 TestSpdyVisitor visitor(spdy_version_); 3810 visitor.use_compression_ = true; 3811 visitor.SimulateInFramer( 3812 reinterpret_cast<unsigned char*>(frame->data()), 3813 frame->size()); 3814 EXPECT_EQ(42u, visitor.last_push_promise_stream_); 3815 EXPECT_EQ(57u, visitor.last_push_promise_promised_stream_); 3816 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); 3817 } 3818 3819 TEST_P(SpdyFramerTest, ReadGarbage) { 3820 SpdyFramer framer(spdy_version_); 3821 unsigned char garbage_frame[256]; 3822 memset(garbage_frame, ~0, sizeof(garbage_frame)); 3823 TestSpdyVisitor visitor(spdy_version_); 3824 visitor.use_compression_ = false; 3825 visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame)); 3826 EXPECT_EQ(1, visitor.error_count_); 3827 } 3828 3829 TEST_P(SpdyFramerTest, ReadGarbageWithValidVersion) { 3830 if (IsSpdy4()) { 3831 // Not valid for SPDY 4 since there is no version field. 3832 return; 3833 } 3834 SpdyFramer framer(spdy_version_); 3835 const unsigned char kFrameData[] = { 3836 0x80, spdy_version_ch_, 0xff, 0xff, 3837 0xff, 0xff, 0xff, 0xff, 3838 }; 3839 TestSpdyVisitor visitor(spdy_version_); 3840 visitor.use_compression_ = false; 3841 visitor.SimulateInFramer(kFrameData, arraysize(kFrameData)); 3842 EXPECT_EQ(1, visitor.error_count_); 3843 } 3844 3845 TEST_P(SpdyFramerTest, SizesTest) { 3846 SpdyFramer framer(spdy_version_); 3847 EXPECT_EQ(8u, framer.GetDataFrameMinimumSize()); 3848 if (IsSpdy4()) { 3849 EXPECT_EQ(8u, framer.GetSynReplyMinimumSize()); 3850 EXPECT_EQ(12u, framer.GetRstStreamSize()); 3851 EXPECT_EQ(12u, framer.GetSettingsMinimumSize()); 3852 EXPECT_EQ(12u, framer.GetPingSize()); 3853 EXPECT_EQ(16u, framer.GetGoAwaySize()); 3854 EXPECT_EQ(8u, framer.GetHeadersMinimumSize()); 3855 EXPECT_EQ(12u, framer.GetWindowUpdateSize()); 3856 EXPECT_EQ(10u, framer.GetCredentialMinimumSize()); 3857 EXPECT_EQ(8u, framer.GetBlockedSize()); 3858 EXPECT_EQ(12u, framer.GetPushPromiseMinimumSize()); 3859 EXPECT_EQ(8u, framer.GetFrameMinimumSize()); 3860 EXPECT_EQ(65535u, framer.GetFrameMaximumSize()); 3861 EXPECT_EQ(65527u, framer.GetDataFrameMaximumPayload()); 3862 } else { 3863 EXPECT_EQ(8u, framer.GetControlFrameHeaderSize()); 3864 EXPECT_EQ(18u, framer.GetSynStreamMinimumSize()); 3865 EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetSynReplyMinimumSize()); 3866 EXPECT_EQ(16u, framer.GetRstStreamSize()); 3867 EXPECT_EQ(12u, framer.GetSettingsMinimumSize()); 3868 EXPECT_EQ(12u, framer.GetPingSize()); 3869 EXPECT_EQ(IsSpdy2() ? 12u : 16u, framer.GetGoAwaySize()); 3870 EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetHeadersMinimumSize()); 3871 EXPECT_EQ(16u, framer.GetWindowUpdateSize()); 3872 EXPECT_EQ(10u, framer.GetCredentialMinimumSize()); 3873 EXPECT_EQ(8u, framer.GetFrameMinimumSize()); 3874 EXPECT_EQ(16777215u, framer.GetFrameMaximumSize()); 3875 EXPECT_EQ(16777207u, framer.GetDataFrameMaximumPayload()); 3876 } 3877 } 3878 3879 TEST_P(SpdyFramerTest, StateToStringTest) { 3880 EXPECT_STREQ("ERROR", 3881 SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR)); 3882 EXPECT_STREQ("AUTO_RESET", 3883 SpdyFramer::StateToString(SpdyFramer::SPDY_AUTO_RESET)); 3884 EXPECT_STREQ("RESET", 3885 SpdyFramer::StateToString(SpdyFramer::SPDY_RESET)); 3886 EXPECT_STREQ("READING_COMMON_HEADER", 3887 SpdyFramer::StateToString( 3888 SpdyFramer::SPDY_READING_COMMON_HEADER)); 3889 EXPECT_STREQ("CONTROL_FRAME_PAYLOAD", 3890 SpdyFramer::StateToString( 3891 SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD)); 3892 EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD", 3893 SpdyFramer::StateToString( 3894 SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD)); 3895 EXPECT_STREQ("FORWARD_STREAM_FRAME", 3896 SpdyFramer::StateToString( 3897 SpdyFramer::SPDY_FORWARD_STREAM_FRAME)); 3898 EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK", 3899 SpdyFramer::StateToString( 3900 SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK)); 3901 EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK", 3902 SpdyFramer::StateToString( 3903 SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK)); 3904 EXPECT_STREQ("SPDY_CREDENTIAL_FRAME_PAYLOAD", 3905 SpdyFramer::StateToString( 3906 SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD)); 3907 EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD", 3908 SpdyFramer::StateToString( 3909 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD)); 3910 EXPECT_STREQ("UNKNOWN_STATE", 3911 SpdyFramer::StateToString( 3912 SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD + 1)); 3913 } 3914 3915 TEST_P(SpdyFramerTest, ErrorCodeToStringTest) { 3916 EXPECT_STREQ("NO_ERROR", 3917 SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR)); 3918 EXPECT_STREQ("INVALID_CONTROL_FRAME", 3919 SpdyFramer::ErrorCodeToString( 3920 SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); 3921 EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE", 3922 SpdyFramer::ErrorCodeToString( 3923 SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); 3924 EXPECT_STREQ("ZLIB_INIT_FAILURE", 3925 SpdyFramer::ErrorCodeToString( 3926 SpdyFramer::SPDY_ZLIB_INIT_FAILURE)); 3927 EXPECT_STREQ("UNSUPPORTED_VERSION", 3928 SpdyFramer::ErrorCodeToString( 3929 SpdyFramer::SPDY_UNSUPPORTED_VERSION)); 3930 EXPECT_STREQ("DECOMPRESS_FAILURE", 3931 SpdyFramer::ErrorCodeToString( 3932 SpdyFramer::SPDY_DECOMPRESS_FAILURE)); 3933 EXPECT_STREQ("COMPRESS_FAILURE", 3934 SpdyFramer::ErrorCodeToString( 3935 SpdyFramer::SPDY_COMPRESS_FAILURE)); 3936 EXPECT_STREQ("SPDY_INVALID_DATA_FRAME_FLAGS", 3937 SpdyFramer::ErrorCodeToString( 3938 SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS)); 3939 EXPECT_STREQ("SPDY_INVALID_CONTROL_FRAME_FLAGS", 3940 SpdyFramer::ErrorCodeToString( 3941 SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS)); 3942 EXPECT_STREQ("UNKNOWN_ERROR", 3943 SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR)); 3944 } 3945 3946 TEST_P(SpdyFramerTest, StatusCodeToStringTest) { 3947 EXPECT_STREQ("INVALID", 3948 SpdyFramer::StatusCodeToString(RST_STREAM_INVALID)); 3949 EXPECT_STREQ("PROTOCOL_ERROR", 3950 SpdyFramer::StatusCodeToString(RST_STREAM_PROTOCOL_ERROR)); 3951 EXPECT_STREQ("INVALID_STREAM", 3952 SpdyFramer::StatusCodeToString(RST_STREAM_INVALID_STREAM)); 3953 EXPECT_STREQ("REFUSED_STREAM", 3954 SpdyFramer::StatusCodeToString(RST_STREAM_REFUSED_STREAM)); 3955 EXPECT_STREQ("UNSUPPORTED_VERSION", 3956 SpdyFramer::StatusCodeToString(RST_STREAM_UNSUPPORTED_VERSION)); 3957 EXPECT_STREQ("CANCEL", 3958 SpdyFramer::StatusCodeToString(RST_STREAM_CANCEL)); 3959 EXPECT_STREQ("INTERNAL_ERROR", 3960 SpdyFramer::StatusCodeToString(RST_STREAM_INTERNAL_ERROR)); 3961 EXPECT_STREQ("FLOW_CONTROL_ERROR", 3962 SpdyFramer::StatusCodeToString(RST_STREAM_FLOW_CONTROL_ERROR)); 3963 EXPECT_STREQ("UNKNOWN_STATUS", 3964 SpdyFramer::StatusCodeToString(RST_STREAM_NUM_STATUS_CODES)); 3965 } 3966 3967 TEST_P(SpdyFramerTest, FrameTypeToStringTest) { 3968 EXPECT_STREQ("DATA", 3969 SpdyFramer::FrameTypeToString(DATA)); 3970 EXPECT_STREQ("SYN_STREAM", 3971 SpdyFramer::FrameTypeToString(SYN_STREAM)); 3972 EXPECT_STREQ("SYN_REPLY", 3973 SpdyFramer::FrameTypeToString(SYN_REPLY)); 3974 EXPECT_STREQ("RST_STREAM", 3975 SpdyFramer::FrameTypeToString(RST_STREAM)); 3976 EXPECT_STREQ("SETTINGS", 3977 SpdyFramer::FrameTypeToString(SETTINGS)); 3978 EXPECT_STREQ("NOOP", 3979 SpdyFramer::FrameTypeToString(NOOP)); 3980 EXPECT_STREQ("PING", 3981 SpdyFramer::FrameTypeToString(PING)); 3982 EXPECT_STREQ("GOAWAY", 3983 SpdyFramer::FrameTypeToString(GOAWAY)); 3984 EXPECT_STREQ("HEADERS", 3985 SpdyFramer::FrameTypeToString(HEADERS)); 3986 EXPECT_STREQ("WINDOW_UPDATE", 3987 SpdyFramer::FrameTypeToString(WINDOW_UPDATE)); 3988 EXPECT_STREQ("PUSH_PROMISE", 3989 SpdyFramer::FrameTypeToString(PUSH_PROMISE)); 3990 EXPECT_STREQ("CREDENTIAL", 3991 SpdyFramer::FrameTypeToString(CREDENTIAL)); 3992 } 3993 3994 TEST_P(SpdyFramerTest, CatchProbableHttpResponse) { 3995 if (IsSpdy4()) { 3996 // TODO(hkhalil): catch probable HTTP response in SPDY 4? 3997 return; 3998 } 3999 { 4000 testing::StrictMock<test::MockVisitor> visitor; 4001 SpdyFramer framer(spdy_version_); 4002 framer.set_visitor(&visitor); 4003 4004 EXPECT_CALL(visitor, OnError(_)); 4005 framer.ProcessInput("HTTP/1.1", 8); 4006 EXPECT_TRUE(framer.probable_http_response()); 4007 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4008 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code()) 4009 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4010 } 4011 { 4012 testing::StrictMock<test::MockVisitor> visitor; 4013 SpdyFramer framer(spdy_version_); 4014 framer.set_visitor(&visitor); 4015 4016 EXPECT_CALL(visitor, OnError(_)); 4017 framer.ProcessInput("HTTP/1.0", 8); 4018 EXPECT_TRUE(framer.probable_http_response()); 4019 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4020 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code()) 4021 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4022 } 4023 } 4024 4025 TEST_P(SpdyFramerTest, DataFrameFlags) { 4026 for (int flags = 0; flags < 256; ++flags) { 4027 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4028 4029 testing::StrictMock<test::MockVisitor> visitor; 4030 SpdyFramer framer(spdy_version_); 4031 framer.set_visitor(&visitor); 4032 4033 scoped_ptr<SpdyFrame> frame( 4034 framer.CreateDataFrame(1, "hello", 5, DATA_FLAG_NONE)); 4035 SetFrameFlags(frame.get(), flags, spdy_version_); 4036 4037 if (flags & ~DATA_FLAG_FIN) { 4038 EXPECT_CALL(visitor, OnError(_)); 4039 } else { 4040 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN)); 4041 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false)); 4042 if (flags & DATA_FLAG_FIN) { 4043 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); 4044 } 4045 } 4046 4047 framer.ProcessInput(frame->data(), frame->size()); 4048 if (flags & ~DATA_FLAG_FIN) { 4049 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4050 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, 4051 framer.error_code()) 4052 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4053 } else { 4054 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4055 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4056 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4057 } 4058 } 4059 } 4060 4061 TEST_P(SpdyFramerTest, SynStreamFrameFlags) { 4062 for (int flags = 0; flags < 256; ++flags) { 4063 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4064 4065 testing::StrictMock<test::MockVisitor> visitor; 4066 testing::StrictMock<test::MockDebugVisitor> debug_visitor; 4067 SpdyFramer framer(spdy_version_); 4068 framer.set_visitor(&visitor); 4069 framer.set_debug_visitor(&debug_visitor); 4070 4071 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(8, SYN_STREAM, _, _)); 4072 4073 SpdyHeaderBlock headers; 4074 headers["foo"] = "bar"; 4075 scoped_ptr<SpdyFrame> frame( 4076 framer.CreateSynStream(8, 3, 1, 0, CONTROL_FLAG_NONE, true, &headers)); 4077 SetFrameFlags(frame.get(), flags, spdy_version_); 4078 4079 if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) { 4080 EXPECT_CALL(visitor, OnError(_)); 4081 } else { 4082 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(8, SYN_STREAM, _)); 4083 EXPECT_CALL(visitor, OnSynStream(8, 3, 1, 0, flags & CONTROL_FLAG_FIN, 4084 flags & CONTROL_FLAG_UNIDIRECTIONAL)); 4085 EXPECT_CALL(visitor, OnControlFrameHeaderData(8, _, _)) 4086 .WillRepeatedly(testing::Return(true)); 4087 if (flags & DATA_FLAG_FIN) { 4088 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); 4089 } 4090 } 4091 4092 framer.ProcessInput(frame->data(), frame->size()); 4093 if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) { 4094 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4095 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4096 framer.error_code()) 4097 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4098 } else { 4099 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4100 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4101 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4102 } 4103 } 4104 } 4105 4106 TEST_P(SpdyFramerTest, SynReplyFrameFlags) { 4107 for (int flags = 0; flags < 256; ++flags) { 4108 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4109 4110 testing::StrictMock<test::MockVisitor> visitor; 4111 SpdyFramer framer(spdy_version_); 4112 framer.set_visitor(&visitor); 4113 4114 SpdyHeaderBlock headers; 4115 headers["foo"] = "bar"; 4116 scoped_ptr<SpdyFrame> frame( 4117 framer.CreateSynReply(37, CONTROL_FLAG_NONE, true, &headers)); 4118 SetFrameFlags(frame.get(), flags, spdy_version_); 4119 4120 if (flags & ~CONTROL_FLAG_FIN) { 4121 EXPECT_CALL(visitor, OnError(_)); 4122 } else { 4123 EXPECT_CALL(visitor, OnSynReply(37, flags & CONTROL_FLAG_FIN)); 4124 EXPECT_CALL(visitor, OnControlFrameHeaderData(37, _, _)) 4125 .WillRepeatedly(testing::Return(true)); 4126 if (flags & DATA_FLAG_FIN) { 4127 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); 4128 } 4129 } 4130 4131 framer.ProcessInput(frame->data(), frame->size()); 4132 if (flags & ~CONTROL_FLAG_FIN) { 4133 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4134 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4135 framer.error_code()) 4136 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4137 } else { 4138 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4139 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4140 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4141 } 4142 } 4143 } 4144 4145 TEST_P(SpdyFramerTest, RstStreamFrameFlags) { 4146 for (int flags = 0; flags < 256; ++flags) { 4147 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4148 4149 testing::StrictMock<test::MockVisitor> visitor; 4150 SpdyFramer framer(spdy_version_); 4151 framer.set_visitor(&visitor); 4152 4153 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(13, RST_STREAM_CANCEL)); 4154 SetFrameFlags(frame.get(), flags, spdy_version_); 4155 4156 if (flags != 0) { 4157 EXPECT_CALL(visitor, OnError(_)); 4158 } else { 4159 EXPECT_CALL(visitor, OnRstStream(13, RST_STREAM_CANCEL)); 4160 } 4161 4162 framer.ProcessInput(frame->data(), frame->size()); 4163 if (flags != 0) { 4164 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4165 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4166 framer.error_code()) 4167 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4168 } else { 4169 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4170 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4171 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4172 } 4173 } 4174 } 4175 4176 TEST_P(SpdyFramerTest, SettingsFrameFlags) { 4177 for (int flags = 0; flags < 256; ++flags) { 4178 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4179 4180 testing::StrictMock<test::MockVisitor> visitor; 4181 SpdyFramer framer(spdy_version_); 4182 framer.set_visitor(&visitor); 4183 4184 SettingsMap settings; 4185 settings[SETTINGS_UPLOAD_BANDWIDTH] = 4186 std::make_pair(SETTINGS_FLAG_NONE, 54321); 4187 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); 4188 SetFrameFlags(frame.get(), flags, spdy_version_); 4189 4190 if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) { 4191 EXPECT_CALL(visitor, OnError(_)); 4192 } else { 4193 EXPECT_CALL(visitor, OnSettings( 4194 flags & SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS)); 4195 EXPECT_CALL(visitor, OnSetting(SETTINGS_UPLOAD_BANDWIDTH, 4196 SETTINGS_FLAG_NONE, 54321)); 4197 } 4198 4199 framer.ProcessInput(frame->data(), frame->size()); 4200 if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) { 4201 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4202 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4203 framer.error_code()) 4204 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4205 } else { 4206 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4207 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4208 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4209 } 4210 } 4211 } 4212 4213 TEST_P(SpdyFramerTest, GoawayFrameFlags) { 4214 for (int flags = 0; flags < 256; ++flags) { 4215 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4216 4217 testing::StrictMock<test::MockVisitor> visitor; 4218 SpdyFramer framer(spdy_version_); 4219 framer.set_visitor(&visitor); 4220 4221 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(97, GOAWAY_OK)); 4222 SetFrameFlags(frame.get(), flags, spdy_version_); 4223 4224 if (flags != 0) { 4225 EXPECT_CALL(visitor, OnError(_)); 4226 } else { 4227 EXPECT_CALL(visitor, OnGoAway(97, GOAWAY_OK)); 4228 } 4229 4230 framer.ProcessInput(frame->data(), frame->size()); 4231 if (flags != 0) { 4232 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4233 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4234 framer.error_code()) 4235 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4236 } else { 4237 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4238 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4239 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4240 } 4241 } 4242 } 4243 4244 TEST_P(SpdyFramerTest, HeadersFrameFlags) { 4245 for (int flags = 0; flags < 256; ++flags) { 4246 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4247 4248 testing::StrictMock<test::MockVisitor> visitor; 4249 SpdyFramer framer(spdy_version_); 4250 framer.set_visitor(&visitor); 4251 4252 SpdyHeaderBlock headers; 4253 headers["foo"] = "bar"; 4254 scoped_ptr<SpdyFrame> frame( 4255 framer.CreateHeaders(57, CONTROL_FLAG_NONE, true, &headers)); 4256 SetFrameFlags(frame.get(), flags, spdy_version_); 4257 4258 if (flags & ~CONTROL_FLAG_FIN) { 4259 EXPECT_CALL(visitor, OnError(_)); 4260 } else { 4261 EXPECT_CALL(visitor, OnHeaders(57, flags & CONTROL_FLAG_FIN)); 4262 EXPECT_CALL(visitor, OnControlFrameHeaderData(57, _, _)) 4263 .WillRepeatedly(testing::Return(true)); 4264 if (flags & DATA_FLAG_FIN) { 4265 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true)); 4266 } 4267 } 4268 4269 framer.ProcessInput(frame->data(), frame->size()); 4270 if (flags & ~CONTROL_FLAG_FIN) { 4271 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4272 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4273 framer.error_code()) 4274 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4275 } else { 4276 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4277 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4278 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4279 } 4280 } 4281 } 4282 4283 TEST_P(SpdyFramerTest, PingFrameFlags) { 4284 for (int flags = 0; flags < 256; ++flags) { 4285 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4286 4287 testing::StrictMock<test::MockVisitor> visitor; 4288 SpdyFramer framer(spdy_version_); 4289 framer.set_visitor(&visitor); 4290 4291 scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(42)); 4292 SetFrameFlags(frame.get(), flags, spdy_version_); 4293 4294 if (flags != 0) { 4295 EXPECT_CALL(visitor, OnError(_)); 4296 } else { 4297 EXPECT_CALL(visitor, OnPing(42)); 4298 } 4299 4300 framer.ProcessInput(frame->data(), frame->size()); 4301 if (flags != 0) { 4302 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4303 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4304 framer.error_code()) 4305 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4306 } else { 4307 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4308 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4309 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4310 } 4311 } 4312 } 4313 4314 TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) { 4315 for (int flags = 0; flags < 256; ++flags) { 4316 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4317 4318 testing::StrictMock<test::MockVisitor> visitor; 4319 SpdyFramer framer(spdy_version_); 4320 framer.set_visitor(&visitor); 4321 4322 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(4, 1024)); 4323 SetFrameFlags(frame.get(), flags, spdy_version_); 4324 4325 if (flags != 0) { 4326 EXPECT_CALL(visitor, OnError(_)); 4327 } else { 4328 EXPECT_CALL(visitor, OnWindowUpdate(4, 1024)); 4329 } 4330 4331 framer.ProcessInput(frame->data(), frame->size()); 4332 if (flags != 0) { 4333 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4334 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4335 framer.error_code()) 4336 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4337 } else { 4338 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4339 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4340 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4341 } 4342 } 4343 } 4344 4345 TEST_P(SpdyFramerTest, PushPromiseFrameFlags) { 4346 if (spdy_version_ < SPDY4) { 4347 return; 4348 } 4349 4350 for (int flags = 0; flags < 256; ++flags) { 4351 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4352 4353 testing::StrictMock<net::test::MockVisitor> visitor; 4354 testing::StrictMock<net::test::MockDebugVisitor> debug_visitor; 4355 SpdyFramer framer(spdy_version_); 4356 framer.set_visitor(&visitor); 4357 framer.set_debug_visitor(&debug_visitor); 4358 4359 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(42, PUSH_PROMISE, _, _)); 4360 4361 SpdyHeaderBlock headers; 4362 headers["foo"] = "bar"; 4363 scoped_ptr<SpdyFrame> frame(framer.CreatePushPromise(42, 57, &headers)); 4364 SetFrameFlags(frame.get(), flags, spdy_version_); 4365 4366 if (flags != 0) { 4367 EXPECT_CALL(visitor, OnError(_)); 4368 } else { 4369 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, PUSH_PROMISE, _)); 4370 EXPECT_CALL(visitor, OnPushPromise(42, 57)); 4371 EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _)) 4372 .WillRepeatedly(testing::Return(true)); 4373 } 4374 4375 framer.ProcessInput(frame->data(), frame->size()); 4376 if (flags != 0) { 4377 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4378 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4379 framer.error_code()) 4380 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4381 } else { 4382 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4383 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4384 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4385 } 4386 } 4387 } 4388 4389 TEST_P(SpdyFramerTest, CredentialFrameFlags) { 4390 for (int flags = 0; flags < 256; ++flags) { 4391 SCOPED_TRACE(testing::Message() << "Flags " << flags); 4392 4393 testing::StrictMock<test::MockVisitor> visitor; 4394 SpdyFramer framer(spdy_version_); 4395 framer.set_visitor(&visitor); 4396 4397 SpdyCredential credential; 4398 scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential)); 4399 SetFrameFlags(frame.get(), flags, spdy_version_); 4400 4401 if (flags != 0) { 4402 EXPECT_CALL(visitor, OnError(_)); 4403 } else { 4404 EXPECT_CALL(visitor, OnCredentialFrameData(_, _)) 4405 .WillRepeatedly(testing::Return(true)); 4406 } 4407 4408 framer.ProcessInput(frame->data(), frame->size()); 4409 if (flags != 0) { 4410 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); 4411 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, 4412 framer.error_code()) 4413 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4414 } else { 4415 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4416 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4417 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4418 } 4419 } 4420 } 4421 4422 TEST_P(SpdyFramerTest, EmptySynStream) { 4423 SpdyHeaderBlock headers; 4424 4425 testing::StrictMock<test::MockVisitor> visitor; 4426 testing::StrictMock<test::MockDebugVisitor> debug_visitor; 4427 SpdyFramer framer(spdy_version_); 4428 framer.set_visitor(&visitor); 4429 framer.set_debug_visitor(&debug_visitor); 4430 4431 EXPECT_CALL(debug_visitor, OnSendCompressedFrame(1, SYN_STREAM, _, _)); 4432 4433 scoped_ptr<SpdyFrame> 4434 frame(framer.CreateSynStream(1, 0, 1, 0, CONTROL_FLAG_NONE, true, 4435 &headers)); 4436 // Adjust size to remove the name/value block. 4437 if (IsSpdy4()) { 4438 SetFrameLength( 4439 frame.get(), 4440 framer.GetSynStreamMinimumSize(), 4441 spdy_version_); 4442 } else { 4443 SetFrameLength( 4444 frame.get(), 4445 framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(), 4446 spdy_version_); 4447 } 4448 4449 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(1, SYN_STREAM, _)); 4450 EXPECT_CALL(visitor, OnSynStream(1, 0, 1, 0, false, false)); 4451 EXPECT_CALL(visitor, OnControlFrameHeaderData(1, NULL, 0)); 4452 4453 framer.ProcessInput(frame->data(), framer.GetSynStreamMinimumSize()); 4454 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4455 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4456 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4457 } 4458 4459 TEST_P(SpdyFramerTest, SettingsFlagsAndId) { 4460 const uint32 kId = 0x020304; 4461 const uint32 kFlags = 0x01; 4462 const uint32 kWireFormat = htonl(IsSpdy2() ? 0x04030201 : 0x01020304); 4463 4464 SettingsFlagsAndId id_and_flags = 4465 SettingsFlagsAndId::FromWireFormat(spdy_version_, kWireFormat); 4466 EXPECT_EQ(kId, id_and_flags.id()); 4467 EXPECT_EQ(kFlags, id_and_flags.flags()); 4468 EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(spdy_version_)); 4469 } 4470 4471 // Test handling of a RST_STREAM with out-of-bounds status codes. 4472 TEST_P(SpdyFramerTest, RstStreamStatusBounds) { 4473 DCHECK_GE(0xff, RST_STREAM_NUM_STATUS_CODES); 4474 4475 const unsigned char kV3RstStreamInvalid[] = { 4476 0x80, spdy_version_ch_, 0x00, 0x03, 4477 0x00, 0x00, 0x00, 0x08, 4478 0x00, 0x00, 0x00, 0x01, 4479 0x00, 0x00, 0x00, RST_STREAM_INVALID 4480 }; 4481 const unsigned char kV4RstStreamInvalid[] = { 4482 0x00, 0x0c, 0x03, 0x00, 4483 0x00, 0x00, 0x00, 0x01, 4484 0x00, 0x00, 0x00, RST_STREAM_INVALID 4485 }; 4486 4487 const unsigned char kV3RstStreamNumStatusCodes[] = { 4488 0x80, spdy_version_ch_, 0x00, 0x03, 4489 0x00, 0x00, 0x00, 0x08, 4490 0x00, 0x00, 0x00, 0x01, 4491 0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES 4492 }; 4493 const unsigned char kV4RstStreamNumStatusCodes[] = { 4494 0x00, 0x0c, 0x03, 0x00, 4495 0x00, 0x00, 0x00, 0x01, 4496 0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES 4497 }; 4498 4499 testing::StrictMock<test::MockVisitor> visitor; 4500 SpdyFramer framer(spdy_version_); 4501 framer.set_visitor(&visitor); 4502 4503 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID)); 4504 if (IsSpdy4()) { 4505 framer.ProcessInput(reinterpret_cast<const char*>(kV4RstStreamInvalid), 4506 arraysize(kV4RstStreamInvalid)); 4507 } else { 4508 framer.ProcessInput(reinterpret_cast<const char*>(kV3RstStreamInvalid), 4509 arraysize(kV3RstStreamInvalid)); 4510 } 4511 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4512 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4513 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4514 4515 EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID)); 4516 if (IsSpdy4()) { 4517 framer.ProcessInput( 4518 reinterpret_cast<const char*>(kV4RstStreamNumStatusCodes), 4519 arraysize(kV4RstStreamNumStatusCodes)); 4520 } else { 4521 framer.ProcessInput( 4522 reinterpret_cast<const char*>(kV3RstStreamNumStatusCodes), 4523 arraysize(kV3RstStreamNumStatusCodes)); 4524 } 4525 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4526 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4527 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4528 } 4529 4530 // Tests handling of a GOAWAY frame with out-of-bounds stream ID. 4531 TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) { 4532 const unsigned char kV2FrameData[] = { 4533 0x80, spdy_version_ch_, 0x00, 0x07, 4534 0x00, 0x00, 0x00, 0x04, 4535 0xff, 0xff, 0xff, 0xff, 4536 }; 4537 const unsigned char kV3FrameData[] = { 4538 0x80, spdy_version_ch_, 0x00, 0x07, 4539 0x00, 0x00, 0x00, 0x08, 4540 0xff, 0xff, 0xff, 0xff, 4541 0x00, 0x00, 0x00, 0x00, 4542 }; 4543 const unsigned char kV4FrameData[] = { 4544 0x00, 0x10, 0x07, 0x00, 4545 0x00, 0x00, 0x00, 0x00, 4546 0xff, 0xff, 0xff, 0xff, 4547 0x00, 0x00, 0x00, 0x00, 4548 }; 4549 4550 testing::StrictMock<test::MockVisitor> visitor; 4551 SpdyFramer framer(spdy_version_); 4552 framer.set_visitor(&visitor); 4553 4554 EXPECT_CALL(visitor, OnGoAway(0x7fffffff, GOAWAY_OK)); 4555 if (IsSpdy2()) { 4556 framer.ProcessInput(reinterpret_cast<const char*>(kV2FrameData), 4557 arraysize(kV2FrameData)); 4558 } else if (IsSpdy3()) { 4559 framer.ProcessInput(reinterpret_cast<const char*>(kV3FrameData), 4560 arraysize(kV3FrameData)); 4561 } else { 4562 framer.ProcessInput(reinterpret_cast<const char*>(kV4FrameData), 4563 arraysize(kV4FrameData)); 4564 } 4565 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4566 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4567 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4568 } 4569 4570 TEST_P(SpdyFramerTest, OnBlocked) { 4571 if (spdy_version_ < SPDY4) { 4572 return; 4573 } 4574 4575 const SpdyStreamId kStreamId = 0; 4576 4577 testing::StrictMock<test::MockVisitor> visitor; 4578 SpdyFramer framer(spdy_version_); 4579 framer.set_visitor(&visitor); 4580 4581 EXPECT_CALL(visitor, OnBlocked(kStreamId)); 4582 4583 SpdyBlockedIR blocked_ir(0); 4584 scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(blocked_ir)); 4585 framer.ProcessInput(frame->data(), framer.GetBlockedSize()); 4586 4587 EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state()); 4588 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) 4589 << SpdyFramer::ErrorCodeToString(framer.error_code()); 4590 } 4591 4592 } // namespace net 4593