| 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 spdy { | |
| 15 | |
| 16 namespace test { | |
| 17 | |
| 18 std::string HexDumpWithMarks(const unsigned char* data, int length, | |
| 19 const bool* marks, int mark_length) { | |
| 20 static const char kHexChars[] = "0123456789ABCDEF"; | |
| 21 static const int kColumns = 4; | |
| 22 | |
| 23 const int kSizeLimit = 1024; | |
| 24 if (length > kSizeLimit || mark_length > kSizeLimit) { | |
| 25 LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes."; | |
| 26 length = std::min(length, kSizeLimit); | |
| 27 mark_length = std::min(mark_length, kSizeLimit); | |
| 28 } | |
| 29 | |
| 30 std::string hex; | |
| 31 for (const unsigned char* row = data; length > 0; | |
| 32 row += kColumns, length -= kColumns) { | |
| 33 for (const unsigned char *p = row; p < row + 4; ++p) { | |
| 34 if (p < row + length) { | |
| 35 const bool mark = | |
| 36 (marks && (p - data) < mark_length && marks[p - data]); | |
| 37 hex += mark ? '*' : ' '; | |
| 38 hex += kHexChars[(*p & 0xf0) >> 4]; | |
| 39 hex += kHexChars[*p & 0x0f]; | |
| 40 hex += mark ? '*' : ' '; | |
| 41 } else { | |
| 42 hex += " "; | |
| 43 } | |
| 44 } | |
| 45 hex = hex + " "; | |
| 46 | |
| 47 for (const unsigned char *p = row; p < row + 4 && p < row + length; ++p) | |
| 48 hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.'; | |
| 49 | |
| 50 hex = hex + '\n'; | |
| 51 } | |
| 52 return hex; | |
| 53 } | |
| 54 | |
| 55 void CompareCharArraysWithHexError( | |
| 56 const std::string& description, | |
| 57 const unsigned char* actual, | |
| 58 const int actual_len, | |
| 59 const unsigned char* expected, | |
| 60 const int expected_len) { | |
| 61 const int min_len = actual_len > expected_len ? expected_len : actual_len; | |
| 62 const int max_len = actual_len > expected_len ? actual_len : expected_len; | |
| 63 scoped_array<bool> marks(new bool[max_len]); | |
| 64 bool identical = (actual_len == expected_len); | |
| 65 for (int i = 0; i < min_len; ++i) { | |
| 66 if (actual[i] != expected[i]) { | |
| 67 marks[i] = true; | |
| 68 identical = false; | |
| 69 } else { | |
| 70 marks[i] = false; | |
| 71 } | |
| 72 } | |
| 73 for (int i = min_len; i < max_len; ++i) { | |
| 74 marks[i] = true; | |
| 75 } | |
| 76 if (identical) return; | |
| 77 ADD_FAILURE() | |
| 78 << "Description:\n" | |
| 79 << description | |
| 80 << "\n\nExpected:\n" | |
| 81 << HexDumpWithMarks(expected, expected_len, marks.get(), max_len) | |
| 82 << "\nActual:\n" | |
| 83 << HexDumpWithMarks(actual, actual_len, marks.get(), max_len); | |
| 84 } | |
| 85 | |
| 86 class TestSpdyVisitor : public SpdyFramerVisitorInterface { | |
| 87 public: | |
| 88 static const size_t kDefaultHeaderBufferSize = 64 * 1024; | |
| 89 static const size_t kDefaultCredentialBufferSize = 16 * 1024; | |
| 90 | |
| 91 TestSpdyVisitor() | |
| 92 : use_compression_(false), | |
| 93 error_count_(0), | |
| 94 syn_frame_count_(0), | |
| 95 syn_reply_frame_count_(0), | |
| 96 headers_frame_count_(0), | |
| 97 goaway_count_(0), | |
| 98 credential_count_(0), | |
| 99 data_bytes_(0), | |
| 100 fin_frame_count_(0), | |
| 101 fin_flag_count_(0), | |
| 102 zero_length_data_frame_count_(0), | |
| 103 header_blocks_count_(0), | |
| 104 control_frame_header_data_count_(0), | |
| 105 zero_length_control_frame_header_data_count_(0), | |
| 106 data_frame_count_(0), | |
| 107 header_buffer_(new char[kDefaultHeaderBufferSize]), | |
| 108 header_buffer_length_(0), | |
| 109 header_buffer_size_(kDefaultHeaderBufferSize), | |
| 110 header_stream_id_(-1), | |
| 111 header_control_type_(NUM_CONTROL_FRAME_TYPES), | |
| 112 header_buffer_valid_(false), | |
| 113 credential_buffer_(new char[kDefaultCredentialBufferSize]), | |
| 114 credential_buffer_length_(0), | |
| 115 credential_buffer_size_(kDefaultCredentialBufferSize) { | |
| 116 } | |
| 117 | |
| 118 void OnError(SpdyFramer* f) { | |
| 119 LOG(INFO) << "SpdyFramer Error: " | |
| 120 << SpdyFramer::ErrorCodeToString(f->error_code()); | |
| 121 error_count_++; | |
| 122 } | |
| 123 | |
| 124 void OnDataFrameHeader(const SpdyDataFrame* frame) { | |
| 125 data_frame_count_++; | |
| 126 header_stream_id_ = frame->stream_id(); | |
| 127 } | |
| 128 | |
| 129 void OnStreamFrameData(SpdyStreamId stream_id, | |
| 130 const char* data, | |
| 131 size_t len) { | |
| 132 EXPECT_EQ(header_stream_id_, stream_id); | |
| 133 if (len == 0) | |
| 134 ++zero_length_data_frame_count_; | |
| 135 | |
| 136 data_bytes_ += len; | |
| 137 std::cerr << "OnStreamFrameData(" << stream_id << ", \""; | |
| 138 if (len > 0) { | |
| 139 for (size_t i = 0 ; i < len; ++i) { | |
| 140 std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec; | |
| 141 } | |
| 142 } | |
| 143 std::cerr << "\", " << len << ")\n"; | |
| 144 } | |
| 145 | |
| 146 void OnControl(const SpdyControlFrame* frame) { | |
| 147 switch (frame->type()) { | |
| 148 case SYN_STREAM: | |
| 149 syn_frame_count_++; | |
| 150 InitHeaderStreaming(frame); | |
| 151 break; | |
| 152 case SYN_REPLY: | |
| 153 syn_reply_frame_count_++; | |
| 154 InitHeaderStreaming(frame); | |
| 155 break; | |
| 156 case RST_STREAM: | |
| 157 fin_frame_count_++; | |
| 158 break; | |
| 159 case HEADERS: | |
| 160 headers_frame_count_++; | |
| 161 InitHeaderStreaming(frame); | |
| 162 break; | |
| 163 case GOAWAY: | |
| 164 goaway_count_++; | |
| 165 break; | |
| 166 case CREDENTIAL: | |
| 167 credential_count_++; | |
| 168 break; | |
| 169 default: | |
| 170 DLOG(FATAL); // Error! | |
| 171 } | |
| 172 if (frame->flags() & CONTROL_FLAG_FIN) | |
| 173 ++fin_flag_count_; | |
| 174 } | |
| 175 | |
| 176 bool OnControlFrameHeaderData(SpdyStreamId stream_id, | |
| 177 const char* header_data, | |
| 178 size_t len) { | |
| 179 ++control_frame_header_data_count_; | |
| 180 CHECK_EQ(header_stream_id_, stream_id); | |
| 181 if (len == 0) { | |
| 182 ++zero_length_control_frame_header_data_count_; | |
| 183 // Indicates end-of-header-block. | |
| 184 CHECK(header_buffer_valid_); | |
| 185 bool parsed_headers = SpdyFramer::ParseHeaderBlockInBuffer( | |
| 186 header_buffer_.get(), header_buffer_length_, &headers_); | |
| 187 DCHECK(parsed_headers); | |
| 188 return true; | |
| 189 } | |
| 190 const size_t available = header_buffer_size_ - header_buffer_length_; | |
| 191 if (len > available) { | |
| 192 header_buffer_valid_ = false; | |
| 193 return false; | |
| 194 } | |
| 195 memcpy(header_buffer_.get() + header_buffer_length_, header_data, len); | |
| 196 header_buffer_length_ += len; | |
| 197 return true; | |
| 198 } | |
| 199 | |
| 200 bool OnCredentialFrameData(const char* credential_data, size_t len) { | |
| 201 if (len == 0) { | |
| 202 if (!framer_.ParseCredentialData(credential_buffer_.get(), | |
| 203 credential_buffer_length_, | |
| 204 &credential_)) { | |
| 205 ++error_count_; | |
| 206 } | |
| 207 return true; | |
| 208 } | |
| 209 const size_t available = | |
| 210 credential_buffer_size_ - credential_buffer_length_; | |
| 211 if (len > available) { | |
| 212 return false; | |
| 213 } | |
| 214 memcpy(credential_buffer_.get() + credential_buffer_length_, | |
| 215 credential_data, len); | |
| 216 credential_buffer_length_ += len; | |
| 217 return true; | |
| 218 } | |
| 219 | |
| 220 // Convenience function which runs a framer simulation with particular input. | |
| 221 void SimulateInFramer(const unsigned char* input, size_t size) { | |
| 222 framer_.set_enable_compression(use_compression_); | |
| 223 framer_.set_visitor(this); | |
| 224 size_t input_remaining = size; | |
| 225 const char* input_ptr = reinterpret_cast<const char*>(input); | |
| 226 while (input_remaining > 0 && | |
| 227 framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) { | |
| 228 // To make the tests more interesting, we feed random (amd small) chunks | |
| 229 // into the framer. This simulates getting strange-sized reads from | |
| 230 // the socket. | |
| 231 const size_t kMaxReadSize = 32; | |
| 232 size_t bytes_read = | |
| 233 (rand() % std::min(input_remaining, kMaxReadSize)) + 1; | |
| 234 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read); | |
| 235 input_remaining -= bytes_processed; | |
| 236 input_ptr += bytes_processed; | |
| 237 if (framer_.state() == SpdyFramer::SPDY_DONE) | |
| 238 framer_.Reset(); | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 void InitHeaderStreaming(const SpdyControlFrame* frame) { | |
| 243 memset(header_buffer_.get(), 0, header_buffer_size_); | |
| 244 header_buffer_length_ = 0; | |
| 245 header_stream_id_ = SpdyFramer::GetControlFrameStreamId(frame); | |
| 246 header_control_type_ = frame->type(); | |
| 247 header_buffer_valid_ = true; | |
| 248 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
| 249 } | |
| 250 | |
| 251 // Override the default buffer size (16K). Call before using the framer! | |
| 252 void set_header_buffer_size(size_t header_buffer_size) { | |
| 253 header_buffer_size_ = header_buffer_size; | |
| 254 header_buffer_.reset(new char[header_buffer_size]); | |
| 255 } | |
| 256 | |
| 257 static size_t control_frame_buffer_max_size() { | |
| 258 return SpdyFramer::kControlFrameBufferMaxSize; | |
| 259 } | |
| 260 | |
| 261 static size_t header_data_chunk_max_size() { | |
| 262 return SpdyFramer::kHeaderDataChunkMaxSize; | |
| 263 } | |
| 264 | |
| 265 SpdyFramer framer_; | |
| 266 bool use_compression_; | |
| 267 | |
| 268 // Counters from the visitor callbacks. | |
| 269 int error_count_; | |
| 270 int syn_frame_count_; | |
| 271 int syn_reply_frame_count_; | |
| 272 int headers_frame_count_; | |
| 273 int goaway_count_; | |
| 274 int credential_count_; | |
| 275 int data_bytes_; | |
| 276 int fin_frame_count_; // The count of RST_STREAM type frames received. | |
| 277 int fin_flag_count_; // The count of frames with the FIN flag set. | |
| 278 int zero_length_data_frame_count_; // The count of zero-length data frames. | |
| 279 int header_blocks_count_; | |
| 280 int control_frame_header_data_count_; // The count of chunks received. | |
| 281 // The count of zero-length control frame header data chunks received. | |
| 282 int zero_length_control_frame_header_data_count_; | |
| 283 int data_frame_count_; | |
| 284 | |
| 285 // Header block streaming state: | |
| 286 scoped_array<char> header_buffer_; | |
| 287 size_t header_buffer_length_; | |
| 288 size_t header_buffer_size_; | |
| 289 SpdyStreamId header_stream_id_; | |
| 290 SpdyControlType header_control_type_; | |
| 291 bool header_buffer_valid_; | |
| 292 SpdyHeaderBlock headers_; | |
| 293 | |
| 294 scoped_array<char> credential_buffer_; | |
| 295 size_t credential_buffer_length_; | |
| 296 size_t credential_buffer_size_; | |
| 297 SpdyCredential credential_; | |
| 298 }; | |
| 299 | |
| 300 } // namespace test | |
| 301 | |
| 302 } // namespace spdy | |
| 303 | |
| 304 using spdy::SpdyControlFlags; | |
| 305 using spdy::SpdyControlFrame; | |
| 306 using spdy::SpdyDataFrame; | |
| 307 using spdy::SpdyFrame; | |
| 308 using spdy::SpdyFrameBuilder; | |
| 309 using spdy::SpdyFramer; | |
| 310 using spdy::SpdyHeaderBlock; | |
| 311 using spdy::SpdySynStreamControlFrame; | |
| 312 using spdy::kControlFlagMask; | |
| 313 using spdy::kLengthMask; | |
| 314 using spdy::CONTROL_FLAG_NONE; | |
| 315 using spdy::DATA_FLAG_COMPRESSED; | |
| 316 using spdy::DATA_FLAG_FIN; | |
| 317 using spdy::SYN_STREAM; | |
| 318 using spdy::test::CompareCharArraysWithHexError; | |
| 319 using spdy::test::TestSpdyVisitor; | |
| 320 | |
| 321 namespace spdy { | |
| 322 | |
| 323 TEST(SpdyFrameBuilderTest, WriteLimits) { | |
| 324 SpdyFrameBuilder builder(kLengthMask + 4); | |
| 325 // length field should fail. | |
| 326 EXPECT_FALSE(builder.WriteBytes(reinterpret_cast<const void*>(0x1), | |
| 327 kLengthMask + 1)); | |
| 328 EXPECT_EQ(0, builder.length()); | |
| 329 | |
| 330 // Writing a block of the maximum allowed size should succeed. | |
| 331 const std::string kLargeData(kLengthMask, 'A'); | |
| 332 builder.WriteUInt32(kLengthMask); | |
| 333 EXPECT_EQ(4, builder.length()); | |
| 334 EXPECT_TRUE(builder.WriteBytes(kLargeData.data(), kLengthMask)); | |
| 335 EXPECT_EQ(4 + kLengthMask, static_cast<unsigned>(builder.length())); | |
| 336 } | |
| 337 | |
| 338 class SpdyFramerTest : public PlatformTest { | |
| 339 public: | |
| 340 virtual void TearDown() {} | |
| 341 | |
| 342 protected: | |
| 343 void CompareFrame(const std::string& description, | |
| 344 const SpdyFrame& actual_frame, | |
| 345 const unsigned char* expected, | |
| 346 const int expected_len) { | |
| 347 const unsigned char* actual = | |
| 348 reinterpret_cast<const unsigned char*>(actual_frame.data()); | |
| 349 int actual_len = actual_frame.length() + SpdyFrame::kHeaderSize; | |
| 350 CompareCharArraysWithHexError( | |
| 351 description, actual, actual_len, expected, expected_len); | |
| 352 } | |
| 353 | |
| 354 // Returns true if the two header blocks have equivalent content. | |
| 355 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected, | |
| 356 const SpdyHeaderBlock* actual) { | |
| 357 if (expected->size() != actual->size()) { | |
| 358 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got " | |
| 359 << actual->size() << "." << std::endl; | |
| 360 return false; | |
| 361 } | |
| 362 for (SpdyHeaderBlock::const_iterator it = expected->begin(); | |
| 363 it != expected->end(); | |
| 364 ++it) { | |
| 365 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first); | |
| 366 if (it2 == actual->end()) { | |
| 367 LOG(ERROR) << "Expected header name '" << it->first << "'." | |
| 368 << std::endl; | |
| 369 return false; | |
| 370 } | |
| 371 if (it->second.compare(it2->second) != 0) { | |
| 372 LOG(ERROR) << "Expected header named '" << it->first | |
| 373 << "' to have a value of '" << it->second | |
| 374 << "'. The actual value received was '" << it2->second | |
| 375 << "'." << std::endl; | |
| 376 return false; | |
| 377 } | |
| 378 } | |
| 379 return true; | |
| 380 } | |
| 381 }; | |
| 382 | |
| 383 | |
| 384 // Test that we can encode and decode a SpdyHeaderBlock in serialized form. | |
| 385 TEST_F(SpdyFramerTest, HeaderBlockInBuffer) { | |
| 386 SpdyHeaderBlock headers; | |
| 387 headers["alpha"] = "beta"; | |
| 388 headers["gamma"] = "charlie"; | |
| 389 SpdyFramer framer; | |
| 390 | |
| 391 // Encode the header block into a SynStream frame. | |
| 392 scoped_ptr<SpdySynStreamControlFrame> frame( | |
| 393 framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, &headers)); | |
| 394 EXPECT_TRUE(frame.get() != NULL); | |
| 395 std::string serialized_headers(frame->header_block(), | |
| 396 frame->header_block_len()); | |
| 397 SpdyHeaderBlock new_headers; | |
| 398 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
| 399 serialized_headers.size(), | |
| 400 &new_headers)); | |
| 401 | |
| 402 EXPECT_EQ(headers.size(), new_headers.size()); | |
| 403 EXPECT_EQ(headers["alpha"], new_headers["alpha"]); | |
| 404 EXPECT_EQ(headers["gamma"], new_headers["gamma"]); | |
| 405 } | |
| 406 | |
| 407 // Test that if there's not a full frame, we fail to parse it. | |
| 408 TEST_F(SpdyFramerTest, UndersizedHeaderBlockInBuffer) { | |
| 409 SpdyHeaderBlock headers; | |
| 410 headers["alpha"] = "beta"; | |
| 411 headers["gamma"] = "charlie"; | |
| 412 SpdyFramer framer; | |
| 413 | |
| 414 // Encode the header block into a SynStream frame. | |
| 415 scoped_ptr<SpdySynStreamControlFrame> frame( | |
| 416 framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, &headers)); | |
| 417 EXPECT_TRUE(frame.get() != NULL); | |
| 418 | |
| 419 std::string serialized_headers(frame->header_block(), | |
| 420 frame->header_block_len()); | |
| 421 SpdyHeaderBlock new_headers; | |
| 422 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
| 423 serialized_headers.size() - 2, | |
| 424 &new_headers)); | |
| 425 } | |
| 426 | |
| 427 TEST_F(SpdyFramerTest, OutOfOrderHeaders) { | |
| 428 // Frame builder with plentiful buffer size. | |
| 429 SpdyFrameBuilder frame(1024); | |
| 430 | |
| 431 frame.WriteUInt16(kControlFlagMask | 1); | |
| 432 frame.WriteUInt16(SYN_STREAM); | |
| 433 frame.WriteUInt32(0); // Placeholder for the length. | |
| 434 frame.WriteUInt32(3); // stream_id | |
| 435 frame.WriteUInt32(0); // Associated stream id | |
| 436 frame.WriteUInt16(0); // Priority. | |
| 437 | |
| 438 frame.WriteUInt16(2); // Number of headers. | |
| 439 SpdyHeaderBlock::iterator it; | |
| 440 frame.WriteString("gamma"); | |
| 441 frame.WriteString("gamma"); | |
| 442 frame.WriteString("alpha"); | |
| 443 frame.WriteString("alpha"); | |
| 444 // write the length | |
| 445 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); | |
| 446 | |
| 447 SpdyHeaderBlock new_headers; | |
| 448 scoped_ptr<SpdyFrame> control_frame(frame.take()); | |
| 449 SpdySynStreamControlFrame syn_frame(control_frame->data(), false); | |
| 450 std::string serialized_headers(syn_frame.header_block(), | |
| 451 syn_frame.header_block_len()); | |
| 452 SpdyFramer framer; | |
| 453 framer.set_enable_compression(false); | |
| 454 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
| 455 serialized_headers.size(), | |
| 456 &new_headers)); | |
| 457 } | |
| 458 | |
| 459 TEST_F(SpdyFramerTest, DuplicateHeader) { | |
| 460 // Frame builder with plentiful buffer size. | |
| 461 SpdyFrameBuilder frame(1024); | |
| 462 | |
| 463 frame.WriteUInt16(kControlFlagMask | 1); | |
| 464 frame.WriteUInt16(SYN_STREAM); | |
| 465 frame.WriteUInt32(0); // Placeholder for the length. | |
| 466 frame.WriteUInt32(3); // stream_id | |
| 467 frame.WriteUInt32(0); // associated stream id | |
| 468 frame.WriteUInt16(0); // Priority. | |
| 469 | |
| 470 frame.WriteUInt16(2); // Number of headers. | |
| 471 SpdyHeaderBlock::iterator it; | |
| 472 frame.WriteString("name"); | |
| 473 frame.WriteString("value1"); | |
| 474 frame.WriteString("name"); | |
| 475 frame.WriteString("value2"); | |
| 476 // write the length | |
| 477 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); | |
| 478 | |
| 479 SpdyHeaderBlock new_headers; | |
| 480 scoped_ptr<SpdyFrame> control_frame(frame.take()); | |
| 481 SpdySynStreamControlFrame syn_frame(control_frame->data(), false); | |
| 482 std::string serialized_headers(syn_frame.header_block(), | |
| 483 syn_frame.header_block_len()); | |
| 484 SpdyFramer framer; | |
| 485 framer.set_enable_compression(false); | |
| 486 // This should fail because duplicate headers are verboten by the spec. | |
| 487 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
| 488 serialized_headers.size(), | |
| 489 &new_headers)); | |
| 490 } | |
| 491 | |
| 492 TEST_F(SpdyFramerTest, MultiValueHeader) { | |
| 493 // Frame builder with plentiful buffer size. | |
| 494 SpdyFrameBuilder frame(1024); | |
| 495 | |
| 496 frame.WriteUInt16(kControlFlagMask | 1); | |
| 497 frame.WriteUInt16(SYN_STREAM); | |
| 498 frame.WriteUInt32(0); // Placeholder for the length. | |
| 499 frame.WriteUInt32(3); // stream_id | |
| 500 frame.WriteUInt32(0); // associated stream id | |
| 501 frame.WriteUInt16(0); // Priority. | |
| 502 | |
| 503 frame.WriteUInt16(1); // Number of headers. | |
| 504 SpdyHeaderBlock::iterator it; | |
| 505 frame.WriteString("name"); | |
| 506 std::string value("value1\0value2"); | |
| 507 frame.WriteString(value); | |
| 508 // write the length | |
| 509 frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); | |
| 510 | |
| 511 SpdyHeaderBlock new_headers; | |
| 512 scoped_ptr<SpdyFrame> control_frame(frame.take()); | |
| 513 SpdySynStreamControlFrame syn_frame(control_frame->data(), false); | |
| 514 std::string serialized_headers(syn_frame.header_block(), | |
| 515 syn_frame.header_block_len()); | |
| 516 SpdyFramer framer; | |
| 517 framer.set_enable_compression(false); | |
| 518 EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), | |
| 519 serialized_headers.size(), | |
| 520 &new_headers)); | |
| 521 EXPECT_TRUE(new_headers.find("name") != new_headers.end()); | |
| 522 EXPECT_EQ(value, new_headers.find("name")->second); | |
| 523 } | |
| 524 | |
| 525 TEST_F(SpdyFramerTest, BasicCompression) { | |
| 526 SpdyHeaderBlock headers; | |
| 527 headers["server"] = "SpdyServer 1.0"; | |
| 528 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; | |
| 529 headers["status"] = "200"; | |
| 530 headers["version"] = "HTTP/1.1"; | |
| 531 headers["content-type"] = "text/html"; | |
| 532 headers["content-length"] = "12"; | |
| 533 | |
| 534 SpdyFramer framer; | |
| 535 framer.set_enable_compression(true); | |
| 536 scoped_ptr<SpdySynStreamControlFrame> | |
| 537 frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, | |
| 538 &headers)); | |
| 539 scoped_ptr<SpdySynStreamControlFrame> | |
| 540 frame2(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, | |
| 541 &headers)); | |
| 542 | |
| 543 // Expect the second frame to be more compact than the first. | |
| 544 EXPECT_LE(frame2->length(), frame1->length()); | |
| 545 | |
| 546 // Decompress the first frame | |
| 547 scoped_ptr<SpdyFrame> frame3(framer.DecompressFrame(*frame1.get())); | |
| 548 | |
| 549 // Decompress the second frame | |
| 550 scoped_ptr<SpdyFrame> frame4(framer.DecompressFrame(*frame2.get())); | |
| 551 | |
| 552 // Expect frames 3 & 4 to be the same. | |
| 553 EXPECT_EQ(0, | |
| 554 memcmp(frame3->data(), frame4->data(), | |
| 555 SpdyFrame::kHeaderSize + frame3->length())); | |
| 556 | |
| 557 | |
| 558 // Expect frames 3 to be the same as a uncompressed frame created | |
| 559 // from scratch. | |
| 560 scoped_ptr<SpdySynStreamControlFrame> | |
| 561 uncompressed_frame(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, | |
| 562 false, &headers)); | |
| 563 EXPECT_EQ(frame3->length(), uncompressed_frame->length()); | |
| 564 EXPECT_EQ(0, | |
| 565 memcmp(frame3->data(), uncompressed_frame->data(), | |
| 566 SpdyFrame::kHeaderSize + uncompressed_frame->length())); | |
| 567 } | |
| 568 | |
| 569 TEST_F(SpdyFramerTest, DecompressUncompressedFrame) { | |
| 570 SpdyHeaderBlock headers; | |
| 571 headers["server"] = "SpdyServer 1.0"; | |
| 572 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; | |
| 573 headers["status"] = "200"; | |
| 574 headers["version"] = "HTTP/1.1"; | |
| 575 headers["content-type"] = "text/html"; | |
| 576 headers["content-length"] = "12"; | |
| 577 | |
| 578 SpdyFramer framer; | |
| 579 framer.set_enable_compression(true); | |
| 580 scoped_ptr<SpdySynStreamControlFrame> | |
| 581 frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, | |
| 582 &headers)); | |
| 583 | |
| 584 // Decompress the frame | |
| 585 scoped_ptr<SpdyFrame> frame2(framer.DecompressFrame(*frame1.get())); | |
| 586 | |
| 587 EXPECT_EQ(NULL, frame2.get()); | |
| 588 } | |
| 589 | |
| 590 TEST_F(SpdyFramerTest, Basic) { | |
| 591 const unsigned char input[] = { | |
| 592 0x80, 0x02, 0x00, 0x01, // SYN Stream #1 | |
| 593 0x00, 0x00, 0x00, 0x14, | |
| 594 0x00, 0x00, 0x00, 0x01, | |
| 595 0x00, 0x00, 0x00, 0x00, | |
| 596 0x00, 0x00, 0x00, 0x01, | |
| 597 0x00, 0x02, 'h', 'h', | |
| 598 0x00, 0x02, 'v', 'v', | |
| 599 | |
| 600 0x80, 0x02, 0x00, 0x08, // HEADERS on Stream #1 | |
| 601 0x00, 0x00, 0x00, 0x18, | |
| 602 0x00, 0x00, 0x00, 0x01, | |
| 603 0x00, 0x00, 0x00, 0x02, | |
| 604 0x00, 0x02, 'h', '2', | |
| 605 0x00, 0x02, 'v', '2', | |
| 606 0x00, 0x02, 'h', '3', | |
| 607 0x00, 0x02, 'v', '3', | |
| 608 | |
| 609 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
| 610 0x00, 0x00, 0x00, 0x0c, | |
| 611 0xde, 0xad, 0xbe, 0xef, | |
| 612 0xde, 0xad, 0xbe, 0xef, | |
| 613 0xde, 0xad, 0xbe, 0xef, | |
| 614 | |
| 615 0x80, 0x02, 0x00, 0x01, // SYN Stream #3 | |
| 616 0x00, 0x00, 0x00, 0x0c, | |
| 617 0x00, 0x00, 0x00, 0x03, | |
| 618 0x00, 0x00, 0x00, 0x00, | |
| 619 0x00, 0x00, 0x00, 0x00, | |
| 620 | |
| 621 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
| 622 0x00, 0x00, 0x00, 0x08, | |
| 623 0xde, 0xad, 0xbe, 0xef, | |
| 624 0xde, 0xad, 0xbe, 0xef, | |
| 625 | |
| 626 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
| 627 0x00, 0x00, 0x00, 0x04, | |
| 628 0xde, 0xad, 0xbe, 0xef, | |
| 629 | |
| 630 0x80, 0x02, 0x00, 0x03, // RST_STREAM on Stream #1 | |
| 631 0x00, 0x00, 0x00, 0x08, | |
| 632 0x00, 0x00, 0x00, 0x01, | |
| 633 0x00, 0x00, 0x00, 0x00, | |
| 634 | |
| 635 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 | |
| 636 0x00, 0x00, 0x00, 0x00, | |
| 637 | |
| 638 0x80, 0x02, 0x00, 0x03, // RST_STREAM on Stream #3 | |
| 639 0x00, 0x00, 0x00, 0x08, | |
| 640 0x00, 0x00, 0x00, 0x03, | |
| 641 0x00, 0x00, 0x00, 0x00, | |
| 642 }; | |
| 643 | |
| 644 TestSpdyVisitor visitor; | |
| 645 visitor.SimulateInFramer(input, sizeof(input)); | |
| 646 | |
| 647 EXPECT_EQ(0, visitor.error_count_); | |
| 648 EXPECT_EQ(2, visitor.syn_frame_count_); | |
| 649 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
| 650 EXPECT_EQ(1, visitor.headers_frame_count_); | |
| 651 EXPECT_EQ(24, visitor.data_bytes_); | |
| 652 EXPECT_EQ(2, visitor.fin_frame_count_); | |
| 653 EXPECT_EQ(0, visitor.fin_flag_count_); | |
| 654 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); | |
| 655 EXPECT_EQ(4, visitor.data_frame_count_); | |
| 656 } | |
| 657 | |
| 658 // Test that the FIN flag on a data frame signifies EOF. | |
| 659 TEST_F(SpdyFramerTest, FinOnDataFrame) { | |
| 660 const unsigned char input[] = { | |
| 661 0x80, 0x02, 0x00, 0x01, // SYN Stream #1 | |
| 662 0x00, 0x00, 0x00, 0x14, | |
| 663 0x00, 0x00, 0x00, 0x01, | |
| 664 0x00, 0x00, 0x00, 0x00, | |
| 665 0x00, 0x00, 0x00, 0x01, | |
| 666 0x00, 0x02, 'h', 'h', | |
| 667 0x00, 0x02, 'v', 'v', | |
| 668 | |
| 669 0x80, 0x02, 0x00, 0x02, // SYN REPLY Stream #1 | |
| 670 0x00, 0x00, 0x00, 0x10, | |
| 671 0x00, 0x00, 0x00, 0x01, | |
| 672 0x00, 0x00, 0x00, 0x01, | |
| 673 0x00, 0x02, 'a', 'a', | |
| 674 0x00, 0x02, 'b', 'b', | |
| 675 | |
| 676 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 | |
| 677 0x00, 0x00, 0x00, 0x0c, | |
| 678 0xde, 0xad, 0xbe, 0xef, | |
| 679 0xde, 0xad, 0xbe, 0xef, | |
| 680 0xde, 0xad, 0xbe, 0xef, | |
| 681 | |
| 682 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF | |
| 683 0x01, 0x00, 0x00, 0x04, | |
| 684 0xde, 0xad, 0xbe, 0xef, | |
| 685 }; | |
| 686 | |
| 687 TestSpdyVisitor visitor; | |
| 688 visitor.SimulateInFramer(input, sizeof(input)); | |
| 689 | |
| 690 EXPECT_EQ(0, visitor.error_count_); | |
| 691 EXPECT_EQ(1, visitor.syn_frame_count_); | |
| 692 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
| 693 EXPECT_EQ(0, visitor.headers_frame_count_); | |
| 694 EXPECT_EQ(16, visitor.data_bytes_); | |
| 695 EXPECT_EQ(0, visitor.fin_frame_count_); | |
| 696 EXPECT_EQ(0, visitor.fin_flag_count_); | |
| 697 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
| 698 EXPECT_EQ(2, visitor.data_frame_count_); | |
| 699 } | |
| 700 | |
| 701 // Test that the FIN flag on a SYN reply frame signifies EOF. | |
| 702 TEST_F(SpdyFramerTest, FinOnSynReplyFrame) { | |
| 703 const unsigned char input[] = { | |
| 704 0x80, 0x02, 0x00, 0x01, // SYN Stream #1 | |
| 705 0x00, 0x00, 0x00, 0x14, | |
| 706 0x00, 0x00, 0x00, 0x01, | |
| 707 0x00, 0x00, 0x00, 0x00, | |
| 708 0x00, 0x00, 0x00, 0x01, | |
| 709 0x00, 0x02, 'h', 'h', | |
| 710 0x00, 0x02, 'v', 'v', | |
| 711 | |
| 712 0x80, 0x02, 0x00, 0x02, // SYN REPLY Stream #1 | |
| 713 0x01, 0x00, 0x00, 0x14, | |
| 714 0x00, 0x00, 0x00, 0x01, | |
| 715 0x00, 0x00, 0x00, 0x00, | |
| 716 0x00, 0x00, 0x00, 0x01, | |
| 717 0x00, 0x02, 'a', 'a', | |
| 718 0x00, 0x02, 'b', 'b', | |
| 719 }; | |
| 720 | |
| 721 TestSpdyVisitor visitor; | |
| 722 visitor.SimulateInFramer(input, sizeof(input)); | |
| 723 | |
| 724 EXPECT_EQ(0, visitor.error_count_); | |
| 725 EXPECT_EQ(1, visitor.syn_frame_count_); | |
| 726 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
| 727 EXPECT_EQ(0, visitor.headers_frame_count_); | |
| 728 EXPECT_EQ(0, visitor.data_bytes_); | |
| 729 EXPECT_EQ(0, visitor.fin_frame_count_); | |
| 730 EXPECT_EQ(1, visitor.fin_flag_count_); | |
| 731 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
| 732 EXPECT_EQ(0, visitor.data_frame_count_); | |
| 733 } | |
| 734 | |
| 735 TEST_F(SpdyFramerTest, HeaderCompression) { | |
| 736 SpdyFramer send_framer; | |
| 737 SpdyFramer recv_framer; | |
| 738 | |
| 739 send_framer.set_enable_compression(true); | |
| 740 recv_framer.set_enable_compression(true); | |
| 741 | |
| 742 const char kHeader1[] = "header1"; | |
| 743 const char kHeader2[] = "header2"; | |
| 744 const char kHeader3[] = "header3"; | |
| 745 const char kValue1[] = "value1"; | |
| 746 const char kValue2[] = "value2"; | |
| 747 const char kValue3[] = "value3"; | |
| 748 | |
| 749 // SYN_STREAM #1 | |
| 750 SpdyHeaderBlock block; | |
| 751 block[kHeader1] = kValue1; | |
| 752 block[kHeader2] = kValue2; | |
| 753 SpdyControlFlags flags(CONTROL_FLAG_NONE); | |
| 754 scoped_ptr<spdy::SpdyFrame> syn_frame_1( | |
| 755 send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); | |
| 756 EXPECT_TRUE(syn_frame_1.get() != NULL); | |
| 757 | |
| 758 // SYN_STREAM #2 | |
| 759 block[kHeader3] = kValue3; | |
| 760 scoped_ptr<spdy::SpdyFrame> syn_frame_2( | |
| 761 send_framer.CreateSynStream(3, 0, 0, flags, true, &block)); | |
| 762 EXPECT_TRUE(syn_frame_2.get() != NULL); | |
| 763 | |
| 764 // Now start decompressing | |
| 765 scoped_ptr<SpdyFrame> decompressed; | |
| 766 scoped_ptr<SpdyFrame> decompressed_syn_frame; | |
| 767 SpdySynStreamControlFrame* syn_frame; | |
| 768 scoped_ptr<std::string> serialized_headers; | |
| 769 SpdyHeaderBlock decompressed_headers; | |
| 770 | |
| 771 // Decompress SYN_STREAM #1 | |
| 772 decompressed.reset(recv_framer.DecompressFrame(*syn_frame_1.get())); | |
| 773 EXPECT_TRUE(decompressed.get() != NULL); | |
| 774 EXPECT_TRUE(decompressed->is_control_frame()); | |
| 775 EXPECT_EQ(SYN_STREAM, | |
| 776 reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type()); | |
| 777 decompressed_syn_frame.reset( | |
| 778 new SpdySynStreamControlFrame(decompressed->data(), false)); | |
| 779 syn_frame = reinterpret_cast<SpdySynStreamControlFrame*>( | |
| 780 decompressed_syn_frame.get()); | |
| 781 serialized_headers.reset(new std::string(syn_frame->header_block(), | |
| 782 syn_frame->header_block_len())); | |
| 783 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(), | |
| 784 serialized_headers->size(), | |
| 785 &decompressed_headers)); | |
| 786 EXPECT_EQ(2u, decompressed_headers.size()); | |
| 787 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); | |
| 788 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); | |
| 789 | |
| 790 // Decompress SYN_STREAM #2 | |
| 791 decompressed.reset(recv_framer.DecompressFrame(*syn_frame_2.get())); | |
| 792 EXPECT_TRUE(decompressed.get() != NULL); | |
| 793 EXPECT_TRUE(decompressed->is_control_frame()); | |
| 794 EXPECT_EQ(SYN_STREAM, | |
| 795 reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type()); | |
| 796 decompressed_syn_frame.reset( | |
| 797 new SpdySynStreamControlFrame(decompressed->data(), false)); | |
| 798 syn_frame = reinterpret_cast<SpdySynStreamControlFrame*>( | |
| 799 decompressed_syn_frame.get()); | |
| 800 serialized_headers.reset(new std::string(syn_frame->header_block(), | |
| 801 syn_frame->header_block_len())); | |
| 802 decompressed_headers.clear(); | |
| 803 EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(), | |
| 804 serialized_headers->size(), | |
| 805 &decompressed_headers)); | |
| 806 EXPECT_EQ(3u, decompressed_headers.size()); | |
| 807 EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); | |
| 808 EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); | |
| 809 EXPECT_EQ(kValue3, decompressed_headers[kHeader3]); | |
| 810 | |
| 811 // We didn't have data streams, so we shouldn't have (de)compressors. | |
| 812 EXPECT_EQ(0, send_framer.num_stream_compressors()); | |
| 813 EXPECT_EQ(0, send_framer.num_stream_decompressors()); | |
| 814 EXPECT_EQ(0, recv_framer.num_stream_compressors()); | |
| 815 EXPECT_EQ(0, recv_framer.num_stream_decompressors()); | |
| 816 } | |
| 817 | |
| 818 // Verify we don't leak when we leave streams unclosed | |
| 819 TEST_F(SpdyFramerTest, UnclosedStreamDataCompressors) { | |
| 820 SpdyFramer send_framer; | |
| 821 | |
| 822 send_framer.set_enable_compression(true); | |
| 823 | |
| 824 const char kHeader1[] = "header1"; | |
| 825 const char kHeader2[] = "header2"; | |
| 826 const char kValue1[] = "value1"; | |
| 827 const char kValue2[] = "value2"; | |
| 828 | |
| 829 SpdyHeaderBlock block; | |
| 830 block[kHeader1] = kValue1; | |
| 831 block[kHeader2] = kValue2; | |
| 832 SpdyControlFlags flags(CONTROL_FLAG_NONE); | |
| 833 scoped_ptr<spdy::SpdyFrame> syn_frame( | |
| 834 send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); | |
| 835 EXPECT_TRUE(syn_frame.get() != NULL); | |
| 836 | |
| 837 const char bytes[] = "this is a test test test test test!"; | |
| 838 scoped_ptr<SpdyFrame> send_frame( | |
| 839 send_framer.CreateDataFrame( | |
| 840 1, bytes, arraysize(bytes), | |
| 841 DATA_FLAG_FIN)); | |
| 842 EXPECT_TRUE(send_frame.get() != NULL); | |
| 843 | |
| 844 // Run the inputs through the framer. | |
| 845 TestSpdyVisitor visitor; | |
| 846 visitor.use_compression_ = true; | |
| 847 const unsigned char* data; | |
| 848 data = reinterpret_cast<const unsigned char*>(syn_frame->data()); | |
| 849 visitor.SimulateInFramer(data, syn_frame->length() + SpdyFrame::kHeaderSize); | |
| 850 data = reinterpret_cast<const unsigned char*>(send_frame->data()); | |
| 851 visitor.SimulateInFramer(data, send_frame->length() + SpdyFrame::kHeaderSize); | |
| 852 | |
| 853 EXPECT_EQ(0, visitor.error_count_); | |
| 854 EXPECT_EQ(1, visitor.syn_frame_count_); | |
| 855 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
| 856 EXPECT_EQ(0, visitor.headers_frame_count_); | |
| 857 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); | |
| 858 EXPECT_EQ(0, visitor.fin_frame_count_); | |
| 859 EXPECT_EQ(0, visitor.fin_flag_count_); | |
| 860 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); | |
| 861 EXPECT_EQ(1, visitor.data_frame_count_); | |
| 862 | |
| 863 // We closed the streams, so all compressors should be down. | |
| 864 EXPECT_EQ(0, visitor.framer_.num_stream_compressors()); | |
| 865 EXPECT_EQ(0, visitor.framer_.num_stream_decompressors()); | |
| 866 EXPECT_EQ(0, send_framer.num_stream_compressors()); | |
| 867 EXPECT_EQ(0, send_framer.num_stream_decompressors()); | |
| 868 } | |
| 869 | |
| 870 TEST_F(SpdyFramerTest, WindowUpdateFrame) { | |
| 871 scoped_ptr<SpdyWindowUpdateControlFrame> window_update_frame( | |
| 872 SpdyFramer::CreateWindowUpdate(1, 0x12345678)); | |
| 873 | |
| 874 const unsigned char expected_data_frame[] = { | |
| 875 0x80, 0x02, 0x00, 0x09, | |
| 876 0x00, 0x00, 0x00, 0x08, | |
| 877 0x00, 0x00, 0x00, 0x01, | |
| 878 0x12, 0x34, 0x56, 0x78 | |
| 879 }; | |
| 880 | |
| 881 EXPECT_EQ(16u, window_update_frame->size()); | |
| 882 EXPECT_EQ(0, | |
| 883 memcmp(window_update_frame->data(), expected_data_frame, 16)); | |
| 884 } | |
| 885 | |
| 886 TEST_F(SpdyFramerTest, CreateDataFrame) { | |
| 887 SpdyFramer framer; | |
| 888 | |
| 889 { | |
| 890 const char kDescription[] = "'hello' data frame, no FIN"; | |
| 891 const unsigned char kFrameData[] = { | |
| 892 0x00, 0x00, 0x00, 0x01, | |
| 893 0x00, 0x00, 0x00, 0x05, | |
| 894 'h', 'e', 'l', 'l', | |
| 895 'o' | |
| 896 }; | |
| 897 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
| 898 1, "hello", 5, DATA_FLAG_NONE)); | |
| 899 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 900 } | |
| 901 | |
| 902 { | |
| 903 const char kDescription[] = "Data frame with negative data byte, no FIN"; | |
| 904 const unsigned char kFrameData[] = { | |
| 905 0x00, 0x00, 0x00, 0x01, | |
| 906 0x00, 0x00, 0x00, 0x01, | |
| 907 0xff | |
| 908 }; | |
| 909 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
| 910 1, "\xff", 1, DATA_FLAG_NONE)); | |
| 911 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 912 } | |
| 913 | |
| 914 { | |
| 915 const char kDescription[] = "'hello' data frame, with FIN"; | |
| 916 const unsigned char kFrameData[] = { | |
| 917 0x00, 0x00, 0x00, 0x01, | |
| 918 0x01, 0x00, 0x00, 0x05, | |
| 919 'h', 'e', 'l', 'l', | |
| 920 'o' | |
| 921 }; | |
| 922 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
| 923 1, "hello", 5, DATA_FLAG_FIN)); | |
| 924 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 925 } | |
| 926 | |
| 927 { | |
| 928 const char kDescription[] = "Empty data frame"; | |
| 929 const unsigned char kFrameData[] = { | |
| 930 0x00, 0x00, 0x00, 0x01, | |
| 931 0x00, 0x00, 0x00, 0x00, | |
| 932 }; | |
| 933 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
| 934 1, "", 0, DATA_FLAG_NONE)); | |
| 935 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 936 } | |
| 937 | |
| 938 { | |
| 939 const char kDescription[] = "Data frame with max stream ID"; | |
| 940 const unsigned char kFrameData[] = { | |
| 941 0x7f, 0xff, 0xff, 0xff, | |
| 942 0x01, 0x00, 0x00, 0x05, | |
| 943 'h', 'e', 'l', 'l', | |
| 944 'o' | |
| 945 }; | |
| 946 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
| 947 0x7fffffff, "hello", 5, DATA_FLAG_FIN)); | |
| 948 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 949 } | |
| 950 | |
| 951 { | |
| 952 const char kDescription[] = "Large data frame"; | |
| 953 const int kDataSize = 4 * 1024 * 1024; // 4 MB | |
| 954 const std::string kData(kDataSize, 'A'); | |
| 955 const unsigned char kFrameHeader[] = { | |
| 956 0x00, 0x00, 0x00, 0x01, | |
| 957 0x01, 0x40, 0x00, 0x00, | |
| 958 }; | |
| 959 | |
| 960 const int kFrameSize = arraysize(kFrameHeader) + kDataSize; | |
| 961 scoped_array<unsigned char> expected_frame_data( | |
| 962 new unsigned char[kFrameSize]); | |
| 963 memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader)); | |
| 964 memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize); | |
| 965 | |
| 966 scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( | |
| 967 1, kData.data(), kData.size(), DATA_FLAG_FIN)); | |
| 968 CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize); | |
| 969 } | |
| 970 } | |
| 971 | |
| 972 TEST_F(SpdyFramerTest, CreateSynStreamUncompressed) { | |
| 973 SpdyFramer framer; | |
| 974 framer.set_enable_compression(false); | |
| 975 | |
| 976 { | |
| 977 const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN"; | |
| 978 | |
| 979 SpdyHeaderBlock headers; | |
| 980 headers["bar"] = "foo"; | |
| 981 headers["foo"] = "bar"; | |
| 982 | |
| 983 const unsigned char kFrameData[] = { | |
| 984 0x80, 0x02, 0x00, 0x01, | |
| 985 0x00, 0x00, 0x00, 0x20, | |
| 986 0x00, 0x00, 0x00, 0x01, | |
| 987 0x00, 0x00, 0x00, 0x00, | |
| 988 0xC0, 0x00, 0x00, 0x02, | |
| 989 0x00, 0x03, 'b', 'a', | |
| 990 'r', 0x00, 0x03, 'f', | |
| 991 'o', 'o', 0x00, 0x03, | |
| 992 'f', 'o', 'o', 0x00, | |
| 993 0x03, 'b', 'a', 'r' | |
| 994 }; | |
| 995 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( | |
| 996 1, 0, SPDY_PRIORITY_LOWEST, CONTROL_FLAG_NONE, | |
| 997 false, &headers)); | |
| 998 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 999 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId( | |
| 1000 reinterpret_cast<const SpdyControlFrame*>(frame.get()))); | |
| 1001 } | |
| 1002 | |
| 1003 { | |
| 1004 const char kDescription[] = | |
| 1005 "SYN_STREAM frame with a 0-length header name, highest pri, FIN, " | |
| 1006 "max stream ID"; | |
| 1007 | |
| 1008 SpdyHeaderBlock headers; | |
| 1009 headers[""] = "foo"; | |
| 1010 headers["foo"] = "bar"; | |
| 1011 | |
| 1012 const unsigned char kFrameData[] = { | |
| 1013 0x80, 0x02, 0x00, 0x01, | |
| 1014 0x01, 0x00, 0x00, 0x1D, | |
| 1015 0x7f, 0xff, 0xff, 0xff, | |
| 1016 0x7f, 0xff, 0xff, 0xff, | |
| 1017 0x00, 0x00, 0x00, 0x02, | |
| 1018 0x00, 0x00, 0x00, 0x03, | |
| 1019 'f', 'o', 'o', 0x00, | |
| 1020 0x03, 'f', 'o', 'o', | |
| 1021 0x00, 0x03, 'b', 'a', | |
| 1022 'r' | |
| 1023 }; | |
| 1024 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( | |
| 1025 0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN, | |
| 1026 false, &headers)); | |
| 1027 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1028 } | |
| 1029 | |
| 1030 { | |
| 1031 const char kDescription[] = | |
| 1032 "SYN_STREAM frame with a 0-length header val, highest pri, FIN, " | |
| 1033 "max stream ID"; | |
| 1034 | |
| 1035 SpdyHeaderBlock headers; | |
| 1036 headers["bar"] = "foo"; | |
| 1037 headers["foo"] = ""; | |
| 1038 | |
| 1039 const unsigned char kFrameData[] = { | |
| 1040 0x80, 0x02, 0x00, 0x01, | |
| 1041 0x01, 0x00, 0x00, 0x1D, | |
| 1042 0x7f, 0xff, 0xff, 0xff, | |
| 1043 0x7f, 0xff, 0xff, 0xff, | |
| 1044 0x00, 0x00, 0x00, 0x02, | |
| 1045 0x00, 0x03, 'b', 'a', | |
| 1046 'r', 0x00, 0x03, 'f', | |
| 1047 'o', 'o', 0x00, 0x03, | |
| 1048 'f', 'o', 'o', 0x00, | |
| 1049 0x00 | |
| 1050 }; | |
| 1051 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( | |
| 1052 0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN, | |
| 1053 false, &headers)); | |
| 1054 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1055 } | |
| 1056 } | |
| 1057 | |
| 1058 TEST_F(SpdyFramerTest, CreateSynStreamCompressed) { | |
| 1059 SpdyFramer framer; | |
| 1060 framer.set_enable_compression(true); | |
| 1061 | |
| 1062 { | |
| 1063 const char kDescription[] = | |
| 1064 "SYN_STREAM frame, lowest pri, no FIN"; | |
| 1065 | |
| 1066 SpdyHeaderBlock headers; | |
| 1067 headers["bar"] = "foo"; | |
| 1068 headers["foo"] = "bar"; | |
| 1069 | |
| 1070 const unsigned char kFrameData[] = { | |
| 1071 0x80, 0x02, 0x00, 0x01, | |
| 1072 0x00, 0x00, 0x00, 0x25, | |
| 1073 0x00, 0x00, 0x00, 0x01, | |
| 1074 0x00, 0x00, 0x00, 0x00, | |
| 1075 0xC0, 0x00, 0x38, 0xea, | |
| 1076 0xdf, 0xa2, 0x51, 0xb2, | |
| 1077 0x62, 0x60, 0x62, 0x60, | |
| 1078 0x4e, 0x4a, 0x2c, 0x62, | |
| 1079 0x60, 0x4e, 0xcb, 0xcf, | |
| 1080 0x87, 0x12, 0x40, 0x2e, | |
| 1081 0x00, 0x00, 0x00, 0xff, | |
| 1082 0xff | |
| 1083 }; | |
| 1084 scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( | |
| 1085 1, 0, SPDY_PRIORITY_LOWEST, CONTROL_FLAG_NONE, | |
| 1086 true, &headers)); | |
| 1087 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1088 } | |
| 1089 } | |
| 1090 | |
| 1091 TEST_F(SpdyFramerTest, CreateSynReplyUncompressed) { | |
| 1092 SpdyFramer framer; | |
| 1093 framer.set_enable_compression(false); | |
| 1094 | |
| 1095 { | |
| 1096 const char kDescription[] = "SYN_REPLY frame, no FIN"; | |
| 1097 | |
| 1098 SpdyHeaderBlock headers; | |
| 1099 headers["bar"] = "foo"; | |
| 1100 headers["foo"] = "bar"; | |
| 1101 | |
| 1102 const unsigned char kFrameData[] = { | |
| 1103 0x80, 0x02, 0x00, 0x02, | |
| 1104 0x00, 0x00, 0x00, 0x1C, | |
| 1105 0x00, 0x00, 0x00, 0x01, | |
| 1106 0x00, 0x00, 0x00, 0x02, | |
| 1107 0x00, 0x03, 'b', 'a', | |
| 1108 'r', 0x00, 0x03, 'f', | |
| 1109 'o', 'o', 0x00, 0x03, | |
| 1110 'f', 'o', 'o', 0x00, | |
| 1111 0x03, 'b', 'a', 'r' | |
| 1112 }; | |
| 1113 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( | |
| 1114 1, CONTROL_FLAG_NONE, false, &headers)); | |
| 1115 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1116 } | |
| 1117 | |
| 1118 { | |
| 1119 const char kDescription[] = | |
| 1120 "SYN_REPLY frame with a 0-length header name, FIN, max stream ID"; | |
| 1121 | |
| 1122 SpdyHeaderBlock headers; | |
| 1123 headers[""] = "foo"; | |
| 1124 headers["foo"] = "bar"; | |
| 1125 | |
| 1126 const unsigned char kFrameData[] = { | |
| 1127 0x80, 0x02, 0x00, 0x02, | |
| 1128 0x01, 0x00, 0x00, 0x19, | |
| 1129 0x7f, 0xff, 0xff, 0xff, | |
| 1130 0x00, 0x00, 0x00, 0x02, | |
| 1131 0x00, 0x00, 0x00, 0x03, | |
| 1132 'f', 'o', 'o', 0x00, | |
| 1133 0x03, 'f', 'o', 'o', | |
| 1134 0x00, 0x03, 'b', 'a', | |
| 1135 'r' | |
| 1136 }; | |
| 1137 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( | |
| 1138 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); | |
| 1139 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1140 } | |
| 1141 | |
| 1142 { | |
| 1143 const char kDescription[] = | |
| 1144 "SYN_REPLY frame with a 0-length header val, FIN, max stream ID"; | |
| 1145 | |
| 1146 SpdyHeaderBlock headers; | |
| 1147 headers["bar"] = "foo"; | |
| 1148 headers["foo"] = ""; | |
| 1149 | |
| 1150 const unsigned char kFrameData[] = { | |
| 1151 0x80, 0x02, 0x00, 0x02, | |
| 1152 0x01, 0x00, 0x00, 0x19, | |
| 1153 0x7f, 0xff, 0xff, 0xff, | |
| 1154 0x00, 0x00, 0x00, 0x02, | |
| 1155 0x00, 0x03, 'b', 'a', | |
| 1156 'r', 0x00, 0x03, 'f', | |
| 1157 'o', 'o', 0x00, 0x03, | |
| 1158 'f', 'o', 'o', 0x00, | |
| 1159 0x00 | |
| 1160 }; | |
| 1161 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( | |
| 1162 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); | |
| 1163 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1164 } | |
| 1165 } | |
| 1166 | |
| 1167 TEST_F(SpdyFramerTest, CreateSynReplyCompressed) { | |
| 1168 SpdyFramer framer; | |
| 1169 framer.set_enable_compression(true); | |
| 1170 | |
| 1171 { | |
| 1172 const char kDescription[] = "SYN_REPLY frame, no FIN"; | |
| 1173 | |
| 1174 SpdyHeaderBlock headers; | |
| 1175 headers["bar"] = "foo"; | |
| 1176 headers["foo"] = "bar"; | |
| 1177 | |
| 1178 const unsigned char kFrameData[] = { | |
| 1179 0x80, 0x02, 0x00, 0x02, | |
| 1180 0x00, 0x00, 0x00, 0x21, | |
| 1181 0x00, 0x00, 0x00, 0x01, | |
| 1182 0x00, 0x00, 0x38, 0xea, | |
| 1183 0xdf, 0xa2, 0x51, 0xb2, | |
| 1184 0x62, 0x60, 0x62, 0x60, | |
| 1185 0x4e, 0x4a, 0x2c, 0x62, | |
| 1186 0x60, 0x4e, 0xcb, 0xcf, | |
| 1187 0x87, 0x12, 0x40, 0x2e, | |
| 1188 0x00, 0x00, 0x00, 0xff, | |
| 1189 0xff | |
| 1190 }; | |
| 1191 scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( | |
| 1192 1, CONTROL_FLAG_NONE, true, &headers)); | |
| 1193 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1194 } | |
| 1195 } | |
| 1196 | |
| 1197 TEST_F(SpdyFramerTest, CreateRstStream) { | |
| 1198 SpdyFramer framer; | |
| 1199 | |
| 1200 { | |
| 1201 const char kDescription[] = "RST_STREAM frame"; | |
| 1202 const unsigned char kFrameData[] = { | |
| 1203 0x80, 0x02, 0x00, 0x03, | |
| 1204 0x00, 0x00, 0x00, 0x08, | |
| 1205 0x00, 0x00, 0x00, 0x01, | |
| 1206 0x00, 0x00, 0x00, 0x01, | |
| 1207 }; | |
| 1208 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(1, PROTOCOL_ERROR)); | |
| 1209 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1210 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId( | |
| 1211 reinterpret_cast<const SpdyControlFrame*>(frame.get()))); | |
| 1212 } | |
| 1213 | |
| 1214 { | |
| 1215 const char kDescription[] = "RST_STREAM frame with max stream ID"; | |
| 1216 const unsigned char kFrameData[] = { | |
| 1217 0x80, 0x02, 0x00, 0x03, | |
| 1218 0x00, 0x00, 0x00, 0x08, | |
| 1219 0x7f, 0xff, 0xff, 0xff, | |
| 1220 0x00, 0x00, 0x00, 0x01, | |
| 1221 }; | |
| 1222 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF, | |
| 1223 PROTOCOL_ERROR)); | |
| 1224 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1225 } | |
| 1226 | |
| 1227 { | |
| 1228 const char kDescription[] = "RST_STREAM frame with max status code"; | |
| 1229 const unsigned char kFrameData[] = { | |
| 1230 0x80, 0x02, 0x00, 0x03, | |
| 1231 0x00, 0x00, 0x00, 0x08, | |
| 1232 0x7f, 0xff, 0xff, 0xff, | |
| 1233 0x00, 0x00, 0x00, 0x06, | |
| 1234 }; | |
| 1235 scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF, | |
| 1236 INTERNAL_ERROR)); | |
| 1237 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1238 } | |
| 1239 } | |
| 1240 | |
| 1241 TEST_F(SpdyFramerTest, CreateSettings) { | |
| 1242 SpdyFramer framer; | |
| 1243 | |
| 1244 { | |
| 1245 const char kDescription[] = "Basic SETTINGS frame"; | |
| 1246 | |
| 1247 SpdySettings settings; | |
| 1248 settings.push_back(SpdySetting(0x00000000, 0x00000000)); | |
| 1249 settings.push_back(SpdySetting(0xffffffff, 0x00000001)); | |
| 1250 settings.push_back(SpdySetting(0xff000001, 0x00000002)); | |
| 1251 | |
| 1252 // Duplicates allowed | |
| 1253 settings.push_back(SpdySetting(0x01000002, 0x00000003)); | |
| 1254 settings.push_back(SpdySetting(0x01000002, 0x00000003)); | |
| 1255 | |
| 1256 settings.push_back(SpdySetting(0x01000003, 0x000000ff)); | |
| 1257 settings.push_back(SpdySetting(0x01000004, 0xff000001)); | |
| 1258 settings.push_back(SpdySetting(0x01000004, 0xffffffff)); | |
| 1259 | |
| 1260 const unsigned char kFrameData[] = { | |
| 1261 0x80, 0x02, 0x00, 0x04, | |
| 1262 0x00, 0x00, 0x00, 0x44, | |
| 1263 0x00, 0x00, 0x00, 0x08, | |
| 1264 0x00, 0x00, 0x00, 0x00, | |
| 1265 0x00, 0x00, 0x00, 0x00, | |
| 1266 0xff, 0xff, 0xff, 0xff, | |
| 1267 0x00, 0x00, 0x00, 0x01, | |
| 1268 0xff, 0x00, 0x00, 0x01, | |
| 1269 0x00, 0x00, 0x00, 0x02, | |
| 1270 0x01, 0x00, 0x00, 0x02, | |
| 1271 0x00, 0x00, 0x00, 0x03, | |
| 1272 0x01, 0x00, 0x00, 0x02, | |
| 1273 0x00, 0x00, 0x00, 0x03, | |
| 1274 0x01, 0x00, 0x00, 0x03, | |
| 1275 0x00, 0x00, 0x00, 0xff, | |
| 1276 0x01, 0x00, 0x00, 0x04, | |
| 1277 0xff, 0x00, 0x00, 0x01, | |
| 1278 0x01, 0x00, 0x00, 0x04, | |
| 1279 0xff, 0xff, 0xff, 0xff, | |
| 1280 }; | |
| 1281 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); | |
| 1282 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1283 EXPECT_EQ(SpdyFramer::kInvalidStream, | |
| 1284 SpdyFramer::GetControlFrameStreamId( | |
| 1285 reinterpret_cast<const SpdyControlFrame*>(frame.get()))); | |
| 1286 } | |
| 1287 | |
| 1288 { | |
| 1289 const char kDescription[] = "Empty SETTINGS frame"; | |
| 1290 | |
| 1291 SpdySettings settings; | |
| 1292 | |
| 1293 const unsigned char kFrameData[] = { | |
| 1294 0x80, 0x02, 0x00, 0x04, | |
| 1295 0x00, 0x00, 0x00, 0x04, | |
| 1296 0x00, 0x00, 0x00, 0x00, | |
| 1297 }; | |
| 1298 scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); | |
| 1299 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1300 } | |
| 1301 } | |
| 1302 | |
| 1303 TEST_F(SpdyFramerTest, CreateNopFrame) { | |
| 1304 SpdyFramer framer; | |
| 1305 | |
| 1306 { | |
| 1307 const char kDescription[] = "NOOP frame"; | |
| 1308 const unsigned char kFrameData[] = { | |
| 1309 0x80, 0x02, 0x00, 0x05, | |
| 1310 0x00, 0x00, 0x00, 0x00, | |
| 1311 }; | |
| 1312 scoped_ptr<SpdyFrame> frame(framer.CreateNopFrame()); | |
| 1313 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1314 EXPECT_EQ(SpdyFramer::kInvalidStream, | |
| 1315 SpdyFramer::GetControlFrameStreamId( | |
| 1316 reinterpret_cast<const SpdyControlFrame*>(frame.get()))); | |
| 1317 } | |
| 1318 } | |
| 1319 | |
| 1320 TEST_F(SpdyFramerTest, CreatePingFrame) { | |
| 1321 SpdyFramer framer; | |
| 1322 | |
| 1323 { | |
| 1324 const char kDescription[] = "PING frame"; | |
| 1325 const unsigned char kFrameData[] = { | |
| 1326 0x80, 0x02, 0x00, 0x06, | |
| 1327 0x00, 0x00, 0x00, 0x04, | |
| 1328 0x12, 0x34, 0x56, 0x78, | |
| 1329 }; | |
| 1330 scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(0x12345678u)); | |
| 1331 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1332 EXPECT_EQ(SpdyFramer::kInvalidStream, | |
| 1333 SpdyFramer::GetControlFrameStreamId( | |
| 1334 reinterpret_cast<const SpdyControlFrame*>(frame.get()))); | |
| 1335 } | |
| 1336 } | |
| 1337 | |
| 1338 TEST_F(SpdyFramerTest, CreateGoAway) { | |
| 1339 SpdyFramer framer; | |
| 1340 | |
| 1341 { | |
| 1342 const char kDescription[] = "GOAWAY frame"; | |
| 1343 const unsigned char kFrameData[] = { | |
| 1344 0x80, 0x02, 0x00, 0x07, | |
| 1345 0x00, 0x00, 0x00, 0x04, | |
| 1346 0x00, 0x00, 0x00, 0x00, | |
| 1347 }; | |
| 1348 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0)); | |
| 1349 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1350 EXPECT_EQ(SpdyFramer::kInvalidStream, | |
| 1351 SpdyFramer::GetControlFrameStreamId( | |
| 1352 reinterpret_cast<const SpdyControlFrame*>(frame.get()))); | |
| 1353 } | |
| 1354 | |
| 1355 { | |
| 1356 const char kDescription[] = "GOAWAY frame with max stream ID"; | |
| 1357 const unsigned char kFrameData[] = { | |
| 1358 0x80, 0x02, 0x00, 0x07, | |
| 1359 0x00, 0x00, 0x00, 0x04, | |
| 1360 0x7f, 0xff, 0xff, 0xff, | |
| 1361 }; | |
| 1362 scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF)); | |
| 1363 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1364 } | |
| 1365 } | |
| 1366 | |
| 1367 TEST_F(SpdyFramerTest, CreateHeadersUncompressed) { | |
| 1368 SpdyFramer framer; | |
| 1369 framer.set_enable_compression(false); | |
| 1370 | |
| 1371 { | |
| 1372 const char kDescription[] = "HEADERS frame, no FIN"; | |
| 1373 | |
| 1374 SpdyHeaderBlock headers; | |
| 1375 headers["bar"] = "foo"; | |
| 1376 headers["foo"] = "bar"; | |
| 1377 | |
| 1378 const unsigned char kFrameData[] = { | |
| 1379 0x80, 0x02, 0x00, 0x08, | |
| 1380 0x00, 0x00, 0x00, 0x1C, | |
| 1381 0x00, 0x00, 0x00, 0x01, | |
| 1382 0x00, 0x00, 0x00, 0x02, | |
| 1383 0x00, 0x03, 'b', 'a', | |
| 1384 'r', 0x00, 0x03, 'f', | |
| 1385 'o', 'o', 0x00, 0x03, | |
| 1386 'f', 'o', 'o', 0x00, | |
| 1387 0x03, 'b', 'a', 'r' | |
| 1388 }; | |
| 1389 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( | |
| 1390 1, CONTROL_FLAG_NONE, false, &headers)); | |
| 1391 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1392 } | |
| 1393 | |
| 1394 { | |
| 1395 const char kDescription[] = | |
| 1396 "HEADERS frame with a 0-length header name, FIN, max stream ID"; | |
| 1397 | |
| 1398 SpdyHeaderBlock headers; | |
| 1399 headers[""] = "foo"; | |
| 1400 headers["foo"] = "bar"; | |
| 1401 | |
| 1402 const unsigned char kFrameData[] = { | |
| 1403 0x80, 0x02, 0x00, 0x08, | |
| 1404 0x01, 0x00, 0x00, 0x19, | |
| 1405 0x7f, 0xff, 0xff, 0xff, | |
| 1406 0x00, 0x00, 0x00, 0x02, | |
| 1407 0x00, 0x00, 0x00, 0x03, | |
| 1408 'f', 'o', 'o', 0x00, | |
| 1409 0x03, 'f', 'o', 'o', | |
| 1410 0x00, 0x03, 'b', 'a', | |
| 1411 'r' | |
| 1412 }; | |
| 1413 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( | |
| 1414 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); | |
| 1415 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1416 } | |
| 1417 | |
| 1418 { | |
| 1419 const char kDescription[] = | |
| 1420 "HEADERS frame with a 0-length header val, FIN, max stream ID"; | |
| 1421 | |
| 1422 SpdyHeaderBlock headers; | |
| 1423 headers["bar"] = "foo"; | |
| 1424 headers["foo"] = ""; | |
| 1425 | |
| 1426 const unsigned char kFrameData[] = { | |
| 1427 0x80, 0x02, 0x00, 0x08, | |
| 1428 0x01, 0x00, 0x00, 0x19, | |
| 1429 0x7f, 0xff, 0xff, 0xff, | |
| 1430 0x00, 0x00, 0x00, 0x02, | |
| 1431 0x00, 0x03, 'b', 'a', | |
| 1432 'r', 0x00, 0x03, 'f', | |
| 1433 'o', 'o', 0x00, 0x03, | |
| 1434 'f', 'o', 'o', 0x00, | |
| 1435 0x00 | |
| 1436 }; | |
| 1437 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( | |
| 1438 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); | |
| 1439 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1440 } | |
| 1441 } | |
| 1442 | |
| 1443 TEST_F(SpdyFramerTest, CreateHeadersCompressed) { | |
| 1444 SpdyFramer framer; | |
| 1445 framer.set_enable_compression(true); | |
| 1446 | |
| 1447 { | |
| 1448 const char kDescription[] = "HEADERS frame, no FIN"; | |
| 1449 | |
| 1450 SpdyHeaderBlock headers; | |
| 1451 headers["bar"] = "foo"; | |
| 1452 headers["foo"] = "bar"; | |
| 1453 | |
| 1454 const unsigned char kFrameData[] = { | |
| 1455 0x80, 0x02, 0x00, 0x08, | |
| 1456 0x00, 0x00, 0x00, 0x21, | |
| 1457 0x00, 0x00, 0x00, 0x01, | |
| 1458 0x00, 0x00, 0x38, 0xea, | |
| 1459 0xdf, 0xa2, 0x51, 0xb2, | |
| 1460 0x62, 0x60, 0x62, 0x60, | |
| 1461 0x4e, 0x4a, 0x2c, 0x62, | |
| 1462 0x60, 0x4e, 0xcb, 0xcf, | |
| 1463 0x87, 0x12, 0x40, 0x2e, | |
| 1464 0x00, 0x00, 0x00, 0xff, | |
| 1465 0xff | |
| 1466 }; | |
| 1467 scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( | |
| 1468 1, CONTROL_FLAG_NONE, true, &headers)); | |
| 1469 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1470 } | |
| 1471 } | |
| 1472 | |
| 1473 TEST_F(SpdyFramerTest, CreateWindowUpdate) { | |
| 1474 SpdyFramer framer; | |
| 1475 | |
| 1476 { | |
| 1477 const char kDescription[] = "WINDOW_UPDATE frame"; | |
| 1478 const unsigned char kFrameData[] = { | |
| 1479 0x80, 0x02, 0x00, 0x09, | |
| 1480 0x00, 0x00, 0x00, 0x08, | |
| 1481 0x00, 0x00, 0x00, 0x01, | |
| 1482 0x00, 0x00, 0x00, 0x01, | |
| 1483 }; | |
| 1484 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 1)); | |
| 1485 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1486 EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId( | |
| 1487 reinterpret_cast<const SpdyControlFrame*>(frame.get()))); | |
| 1488 } | |
| 1489 | |
| 1490 { | |
| 1491 const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; | |
| 1492 const unsigned char kFrameData[] = { | |
| 1493 0x80, 0x02, 0x00, 0x09, | |
| 1494 0x00, 0x00, 0x00, 0x08, | |
| 1495 0x7f, 0xff, 0xff, 0xff, | |
| 1496 0x00, 0x00, 0x00, 0x01, | |
| 1497 }; | |
| 1498 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1)); | |
| 1499 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1500 } | |
| 1501 | |
| 1502 { | |
| 1503 const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; | |
| 1504 const unsigned char kFrameData[] = { | |
| 1505 0x80, 0x02, 0x00, 0x09, | |
| 1506 0x00, 0x00, 0x00, 0x08, | |
| 1507 0x00, 0x00, 0x00, 0x01, | |
| 1508 0x7f, 0xff, 0xff, 0xff, | |
| 1509 }; | |
| 1510 scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF)); | |
| 1511 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1512 } | |
| 1513 } | |
| 1514 | |
| 1515 TEST_F(SpdyFramerTest, CreateCredential) { | |
| 1516 SpdyFramer framer; | |
| 1517 | |
| 1518 { | |
| 1519 const char kDescription[] = "CREDENTIAL frame"; | |
| 1520 const unsigned char kFrameData[] = { | |
| 1521 0x80, 0x02, 0x00, 0x0A, | |
| 1522 0x00, 0x00, 0x00, 0x33, | |
| 1523 0x00, 0x03, 0x00, 0x00, | |
| 1524 0x00, 0x05, 'p', 'r', | |
| 1525 'o', 'o', 'f', 0x00, | |
| 1526 0x00, 0x00, 0x06, 'a', | |
| 1527 ' ', 'c', 'e', 'r', | |
| 1528 't', 0x00, 0x00, 0x00, | |
| 1529 0x0C, 'a', 'n', 'o', | |
| 1530 't', 'h', 'e', 'r', | |
| 1531 ' ', 'c', 'e', 'r', | |
| 1532 't', 0x00, 0x00, 0x00, | |
| 1533 0x0A, 'f', 'i', 'n', | |
| 1534 'a', 'l', ' ', 'c', | |
| 1535 'e', 'r', 't', | |
| 1536 }; | |
| 1537 SpdyCredential credential; | |
| 1538 credential.slot = 3; | |
| 1539 credential.proof = "proof"; | |
| 1540 credential.certs.push_back("a cert"); | |
| 1541 credential.certs.push_back("another cert"); | |
| 1542 credential.certs.push_back("final cert"); | |
| 1543 scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential)); | |
| 1544 CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); | |
| 1545 } | |
| 1546 } | |
| 1547 | |
| 1548 TEST_F(SpdyFramerTest, ParseCredentialFrame) { | |
| 1549 SpdyFramer framer; | |
| 1550 | |
| 1551 { | |
| 1552 unsigned char kFrameData[] = { | |
| 1553 0x80, 0x02, 0x00, 0x0A, | |
| 1554 0x00, 0x00, 0x00, 0x33, | |
| 1555 0x00, 0x03, 0x00, 0x00, | |
| 1556 0x00, 0x05, 'p', 'r', | |
| 1557 'o', 'o', 'f', 0x00, | |
| 1558 0x00, 0x00, 0x06, 'a', | |
| 1559 ' ', 'c', 'e', 'r', | |
| 1560 't', 0x00, 0x00, 0x00, | |
| 1561 0x0C, 'a', 'n', 'o', | |
| 1562 't', 'h', 'e', 'r', | |
| 1563 ' ', 'c', 'e', 'r', | |
| 1564 't', 0x00, 0x00, 0x00, | |
| 1565 0x0A, 'f', 'i', 'n', | |
| 1566 'a', 'l', ' ', 'c', | |
| 1567 'e', 'r', 't', | |
| 1568 }; | |
| 1569 SpdyCredentialControlFrame frame(reinterpret_cast<char*>(kFrameData), | |
| 1570 false); | |
| 1571 SpdyCredential credential; | |
| 1572 EXPECT_TRUE(SpdyFramer::ParseCredentialData(frame.payload(), | |
| 1573 frame.length(), | |
| 1574 &credential)); | |
| 1575 EXPECT_EQ(3u, credential.slot); | |
| 1576 EXPECT_EQ("proof", credential.proof); | |
| 1577 EXPECT_EQ("a cert", credential.certs.front()); | |
| 1578 credential.certs.erase(credential.certs.begin()); | |
| 1579 EXPECT_EQ("another cert", credential.certs.front()); | |
| 1580 credential.certs.erase(credential.certs.begin()); | |
| 1581 EXPECT_EQ("final cert", credential.certs.front()); | |
| 1582 credential.certs.erase(credential.certs.begin()); | |
| 1583 EXPECT_TRUE(credential.certs.empty()); | |
| 1584 } | |
| 1585 } | |
| 1586 | |
| 1587 TEST_F(SpdyFramerTest, DuplicateFrame) { | |
| 1588 SpdyFramer framer; | |
| 1589 | |
| 1590 { | |
| 1591 const char kDescription[] = "PING frame"; | |
| 1592 const unsigned char kFrameData[] = { | |
| 1593 0x80, 0x02, 0x00, 0x06, | |
| 1594 0x00, 0x00, 0x00, 0x04, | |
| 1595 0x12, 0x34, 0x56, 0x78, | |
| 1596 }; | |
| 1597 scoped_ptr<SpdyFrame> frame1(framer.CreatePingFrame(0x12345678u)); | |
| 1598 CompareFrame(kDescription, *frame1, kFrameData, arraysize(kFrameData)); | |
| 1599 | |
| 1600 scoped_ptr<SpdyFrame> frame2(framer.DuplicateFrame(*frame1)); | |
| 1601 CompareFrame(kDescription, *frame2, kFrameData, arraysize(kFrameData)); | |
| 1602 } | |
| 1603 } | |
| 1604 | |
| 1605 // This test case reproduces conditions that caused ExpandControlFrameBuffer to | |
| 1606 // fail to expand the buffer control frame buffer when it should have, allowing | |
| 1607 // the framer to overrun the buffer, and smash other heap contents. This test | |
| 1608 // relies on the debug version of the heap manager, which checks for buffer | |
| 1609 // overrun errors during delete processing. Regression test for b/2974814. | |
| 1610 TEST_F(SpdyFramerTest, ExpandBuffer_HeapSmash) { | |
| 1611 // Sweep through the area of problematic values, to make sure we always cover | |
| 1612 // the danger zone, even if it moves around at bit due to SPDY changes. | |
| 1613 for (uint16 val2_len = SpdyFramer::kControlFrameBufferInitialSize - 50; | |
| 1614 val2_len < SpdyFramer::kControlFrameBufferInitialSize; | |
| 1615 val2_len++) { | |
| 1616 std::string val2 = std::string(val2_len, 'a'); | |
| 1617 SpdyHeaderBlock headers; | |
| 1618 headers["bar"] = "foo"; | |
| 1619 headers["foo"] = "baz"; | |
| 1620 headers["grue"] = val2.c_str(); | |
| 1621 SpdyFramer framer; | |
| 1622 scoped_ptr<SpdySynStreamControlFrame> template_frame( | |
| 1623 framer.CreateSynStream(1, // stream_id | |
| 1624 0, // associated_stream_id | |
| 1625 1, // priority | |
| 1626 CONTROL_FLAG_NONE, | |
| 1627 false, // compress | |
| 1628 &headers)); | |
| 1629 EXPECT_TRUE(template_frame.get() != NULL); | |
| 1630 TestSpdyVisitor visitor; | |
| 1631 visitor.SimulateInFramer( | |
| 1632 reinterpret_cast<unsigned char*>(template_frame.get()->data()), | |
| 1633 template_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
| 1634 EXPECT_EQ(1, visitor.syn_frame_count_); | |
| 1635 } | |
| 1636 } | |
| 1637 | |
| 1638 TEST_F(SpdyFramerTest, ReadCredentialFrame) { | |
| 1639 SpdyCredential credential; | |
| 1640 credential.slot = 3; | |
| 1641 credential.proof = "proof"; | |
| 1642 credential.certs.push_back("a cert"); | |
| 1643 credential.certs.push_back("another cert"); | |
| 1644 credential.certs.push_back("final cert"); | |
| 1645 SpdyFramer framer; | |
| 1646 scoped_ptr<SpdyFrame> control_frame( | |
| 1647 framer.CreateCredentialFrame(credential)); | |
| 1648 EXPECT_TRUE(control_frame.get() != NULL); | |
| 1649 TestSpdyVisitor visitor; | |
| 1650 visitor.use_compression_ = false; | |
| 1651 visitor.SimulateInFramer( | |
| 1652 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
| 1653 control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
| 1654 EXPECT_EQ(0, visitor.error_count_); | |
| 1655 EXPECT_EQ(1, visitor.credential_count_); | |
| 1656 EXPECT_EQ(control_frame->length(), visitor.credential_buffer_length_); | |
| 1657 EXPECT_EQ(credential.slot, visitor.credential_.slot); | |
| 1658 EXPECT_EQ(credential.proof, visitor.credential_.proof); | |
| 1659 EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size()); | |
| 1660 for (size_t i = 0; i < credential.certs.size(); i++) { | |
| 1661 EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]); | |
| 1662 } | |
| 1663 } | |
| 1664 | |
| 1665 TEST_F(SpdyFramerTest, ReadCredentialFrameWithCorruptProof) { | |
| 1666 SpdyCredential credential; | |
| 1667 credential.slot = 3; | |
| 1668 credential.proof = "proof"; | |
| 1669 credential.certs.push_back("a cert"); | |
| 1670 credential.certs.push_back("another cert"); | |
| 1671 credential.certs.push_back("final cert"); | |
| 1672 SpdyFramer framer; | |
| 1673 scoped_ptr<SpdyFrame> control_frame( | |
| 1674 framer.CreateCredentialFrame(credential)); | |
| 1675 EXPECT_TRUE(control_frame.get() != NULL); | |
| 1676 TestSpdyVisitor visitor; | |
| 1677 visitor.use_compression_ = false; | |
| 1678 unsigned char* data = | |
| 1679 reinterpret_cast<unsigned char*>(control_frame.get()->data()); | |
| 1680 size_t offset = SpdyControlFrame::kHeaderSize + 4; | |
| 1681 data[offset] = 0xFF; // Proof length is past the end of the frame | |
| 1682 visitor.SimulateInFramer( | |
| 1683 data, control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
| 1684 EXPECT_EQ(1, visitor.error_count_); | |
| 1685 } | |
| 1686 | |
| 1687 TEST_F(SpdyFramerTest, ReadCredentialFrameWithCorruptCertificate) { | |
| 1688 SpdyCredential credential; | |
| 1689 credential.slot = 3; | |
| 1690 credential.proof = "proof"; | |
| 1691 credential.certs.push_back("a cert"); | |
| 1692 credential.certs.push_back("another cert"); | |
| 1693 credential.certs.push_back("final cert"); | |
| 1694 SpdyFramer framer; | |
| 1695 scoped_ptr<SpdyFrame> control_frame( | |
| 1696 framer.CreateCredentialFrame(credential)); | |
| 1697 EXPECT_TRUE(control_frame.get() != NULL); | |
| 1698 TestSpdyVisitor visitor; | |
| 1699 visitor.use_compression_ = false; | |
| 1700 unsigned char* data = | |
| 1701 reinterpret_cast<unsigned char*>(control_frame.get()->data()); | |
| 1702 size_t offset = SpdyControlFrame::kHeaderSize + credential.proof.length(); | |
| 1703 data[offset] = 0xFF; // Certificate length is past the end of the frame | |
| 1704 visitor.SimulateInFramer( | |
| 1705 data, control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
| 1706 EXPECT_EQ(1, visitor.error_count_); | |
| 1707 } | |
| 1708 | |
| 1709 TEST_F(SpdyFramerTest, ReadGarbage) { | |
| 1710 SpdyFramer framer; | |
| 1711 unsigned char garbage_frame[256]; | |
| 1712 memset(garbage_frame, ~0, sizeof(garbage_frame)); | |
| 1713 TestSpdyVisitor visitor; | |
| 1714 visitor.use_compression_ = false; | |
| 1715 visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame)); | |
| 1716 EXPECT_EQ(1, visitor.error_count_); | |
| 1717 } | |
| 1718 | |
| 1719 TEST_F(SpdyFramerTest, ReadGarbageWithValidVersion) { | |
| 1720 SpdyFramer framer; | |
| 1721 char garbage_frame[256]; | |
| 1722 memset(garbage_frame, ~0, sizeof(garbage_frame)); | |
| 1723 SpdyControlFrame control_frame(&garbage_frame[0], false); | |
| 1724 control_frame.set_version(kSpdyProtocolVersion); | |
| 1725 TestSpdyVisitor visitor; | |
| 1726 visitor.use_compression_ = false; | |
| 1727 visitor.SimulateInFramer( | |
| 1728 reinterpret_cast<unsigned char*>(control_frame.data()), | |
| 1729 sizeof(garbage_frame)); | |
| 1730 EXPECT_EQ(1, visitor.error_count_); | |
| 1731 } | |
| 1732 | |
| 1733 TEST(SpdyFramer, StateToStringTest) { | |
| 1734 EXPECT_STREQ("ERROR", | |
| 1735 SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR)); | |
| 1736 EXPECT_STREQ("DONE", | |
| 1737 SpdyFramer::StateToString(SpdyFramer::SPDY_DONE)); | |
| 1738 EXPECT_STREQ("AUTO_RESET", | |
| 1739 SpdyFramer::StateToString(SpdyFramer::SPDY_AUTO_RESET)); | |
| 1740 EXPECT_STREQ("RESET", | |
| 1741 SpdyFramer::StateToString(SpdyFramer::SPDY_RESET)); | |
| 1742 EXPECT_STREQ("READING_COMMON_HEADER", | |
| 1743 SpdyFramer::StateToString( | |
| 1744 SpdyFramer::SPDY_READING_COMMON_HEADER)); | |
| 1745 EXPECT_STREQ("CONTROL_FRAME_PAYLOAD", | |
| 1746 SpdyFramer::StateToString( | |
| 1747 SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD)); | |
| 1748 EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD", | |
| 1749 SpdyFramer::StateToString( | |
| 1750 SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD)); | |
| 1751 EXPECT_STREQ("FORWARD_STREAM_FRAME", | |
| 1752 SpdyFramer::StateToString( | |
| 1753 SpdyFramer::SPDY_FORWARD_STREAM_FRAME)); | |
| 1754 EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK", | |
| 1755 SpdyFramer::StateToString( | |
| 1756 SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK)); | |
| 1757 EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK", | |
| 1758 SpdyFramer::StateToString( | |
| 1759 SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK)); | |
| 1760 EXPECT_STREQ("SPDY_CREDENTIAL_FRAME_PAYLOAD", | |
| 1761 SpdyFramer::StateToString( | |
| 1762 SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD)); | |
| 1763 EXPECT_STREQ("UNKNOWN_STATE", | |
| 1764 SpdyFramer::StateToString( | |
| 1765 SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD + 1)); | |
| 1766 } | |
| 1767 | |
| 1768 TEST(SpdyFramer, ErrorCodeToStringTest) { | |
| 1769 EXPECT_STREQ("NO_ERROR", | |
| 1770 SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR)); | |
| 1771 EXPECT_STREQ("INVALID_CONTROL_FRAME", | |
| 1772 SpdyFramer::ErrorCodeToString( | |
| 1773 SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); | |
| 1774 EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE", | |
| 1775 SpdyFramer::ErrorCodeToString( | |
| 1776 SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); | |
| 1777 EXPECT_STREQ("ZLIB_INIT_FAILURE", | |
| 1778 SpdyFramer::ErrorCodeToString( | |
| 1779 SpdyFramer::SPDY_ZLIB_INIT_FAILURE)); | |
| 1780 EXPECT_STREQ("UNSUPPORTED_VERSION", | |
| 1781 SpdyFramer::ErrorCodeToString( | |
| 1782 SpdyFramer::SPDY_UNSUPPORTED_VERSION)); | |
| 1783 EXPECT_STREQ("DECOMPRESS_FAILURE", | |
| 1784 SpdyFramer::ErrorCodeToString( | |
| 1785 SpdyFramer::SPDY_DECOMPRESS_FAILURE)); | |
| 1786 EXPECT_STREQ("COMPRESS_FAILURE", | |
| 1787 SpdyFramer::ErrorCodeToString( | |
| 1788 SpdyFramer::SPDY_COMPRESS_FAILURE)); | |
| 1789 EXPECT_STREQ("UNKNOWN_ERROR", | |
| 1790 SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR)); | |
| 1791 } | |
| 1792 | |
| 1793 TEST(SpdyFramer, StatusCodeToStringTest) { | |
| 1794 EXPECT_STREQ("INVALID", | |
| 1795 SpdyFramer::StatusCodeToString(INVALID)); | |
| 1796 EXPECT_STREQ("PROTOCOL_ERROR", | |
| 1797 SpdyFramer::StatusCodeToString(PROTOCOL_ERROR)); | |
| 1798 EXPECT_STREQ("INVALID_STREAM", | |
| 1799 SpdyFramer::StatusCodeToString(INVALID_STREAM)); | |
| 1800 EXPECT_STREQ("REFUSED_STREAM", | |
| 1801 SpdyFramer::StatusCodeToString(REFUSED_STREAM)); | |
| 1802 EXPECT_STREQ("UNSUPPORTED_VERSION", | |
| 1803 SpdyFramer::StatusCodeToString(UNSUPPORTED_VERSION)); | |
| 1804 EXPECT_STREQ("CANCEL", | |
| 1805 SpdyFramer::StatusCodeToString(CANCEL)); | |
| 1806 EXPECT_STREQ("INTERNAL_ERROR", | |
| 1807 SpdyFramer::StatusCodeToString(INTERNAL_ERROR)); | |
| 1808 EXPECT_STREQ("FLOW_CONTROL_ERROR", | |
| 1809 SpdyFramer::StatusCodeToString(FLOW_CONTROL_ERROR)); | |
| 1810 EXPECT_STREQ("UNKNOWN_STATUS", | |
| 1811 SpdyFramer::StatusCodeToString(NUM_STATUS_CODES)); | |
| 1812 } | |
| 1813 | |
| 1814 TEST(SpdyFramer, ControlTypeToStringTest) { | |
| 1815 EXPECT_STREQ("SYN_STREAM", | |
| 1816 SpdyFramer::ControlTypeToString(SYN_STREAM)); | |
| 1817 EXPECT_STREQ("SYN_REPLY", | |
| 1818 SpdyFramer::ControlTypeToString(SYN_REPLY)); | |
| 1819 EXPECT_STREQ("RST_STREAM", | |
| 1820 SpdyFramer::ControlTypeToString(RST_STREAM)); | |
| 1821 EXPECT_STREQ("SETTINGS", | |
| 1822 SpdyFramer::ControlTypeToString(SETTINGS)); | |
| 1823 EXPECT_STREQ("NOOP", | |
| 1824 SpdyFramer::ControlTypeToString(NOOP)); | |
| 1825 EXPECT_STREQ("PING", | |
| 1826 SpdyFramer::ControlTypeToString(PING)); | |
| 1827 EXPECT_STREQ("GOAWAY", | |
| 1828 SpdyFramer::ControlTypeToString(GOAWAY)); | |
| 1829 EXPECT_STREQ("HEADERS", | |
| 1830 SpdyFramer::ControlTypeToString(HEADERS)); | |
| 1831 EXPECT_STREQ("WINDOW_UPDATE", | |
| 1832 SpdyFramer::ControlTypeToString(WINDOW_UPDATE)); | |
| 1833 EXPECT_STREQ("SETTINGS", | |
| 1834 SpdyFramer::ControlTypeToString(SETTINGS)); | |
| 1835 EXPECT_STREQ("UNKNOWN_CONTROL_TYPE", | |
| 1836 SpdyFramer::ControlTypeToString(NUM_CONTROL_FRAME_TYPES)); | |
| 1837 } | |
| 1838 | |
| 1839 TEST(SpdyFramer, GetMinimumControlFrameSizeTest) { | |
| 1840 EXPECT_EQ(SpdySynStreamControlFrame::size(), | |
| 1841 SpdyFramer::GetMinimumControlFrameSize(SYN_STREAM)); | |
| 1842 EXPECT_EQ(SpdySynReplyControlFrame::size(), | |
| 1843 SpdyFramer::GetMinimumControlFrameSize(SYN_REPLY)); | |
| 1844 EXPECT_EQ(SpdyRstStreamControlFrame::size(), | |
| 1845 SpdyFramer::GetMinimumControlFrameSize(RST_STREAM)); | |
| 1846 EXPECT_EQ(SpdySettingsControlFrame::size(), | |
| 1847 SpdyFramer::GetMinimumControlFrameSize(SETTINGS)); | |
| 1848 EXPECT_EQ(SpdyNoOpControlFrame::size(), | |
| 1849 SpdyFramer::GetMinimumControlFrameSize(NOOP)); | |
| 1850 EXPECT_EQ(SpdyPingControlFrame::size(), | |
| 1851 SpdyFramer::GetMinimumControlFrameSize(PING)); | |
| 1852 EXPECT_EQ(SpdyGoAwayControlFrame::size(), | |
| 1853 SpdyFramer::GetMinimumControlFrameSize(GOAWAY)); | |
| 1854 EXPECT_EQ(SpdyHeadersControlFrame::size(), | |
| 1855 SpdyFramer::GetMinimumControlFrameSize(HEADERS)); | |
| 1856 EXPECT_EQ(SpdyWindowUpdateControlFrame::size(), | |
| 1857 SpdyFramer::GetMinimumControlFrameSize(WINDOW_UPDATE)); | |
| 1858 EXPECT_EQ(SpdyCredentialControlFrame::size(), | |
| 1859 SpdyFramer::GetMinimumControlFrameSize(CREDENTIAL)); | |
| 1860 EXPECT_EQ(static_cast<size_t>(0x7FFFFFFF), | |
| 1861 SpdyFramer::GetMinimumControlFrameSize(NUM_CONTROL_FRAME_TYPES)); | |
| 1862 } | |
| 1863 | |
| 1864 std::string RandomString(int length) { | |
| 1865 std::string rv; | |
| 1866 for (int index = 0; index < length; index++) | |
| 1867 rv += static_cast<char>('a' + (rand() % 26)); | |
| 1868 return rv; | |
| 1869 } | |
| 1870 | |
| 1871 } // namespace | |
| OLD | NEW |