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