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