Index: net/spdy/spdy_framer_spdy3_test.cc |
=================================================================== |
--- net/spdy/spdy_framer_spdy3_test.cc (revision 126484) |
+++ net/spdy/spdy_framer_spdy3_test.cc (working copy) |
@@ -1,2623 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include <algorithm> |
-#include <iostream> |
- |
-#include "base/memory/scoped_ptr.h" |
-#include "net/spdy/spdy_framer.h" |
-#include "net/spdy/spdy_protocol.h" |
-#include "net/spdy/spdy_frame_builder.h" |
-#include "testing/platform_test.h" |
- |
-namespace { |
- |
-// Default SPDY version for unit tests. |
-const int SPDY_VERSION_FOR_TESTS = 3; |
- |
-// The current default spdy version as a byte to be included in const |
-// byte arrays below. Name choice is unfortunate, but better to fit to four |
-// bytes than not. |
-unsigned char kVer = SPDY_VERSION_FOR_TESTS; |
- |
-spdy::SpdySetting SpdySettingFromWireFormat(uint32 key, uint32 value) { |
- return spdy::SpdySetting( |
- spdy::SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, key), |
- value); |
-} |
- |
-} // namespace |
- |
-namespace spdy { |
- |
-namespace test_spdy3 { |
- |
-static const size_t kMaxDecompressedSize = 1024; |
- |
-class SpdyFramerTestUtil { |
- public: |
- // Decompress a single frame using the decompression context held by |
- // the SpdyFramer. The implemention will CHECK fail if the input is anything |
- // other than a single, well-formed compressed frame. |
- // |
- // Returns a new decompressed SpdyFrame. |
- template<class SpdyFrameType> static SpdyFrame* DecompressFrame( |
- SpdyFramer* framer, const SpdyFrameType& frame) { |
- DecompressionVisitor visitor; |
- framer->set_visitor(&visitor); |
- size_t input_size = frame.length() + SpdyFrame::kHeaderSize; |
- CHECK_EQ(input_size, framer->ProcessInput(frame.data(), input_size)); |
- CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state()); |
- framer->set_visitor(NULL); |
- |
- char* buffer = visitor.ReleaseBuffer(); |
- CHECK(buffer); |
- SpdyFrame* decompressed_frame = new SpdyFrame(buffer, true); |
- decompressed_frame->set_length(visitor.size() - SpdyFrame::kHeaderSize); |
- return decompressed_frame; |
- } |
- |
- class DecompressionVisitor : public SpdyFramerVisitorInterface { |
- public: |
- DecompressionVisitor() |
- : buffer_(NULL), size_(0), finished_(false), allow_data_frames_(false) { |
- } |
- |
- virtual void OnControl(const SpdyControlFrame* frame) { |
- CHECK(frame->has_header_block()); |
- CHECK(!buffer_.get()); |
- CHECK_EQ(size_, 0u); |
- CHECK(!finished_); |
- |
- int32 control_frame_header_size = 0; |
- switch (frame->type()) { |
- case SYN_STREAM: |
- control_frame_header_size = SpdySynStreamControlFrame::size(); |
- break; |
- case SYN_REPLY: |
- control_frame_header_size = SpdySynReplyControlFrame::size(); |
- break; |
- case HEADERS: |
- control_frame_header_size = SpdyHeadersControlFrame::size(); |
- break; |
- default: |
- LOG(FATAL); |
- return; |
- } |
- |
- // Allocate space for the frame, and the copy header over. |
- buffer_.reset(new char[kMaxDecompressedSize]); |
- memcpy(buffer_.get(), frame->data(), control_frame_header_size); |
- size_ += control_frame_header_size; |
- } |
- |
- virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, |
- const char* header_data, |
- size_t len) { |
- CHECK(buffer_.get() != NULL); |
- CHECK_GE(kMaxDecompressedSize, size_ + len); |
- CHECK(!finished_); |
- if (len != 0) { |
- memcpy(buffer_.get() + size_, header_data, len); |
- size_ += len; |
- } else { |
- // Done. |
- finished_ = true; |
- } |
- return true; |
- } |
- |
- virtual bool OnCredentialFrameData(const char* header_data, |
- size_t len) { |
- LOG(FATAL) << "Unexpected CREDENTIAL Frame"; |
- return false; |
- } |
- |
- virtual void OnError(SpdyFramer* framer) { LOG(FATAL); } |
- virtual void OnDataFrameHeader(const SpdyDataFrame* frame) { |
- // For most tests, this class does not expect to see OnDataFrameHeader |
- // calls. Individual tests can override this if they need to. |
- if (!allow_data_frames_) { |
- LOG(FATAL) << "Unexpected data frame header"; |
- } |
- } |
- virtual void OnStreamFrameData(SpdyStreamId stream_id, |
- const char* data, |
- size_t len) { |
- LOG(FATAL); |
- } |
- virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) { |
- LOG(FATAL); |
- } |
- |
- char* ReleaseBuffer() { |
- CHECK(finished_); |
- return buffer_.release(); |
- } |
- |
- size_t size() const { |
- CHECK(finished_); |
- return size_; |
- } |
- void set_allow_data_frames(bool allow) { allow_data_frames_ = allow; } |
- |
- private: |
- scoped_array<char> buffer_; |
- size_t size_; |
- bool finished_; |
- bool allow_data_frames_; |
- |
- DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor); |
- }; |
- |
- DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil); |
-}; |
- |
-std::string HexDumpWithMarks(const unsigned char* data, int length, |
- const bool* marks, int mark_length) { |
- static const char kHexChars[] = "0123456789abcdef"; |
- static const int kColumns = 4; |
- |
- const int kSizeLimit = 1024; |
- if (length > kSizeLimit || mark_length > kSizeLimit) { |
- LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes."; |
- length = std::min(length, kSizeLimit); |
- mark_length = std::min(mark_length, kSizeLimit); |
- } |
- |
- std::string hex; |
- for (const unsigned char* row = data; length > 0; |
- row += kColumns, length -= kColumns) { |
- for (const unsigned char *p = row; p < row + 4; ++p) { |
- if (p < row + length) { |
- const bool mark = |
- (marks && (p - data) < mark_length && marks[p - data]); |
- hex += mark ? '*' : ' '; |
- hex += kHexChars[(*p & 0xf0) >> 4]; |
- hex += kHexChars[*p & 0x0f]; |
- hex += mark ? '*' : ' '; |
- } else { |
- hex += " "; |
- } |
- } |
- hex = hex + " "; |
- |
- for (const unsigned char *p = row; p < row + 4 && p < row + length; ++p) |
- hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.'; |
- |
- hex = hex + '\n'; |
- } |
- return hex; |
-} |
- |
-void CompareCharArraysWithHexError( |
- const std::string& description, |
- const unsigned char* actual, |
- const int actual_len, |
- const unsigned char* expected, |
- const int expected_len) { |
- const int min_len = std::min(actual_len, expected_len); |
- const int max_len = std::max(actual_len, expected_len); |
- scoped_array<bool> marks(new bool[max_len]); |
- bool identical = (actual_len == expected_len); |
- for (int i = 0; i < min_len; ++i) { |
- if (actual[i] != expected[i]) { |
- marks[i] = true; |
- identical = false; |
- } else { |
- marks[i] = false; |
- } |
- } |
- for (int i = min_len; i < max_len; ++i) { |
- marks[i] = true; |
- } |
- if (identical) return; |
- ADD_FAILURE() |
- << "Description:\n" |
- << description |
- << "\n\nExpected:\n" |
- << HexDumpWithMarks(expected, expected_len, marks.get(), max_len) |
- << "\nActual:\n" |
- << HexDumpWithMarks(actual, actual_len, marks.get(), max_len); |
-} |
- |
-class TestSpdyVisitor : public SpdyFramerVisitorInterface { |
- public: |
- static const size_t kDefaultHeaderBufferSize = 64 * 1024; |
- static const size_t kDefaultCredentialBufferSize = 16 * 1024; |
- |
- TestSpdyVisitor() |
- : framer_(kVer), |
- use_compression_(false), |
- error_count_(0), |
- syn_frame_count_(0), |
- syn_reply_frame_count_(0), |
- headers_frame_count_(0), |
- goaway_count_(0), |
- credential_count_(0), |
- settings_frame_count_(0), |
- setting_count_(0), |
- data_bytes_(0), |
- fin_frame_count_(0), |
- fin_flag_count_(0), |
- zero_length_data_frame_count_(0), |
- header_blocks_count_(0), |
- control_frame_header_data_count_(0), |
- zero_length_control_frame_header_data_count_(0), |
- data_frame_count_(0), |
- header_buffer_(new char[kDefaultHeaderBufferSize]), |
- header_buffer_length_(0), |
- header_buffer_size_(kDefaultHeaderBufferSize), |
- header_stream_id_(-1), |
- header_control_type_(NUM_CONTROL_FRAME_TYPES), |
- header_buffer_valid_(false), |
- credential_buffer_(new char[kDefaultCredentialBufferSize]), |
- credential_buffer_length_(0), |
- credential_buffer_size_(kDefaultCredentialBufferSize) { |
- } |
- |
- void OnError(SpdyFramer* f) { |
- LOG(INFO) << "SpdyFramer Error: " |
- << SpdyFramer::ErrorCodeToString(f->error_code()); |
- error_count_++; |
- } |
- |
- void OnDataFrameHeader(const SpdyDataFrame* frame) { |
- data_frame_count_++; |
- header_stream_id_ = frame->stream_id(); |
- } |
- |
- void OnStreamFrameData(SpdyStreamId stream_id, |
- const char* data, |
- size_t len) { |
- EXPECT_EQ(header_stream_id_, stream_id); |
- if (len == 0) |
- ++zero_length_data_frame_count_; |
- |
- data_bytes_ += len; |
- std::cerr << "OnStreamFrameData(" << stream_id << ", \""; |
- if (len > 0) { |
- for (size_t i = 0 ; i < len; ++i) { |
- std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec; |
- } |
- } |
- std::cerr << "\", " << len << ")\n"; |
- } |
- |
- void OnControl(const SpdyControlFrame* frame) { |
- switch (frame->type()) { |
- case SYN_STREAM: |
- syn_frame_count_++; |
- InitHeaderStreaming(frame); |
- break; |
- case SYN_REPLY: |
- syn_reply_frame_count_++; |
- InitHeaderStreaming(frame); |
- break; |
- case RST_STREAM: |
- fin_frame_count_++; |
- break; |
- case HEADERS: |
- headers_frame_count_++; |
- InitHeaderStreaming(frame); |
- break; |
- case GOAWAY: |
- goaway_count_++; |
- break; |
- case CREDENTIAL: |
- credential_count_++; |
- break; |
- case SETTINGS: |
- settings_frame_count_++; |
- break; |
- default: |
- DLOG(FATAL); // Error! |
- } |
- if (frame->flags() & CONTROL_FLAG_FIN) |
- ++fin_flag_count_; |
- } |
- |
- virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) { |
- setting_count_++; |
- } |
- |
- bool OnControlFrameHeaderData(SpdyStreamId stream_id, |
- const char* header_data, |
- size_t len) { |
- ++control_frame_header_data_count_; |
- CHECK_EQ(header_stream_id_, stream_id); |
- if (len == 0) { |
- ++zero_length_control_frame_header_data_count_; |
- // Indicates end-of-header-block. |
- CHECK(header_buffer_valid_); |
- bool parsed_headers = framer_.ParseHeaderBlockInBuffer( |
- header_buffer_.get(), header_buffer_length_, &headers_); |
- DCHECK(parsed_headers); |
- return true; |
- } |
- const size_t available = header_buffer_size_ - header_buffer_length_; |
- if (len > available) { |
- header_buffer_valid_ = false; |
- return false; |
- } |
- memcpy(header_buffer_.get() + header_buffer_length_, header_data, len); |
- header_buffer_length_ += len; |
- return true; |
- } |
- |
- bool OnCredentialFrameData(const char* credential_data, |
- size_t len) { |
- if (len == 0) { |
- if (!framer_.ParseCredentialData(credential_buffer_.get(), |
- credential_buffer_length_, |
- &credential_)) { |
- ++error_count_; |
- } |
- return true; |
- } |
- const size_t available = |
- credential_buffer_size_ - credential_buffer_length_; |
- if (len > available) { |
- return false; |
- } |
- memcpy(credential_buffer_.get() + credential_buffer_length_, |
- credential_data, len); |
- credential_buffer_length_ += len; |
- return true; |
- } |
- |
- // Convenience function which runs a framer simulation with particular input. |
- void SimulateInFramer(const unsigned char* input, size_t size) { |
- framer_.set_enable_compression(use_compression_); |
- framer_.set_visitor(this); |
- size_t input_remaining = size; |
- const char* input_ptr = reinterpret_cast<const char*>(input); |
- while (input_remaining > 0 && |
- framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) { |
- // To make the tests more interesting, we feed random (amd small) chunks |
- // into the framer. This simulates getting strange-sized reads from |
- // the socket. |
- const size_t kMaxReadSize = 32; |
- size_t bytes_read = |
- (rand() % std::min(input_remaining, kMaxReadSize)) + 1; |
- size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read); |
- input_remaining -= bytes_processed; |
- input_ptr += bytes_processed; |
- if (framer_.state() == SpdyFramer::SPDY_DONE) |
- framer_.Reset(); |
- } |
- } |
- |
- void InitHeaderStreaming(const SpdyControlFrame* frame) { |
- memset(header_buffer_.get(), 0, header_buffer_size_); |
- header_buffer_length_ = 0; |
- header_stream_id_ = SpdyFramer::GetControlFrameStreamId(frame); |
- header_control_type_ = frame->type(); |
- header_buffer_valid_ = true; |
- DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); |
- } |
- |
- // Override the default buffer size (16K). Call before using the framer! |
- void set_header_buffer_size(size_t header_buffer_size) { |
- header_buffer_size_ = header_buffer_size; |
- header_buffer_.reset(new char[header_buffer_size]); |
- } |
- |
- static size_t control_frame_buffer_max_size() { |
- return SpdyFramer::kControlFrameBufferMaxSize; |
- } |
- |
- static size_t header_data_chunk_max_size() { |
- return SpdyFramer::kHeaderDataChunkMaxSize; |
- } |
- |
- SpdyFramer framer_; |
- bool use_compression_; |
- |
- // Counters from the visitor callbacks. |
- int error_count_; |
- int syn_frame_count_; |
- int syn_reply_frame_count_; |
- int headers_frame_count_; |
- int goaway_count_; |
- int credential_count_; |
- int settings_frame_count_; |
- int setting_count_; |
- int data_bytes_; |
- int fin_frame_count_; // The count of RST_STREAM type frames received. |
- int fin_flag_count_; // The count of frames with the FIN flag set. |
- int zero_length_data_frame_count_; // The count of zero-length data frames. |
- int header_blocks_count_; |
- int control_frame_header_data_count_; // The count of chunks received. |
- // The count of zero-length control frame header data chunks received. |
- int zero_length_control_frame_header_data_count_; |
- int data_frame_count_; |
- |
- // Header block streaming state: |
- scoped_array<char> header_buffer_; |
- size_t header_buffer_length_; |
- size_t header_buffer_size_; |
- SpdyStreamId header_stream_id_; |
- SpdyControlType header_control_type_; |
- bool header_buffer_valid_; |
- SpdyHeaderBlock headers_; |
- |
- scoped_array<char> credential_buffer_; |
- size_t credential_buffer_length_; |
- size_t credential_buffer_size_; |
- SpdyCredential credential_; |
-}; |
- |
-} // namespace test_spdy3 |
- |
-} // namespace spdy |
- |
-using spdy::SpdyControlFlags; |
-using spdy::SpdyControlFrame; |
-using spdy::SpdyDataFrame; |
-using spdy::SpdyFrame; |
-using spdy::SpdyFrameBuilder; |
-using spdy::SpdyFramer; |
-using spdy::SpdyHeaderBlock; |
-using spdy::SpdySynStreamControlFrame; |
-using spdy::kControlFlagMask; |
-using spdy::kLengthMask; |
-using spdy::CONTROL_FLAG_NONE; |
-using spdy::DATA_FLAG_COMPRESSED; |
-using spdy::DATA_FLAG_FIN; |
-using spdy::SYN_STREAM; |
-using spdy::test_spdy3::CompareCharArraysWithHexError; |
-using spdy::test_spdy3::SpdyFramerTestUtil; |
-using spdy::test_spdy3::TestSpdyVisitor; |
- |
-namespace spdy { |
- |
-TEST(SpdyFrameBuilderSpdy3Test, WriteLimits) { |
- SpdyFrameBuilder builder(kLengthMask + 4); |
- // length field should fail. |
- EXPECT_FALSE(builder.WriteBytes(reinterpret_cast<const void*>(0x1), |
- kLengthMask + 1)); |
- EXPECT_EQ(0, builder.length()); |
- |
- // Writing a block of the maximum allowed size should succeed. |
- const std::string kLargeData(kLengthMask, 'A'); |
- builder.WriteUInt32(kLengthMask); |
- EXPECT_EQ(4, builder.length()); |
- EXPECT_TRUE(builder.WriteBytes(kLargeData.data(), kLengthMask)); |
- EXPECT_EQ(4 + kLengthMask, static_cast<unsigned>(builder.length())); |
-} |
- |
-class SpdyFramerSpdy3Test : public PlatformTest { |
- public: |
- virtual void TearDown() {} |
- |
- protected: |
- void CompareFrame(const std::string& description, |
- const SpdyFrame& actual_frame, |
- const unsigned char* expected, |
- const int expected_len) { |
- const unsigned char* actual = |
- reinterpret_cast<const unsigned char*>(actual_frame.data()); |
- int actual_len = actual_frame.length() + SpdyFrame::kHeaderSize; |
- CompareCharArraysWithHexError( |
- description, actual, actual_len, expected, expected_len); |
- } |
- |
- // Returns true if the two header blocks have equivalent content. |
- bool CompareHeaderBlocks(const SpdyHeaderBlock* expected, |
- const SpdyHeaderBlock* actual) { |
- if (expected->size() != actual->size()) { |
- LOG(ERROR) << "Expected " << expected->size() << " headers; actually got " |
- << actual->size() << "." << std::endl; |
- return false; |
- } |
- for (SpdyHeaderBlock::const_iterator it = expected->begin(); |
- it != expected->end(); |
- ++it) { |
- SpdyHeaderBlock::const_iterator it2 = actual->find(it->first); |
- if (it2 == actual->end()) { |
- LOG(ERROR) << "Expected header name '" << it->first << "'." |
- << std::endl; |
- return false; |
- } |
- if (it->second.compare(it2->second) != 0) { |
- LOG(ERROR) << "Expected header named '" << it->first |
- << "' to have a value of '" << it->second |
- << "'. The actual value received was '" << it2->second |
- << "'." << std::endl; |
- return false; |
- } |
- } |
- return true; |
- } |
-}; |
- |
- |
-// Test that we can encode and decode a SpdyHeaderBlock in serialized form. |
-TEST_F(SpdyFramerSpdy3Test, HeaderBlockInBuffer) { |
- SpdyHeaderBlock headers; |
- headers["alpha"] = "beta"; |
- headers["gamma"] = "charlie"; |
- SpdyFramer framer(kVer); |
- |
- // Encode the header block into a SynStream frame. |
- scoped_ptr<SpdySynStreamControlFrame> frame( |
- framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, &headers)); |
- EXPECT_TRUE(frame.get() != NULL); |
- std::string serialized_headers(frame->header_block(), |
- frame->header_block_len()); |
- SpdyHeaderBlock new_headers; |
- EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), |
- serialized_headers.size(), |
- &new_headers)); |
- |
- EXPECT_EQ(headers.size(), new_headers.size()); |
- EXPECT_EQ(headers["alpha"], new_headers["alpha"]); |
- EXPECT_EQ(headers["gamma"], new_headers["gamma"]); |
-} |
- |
-// Test that if there's not a full frame, we fail to parse it. |
-TEST_F(SpdyFramerSpdy3Test, UndersizedHeaderBlockInBuffer) { |
- SpdyHeaderBlock headers; |
- headers["alpha"] = "beta"; |
- headers["gamma"] = "charlie"; |
- SpdyFramer framer(kVer); |
- |
- // Encode the header block into a SynStream frame. |
- scoped_ptr<SpdySynStreamControlFrame> frame( |
- framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false, &headers)); |
- EXPECT_TRUE(frame.get() != NULL); |
- |
- std::string serialized_headers(frame->header_block(), |
- frame->header_block_len()); |
- SpdyHeaderBlock new_headers; |
- EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), |
- serialized_headers.size() - 2, |
- &new_headers)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, OutOfOrderHeaders) { |
- // Frame builder with plentiful buffer size. |
- SpdyFrameBuilder frame(1024); |
- |
- frame.WriteUInt16(kControlFlagMask | 1); |
- frame.WriteUInt16(SYN_STREAM); |
- frame.WriteUInt32(0); // Placeholder for the length. |
- frame.WriteUInt32(3); // stream_id |
- frame.WriteUInt32(0); // Associated stream id |
- frame.WriteUInt16(0); // Priority. |
- |
- if (SPDY_VERSION_FOR_TESTS < 3) { |
- frame.WriteUInt16(2); // Number of headers. |
- frame.WriteString("gamma"); |
- frame.WriteString("gamma"); |
- frame.WriteString("alpha"); |
- frame.WriteString("alpha"); |
- } else { |
- frame.WriteUInt32(2); // Number of headers. |
- frame.WriteStringPiece32("gamma"); |
- frame.WriteStringPiece32("gamma"); |
- frame.WriteStringPiece32("alpha"); |
- frame.WriteStringPiece32("alpha"); |
- } |
- // write the length |
- frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); |
- |
- SpdyHeaderBlock new_headers; |
- scoped_ptr<SpdyFrame> control_frame(frame.take()); |
- SpdySynStreamControlFrame syn_frame(control_frame->data(), false); |
- std::string serialized_headers(syn_frame.header_block(), |
- syn_frame.header_block_len()); |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(false); |
- EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), |
- serialized_headers.size(), |
- &new_headers)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateCredential) { |
- SpdyFramer framer(kVer); |
- |
- { |
- const char kDescription[] = "CREDENTIAL frame"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x0A, |
- 0x00, 0x00, 0x00, 0x33, |
- 0x00, 0x03, 0x00, 0x00, |
- 0x00, 0x05, 'p', 'r', |
- 'o', 'o', 'f', 0x00, |
- 0x00, 0x00, 0x06, 'a', |
- ' ', 'c', 'e', 'r', |
- 't', 0x00, 0x00, 0x00, |
- 0x0C, 'a', 'n', 'o', |
- 't', 'h', 'e', 'r', |
- ' ', 'c', 'e', 'r', |
- 't', 0x00, 0x00, 0x00, |
- 0x0A, 'f', 'i', 'n', |
- 'a', 'l', ' ', 'c', |
- 'e', 'r', 't', |
- }; |
- SpdyCredential credential; |
- credential.slot = 3; |
- credential.proof = "proof"; |
- credential.certs.push_back("a cert"); |
- credential.certs.push_back("another cert"); |
- credential.certs.push_back("final cert"); |
- scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ParseCredentialFrameData) { |
- SpdyFramer framer(kVer); |
- |
- { |
- unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x0A, |
- 0x00, 0x00, 0x00, 0x33, |
- 0x00, 0x03, 0x00, 0x00, |
- 0x00, 0x05, 'p', 'r', |
- 'o', 'o', 'f', 0x00, |
- 0x00, 0x00, 0x06, 'a', |
- ' ', 'c', 'e', 'r', |
- 't', 0x00, 0x00, 0x00, |
- 0x0C, 'a', 'n', 'o', |
- 't', 'h', 'e', 'r', |
- ' ', 'c', 'e', 'r', |
- 't', 0x00, 0x00, 0x00, |
- 0x0A, 'f', 'i', 'n', |
- 'a', 'l', ' ', 'c', |
- 'e', 'r', 't', |
- }; |
- SpdyCredentialControlFrame frame(reinterpret_cast<char*>(kFrameData), |
- false); |
- SpdyCredential credential; |
- EXPECT_TRUE(SpdyFramer::ParseCredentialData(frame.payload(), frame.length(), |
- &credential)); |
- EXPECT_EQ(3u, credential.slot); |
- EXPECT_EQ("proof", credential.proof); |
- EXPECT_EQ("a cert", credential.certs.front()); |
- credential.certs.erase(credential.certs.begin()); |
- EXPECT_EQ("another cert", credential.certs.front()); |
- credential.certs.erase(credential.certs.begin()); |
- EXPECT_EQ("final cert", credential.certs.front()); |
- credential.certs.erase(credential.certs.begin()); |
- EXPECT_TRUE(credential.certs.empty()); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, DuplicateHeader) { |
- // Frame builder with plentiful buffer size. |
- SpdyFrameBuilder frame(1024); |
- |
- frame.WriteUInt16(kControlFlagMask | 1); |
- frame.WriteUInt16(SYN_STREAM); |
- frame.WriteUInt32(0); // Placeholder for the length. |
- frame.WriteUInt32(3); // stream_id |
- frame.WriteUInt32(0); // associated stream id |
- frame.WriteUInt16(0); // Priority. |
- |
- if (SPDY_VERSION_FOR_TESTS < 3) { |
- frame.WriteUInt16(2); // Number of headers. |
- frame.WriteString("name"); |
- frame.WriteString("value1"); |
- frame.WriteString("name"); |
- frame.WriteString("value2"); |
- } else { |
- frame.WriteUInt32(2); // Number of headers. |
- frame.WriteStringPiece32("name"); |
- frame.WriteStringPiece32("value1"); |
- frame.WriteStringPiece32("name"); |
- frame.WriteStringPiece32("value2"); |
- } |
- // write the length |
- frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); |
- |
- SpdyHeaderBlock new_headers; |
- scoped_ptr<SpdyFrame> control_frame(frame.take()); |
- SpdySynStreamControlFrame syn_frame(control_frame->data(), false); |
- std::string serialized_headers(syn_frame.header_block(), |
- syn_frame.header_block_len()); |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(false); |
- // This should fail because duplicate headers are verboten by the spec. |
- EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), |
- serialized_headers.size(), |
- &new_headers)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, MultiValueHeader) { |
- // Frame builder with plentiful buffer size. |
- SpdyFrameBuilder frame(1024); |
- |
- frame.WriteUInt16(kControlFlagMask | 1); |
- frame.WriteUInt16(SYN_STREAM); |
- frame.WriteUInt32(0); // Placeholder for the length. |
- frame.WriteUInt32(3); // stream_id |
- frame.WriteUInt32(0); // associated stream id |
- frame.WriteUInt16(0); // Priority. |
- |
- std::string value("value1\0value2"); |
- if (SPDY_VERSION_FOR_TESTS < 3) { |
- frame.WriteUInt16(1); // Number of headers. |
- frame.WriteString("name"); |
- frame.WriteString(value); |
- } else { |
- frame.WriteUInt32(1); // Number of headers. |
- frame.WriteStringPiece32("name"); |
- frame.WriteStringPiece32(value); |
- } |
- // write the length |
- frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::kHeaderSize); |
- |
- SpdyHeaderBlock new_headers; |
- scoped_ptr<SpdyFrame> control_frame(frame.take()); |
- SpdySynStreamControlFrame syn_frame(control_frame->data(), false); |
- std::string serialized_headers(syn_frame.header_block(), |
- syn_frame.header_block_len()); |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(false); |
- EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.c_str(), |
- serialized_headers.size(), |
- &new_headers)); |
- EXPECT_TRUE(new_headers.find("name") != new_headers.end()); |
- EXPECT_EQ(value, new_headers.find("name")->second); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, BasicCompression) { |
- SpdyHeaderBlock headers; |
- headers["server"] = "SpdyServer 1.0"; |
- headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; |
- headers["status"] = "200"; |
- headers["version"] = "HTTP/1.1"; |
- headers["content-type"] = "text/html"; |
- headers["content-length"] = "12"; |
- |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(true); |
- scoped_ptr<SpdySynStreamControlFrame> |
- frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, |
- &headers)); |
- scoped_ptr<SpdySynStreamControlFrame> |
- frame2(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, |
- &headers)); |
- |
- // Expect the second frame to be more compact than the first. |
- EXPECT_LE(frame2->length(), frame1->length()); |
- |
- // Decompress the first frame |
- scoped_ptr<SpdyFrame> frame3(SpdyFramerTestUtil::DecompressFrame( |
- &framer, *frame1.get())); |
- |
- // Decompress the second frame |
- scoped_ptr<SpdyFrame> frame4(SpdyFramerTestUtil::DecompressFrame( |
- &framer, *frame2.get())); |
- |
- // Expect frames 3 & 4 to be the same. |
- EXPECT_EQ(0, |
- memcmp(frame3->data(), frame4->data(), |
- SpdyFrame::kHeaderSize + frame3->length())); |
- |
- |
- // Expect frames 3 to be the same as a uncompressed frame created |
- // from scratch. |
- scoped_ptr<SpdySynStreamControlFrame> |
- uncompressed_frame(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, |
- false, &headers)); |
- EXPECT_EQ(frame3->length(), uncompressed_frame->length()); |
- EXPECT_EQ(0, |
- memcmp(frame3->data(), uncompressed_frame->data(), |
- SpdyFrame::kHeaderSize + uncompressed_frame->length())); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, Basic) { |
- const unsigned char kV2Input[] = { |
- 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
- 0x00, 0x00, 0x00, 0x14, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x02, 'h', 'h', |
- 0x00, 0x02, 'v', 'v', |
- |
- 0x80, kVer, 0x00, 0x08, // HEADERS on Stream #1 |
- 0x00, 0x00, 0x00, 0x18, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x02, 'h', '2', |
- 0x00, 0x02, 'v', '2', |
- 0x00, 0x02, 'h', '3', |
- 0x00, 0x02, 'v', '3', |
- |
- 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
- 0x00, 0x00, 0x00, 0x0c, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- |
- 0x80, kVer, 0x00, 0x01, // SYN Stream #3 |
- 0x00, 0x00, 0x00, 0x0c, |
- 0x00, 0x00, 0x00, 0x03, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- |
- 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 |
- 0x00, 0x00, 0x00, 0x08, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- |
- 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
- 0x00, 0x00, 0x00, 0x04, |
- 0xde, 0xad, 0xbe, 0xef, |
- |
- 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #1 |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- |
- 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 |
- 0x00, 0x00, 0x00, 0x00, |
- |
- 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #3 |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x03, |
- 0x00, 0x00, 0x00, 0x00, |
- }; |
- |
- const unsigned char kV3Input[] = { |
- 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
- 0x00, 0x00, 0x00, 0x1a, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x01, 0x00, 0x00, |
- 0x00, 0x02, 'h', 'h', |
- 0x00, 0x00, 0x00, 0x02, |
- 'v', 'v', |
- |
- 0x80, kVer, 0x00, 0x08, // HEADERS on Stream #1 |
- 0x00, 0x00, 0x00, 0x22, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x02, 0x00, 0x00, |
- 0x00, 0x02, 'h', '2', |
- 0x00, 0x00, 0x00, 0x02, |
- 'v', '2', 0x00, 0x00, |
- 0x00, 0x02, 'h', '3', |
- 0x00, 0x00, 0x00, 0x02, |
- 'v', '3', |
- |
- 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
- 0x00, 0x00, 0x00, 0x0c, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- |
- 0x80, kVer, 0x00, 0x01, // SYN Stream #3 |
- 0x00, 0x00, 0x00, 0x0e, |
- 0x00, 0x00, 0x00, 0x03, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, |
- |
- 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 |
- 0x00, 0x00, 0x00, 0x08, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- |
- 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
- 0x00, 0x00, 0x00, 0x04, |
- 0xde, 0xad, 0xbe, 0xef, |
- |
- 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #1 |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- |
- 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 |
- 0x00, 0x00, 0x00, 0x00, |
- |
- 0x80, kVer, 0x00, 0x03, // RST_STREAM on Stream #3 |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x03, |
- 0x00, 0x00, 0x00, 0x00, |
- }; |
- |
- TestSpdyVisitor visitor; |
- if (SPDY_VERSION_FOR_TESTS < 3) { |
- visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); |
- } else { |
- visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); |
- } |
- |
- EXPECT_EQ(0, visitor.error_count_); |
- EXPECT_EQ(2, visitor.syn_frame_count_); |
- EXPECT_EQ(0, visitor.syn_reply_frame_count_); |
- EXPECT_EQ(1, visitor.headers_frame_count_); |
- EXPECT_EQ(24, visitor.data_bytes_); |
- EXPECT_EQ(2, visitor.fin_frame_count_); |
- EXPECT_EQ(0, visitor.fin_flag_count_); |
- EXPECT_EQ(0, visitor.zero_length_data_frame_count_); |
- EXPECT_EQ(4, visitor.data_frame_count_); |
-} |
- |
-// Test that the FIN flag on a data frame signifies EOF. |
-TEST_F(SpdyFramerSpdy3Test, FinOnDataFrame) { |
- const unsigned char kV2Input[] = { |
- 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
- 0x00, 0x00, 0x00, 0x14, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x02, 'h', 'h', |
- 0x00, 0x02, 'v', 'v', |
- |
- 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 |
- 0x00, 0x00, 0x00, 0x10, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x02, 'a', 'a', |
- 0x00, 0x02, 'b', 'b', |
- |
- 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
- 0x00, 0x00, 0x00, 0x0c, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- |
- 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF |
- 0x01, 0x00, 0x00, 0x04, |
- 0xde, 0xad, 0xbe, 0xef, |
- }; |
- const unsigned char kV3Input[] = { |
- 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
- 0x00, 0x00, 0x00, 0x1a, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x01, 0x00, 0x00, |
- 0x00, 0x02, 'h', 'h', |
- 0x00, 0x00, 0x00, 0x02, |
- 'v', 'v', |
- |
- 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 |
- 0x00, 0x00, 0x00, 0x16, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x01, 0x00, 0x00, |
- 0x00, 0x02, 'a', 'a', |
- 0x00, 0x00, 0x00, 0x02, |
- 'b', 'b', |
- |
- 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 |
- 0x00, 0x00, 0x00, 0x0c, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- 0xde, 0xad, 0xbe, 0xef, |
- |
- 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF |
- 0x01, 0x00, 0x00, 0x04, |
- 0xde, 0xad, 0xbe, 0xef, |
- }; |
- |
- TestSpdyVisitor visitor; |
- if (SPDY_VERSION_FOR_TESTS < 3) { |
- visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); |
- } else { |
- visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); |
- } |
- |
- EXPECT_EQ(0, visitor.error_count_); |
- EXPECT_EQ(1, visitor.syn_frame_count_); |
- EXPECT_EQ(1, visitor.syn_reply_frame_count_); |
- EXPECT_EQ(0, visitor.headers_frame_count_); |
- EXPECT_EQ(16, visitor.data_bytes_); |
- EXPECT_EQ(0, visitor.fin_frame_count_); |
- EXPECT_EQ(0, visitor.fin_flag_count_); |
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_); |
- EXPECT_EQ(2, visitor.data_frame_count_); |
-} |
- |
-// Test that the FIN flag on a SYN reply frame signifies EOF. |
-TEST_F(SpdyFramerSpdy3Test, FinOnSynReplyFrame) { |
- const unsigned char kV2Input[] = { |
- 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
- 0x00, 0x00, 0x00, 0x14, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x02, 'h', 'h', |
- 0x00, 0x02, 'v', 'v', |
- |
- 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 |
- 0x01, 0x00, 0x00, 0x14, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x02, 'a', 'a', |
- 0x00, 0x02, 'b', 'b', |
- }; |
- const unsigned char kV3Input[] = { |
- 0x80, kVer, 0x00, 0x01, // SYN Stream #1 |
- 0x00, 0x00, 0x00, 0x1a, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x01, 0x00, 0x00, |
- 0x00, 0x02, 'h', 'h', |
- 0x00, 0x00, 0x00, 0x02, |
- 'v', 'v', |
- |
- 0x80, kVer, 0x00, 0x02, // SYN REPLY Stream #1 |
- 0x01, 0x00, 0x00, 0x1a, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x01, 0x00, 0x00, |
- 0x00, 0x02, 'a', 'a', |
- 0x00, 0x00, 0x00, 0x02, |
- 'b', 'b', |
- }; |
- |
- TestSpdyVisitor visitor; |
- if (SPDY_VERSION_FOR_TESTS < 3) { |
- visitor.SimulateInFramer(kV2Input, sizeof(kV2Input)); |
- } else { |
- visitor.SimulateInFramer(kV3Input, sizeof(kV3Input)); |
- } |
- |
- EXPECT_EQ(0, visitor.error_count_); |
- EXPECT_EQ(1, visitor.syn_frame_count_); |
- EXPECT_EQ(1, visitor.syn_reply_frame_count_); |
- EXPECT_EQ(0, visitor.headers_frame_count_); |
- EXPECT_EQ(0, visitor.data_bytes_); |
- EXPECT_EQ(0, visitor.fin_frame_count_); |
- EXPECT_EQ(1, visitor.fin_flag_count_); |
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_); |
- EXPECT_EQ(0, visitor.data_frame_count_); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, HeaderCompression) { |
- SpdyFramer send_framer(kVer); |
- SpdyFramer recv_framer(kVer); |
- |
- send_framer.set_enable_compression(true); |
- recv_framer.set_enable_compression(true); |
- |
- const char kHeader1[] = "header1"; |
- const char kHeader2[] = "header2"; |
- const char kHeader3[] = "header3"; |
- const char kValue1[] = "value1"; |
- const char kValue2[] = "value2"; |
- const char kValue3[] = "value3"; |
- |
- // SYN_STREAM #1 |
- SpdyHeaderBlock block; |
- block[kHeader1] = kValue1; |
- block[kHeader2] = kValue2; |
- SpdyControlFlags flags(CONTROL_FLAG_NONE); |
- scoped_ptr<SpdySynStreamControlFrame> syn_frame_1( |
- send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); |
- EXPECT_TRUE(syn_frame_1.get() != NULL); |
- |
- // SYN_STREAM #2 |
- block[kHeader3] = kValue3; |
- scoped_ptr<SpdySynStreamControlFrame> syn_frame_2( |
- send_framer.CreateSynStream(3, 0, 0, flags, true, &block)); |
- EXPECT_TRUE(syn_frame_2.get() != NULL); |
- |
- // Now start decompressing |
- scoped_ptr<SpdyFrame> decompressed; |
- scoped_ptr<SpdySynStreamControlFrame> syn_frame; |
- scoped_ptr<std::string> serialized_headers; |
- SpdyHeaderBlock decompressed_headers; |
- |
- // Decompress SYN_STREAM #1 |
- decompressed.reset(SpdyFramerTestUtil::DecompressFrame( |
- &recv_framer, *syn_frame_1.get())); |
- EXPECT_TRUE(decompressed.get() != NULL); |
- EXPECT_TRUE(decompressed->is_control_frame()); |
- EXPECT_EQ(SYN_STREAM, |
- reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type()); |
- syn_frame.reset(new SpdySynStreamControlFrame(decompressed->data(), false)); |
- serialized_headers.reset(new std::string(syn_frame->header_block(), |
- syn_frame->header_block_len())); |
- EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(), |
- serialized_headers->size(), |
- &decompressed_headers)); |
- EXPECT_EQ(2u, decompressed_headers.size()); |
- EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); |
- EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); |
- |
- // Decompress SYN_STREAM #2 |
- decompressed.reset(SpdyFramerTestUtil::DecompressFrame( |
- &recv_framer, *syn_frame_2.get())); |
- EXPECT_TRUE(decompressed.get() != NULL); |
- EXPECT_TRUE(decompressed->is_control_frame()); |
- EXPECT_EQ(SYN_STREAM, |
- reinterpret_cast<SpdyControlFrame*>(decompressed.get())->type()); |
- syn_frame.reset(new SpdySynStreamControlFrame(decompressed->data(), false)); |
- serialized_headers.reset(new std::string(syn_frame->header_block(), |
- syn_frame->header_block_len())); |
- decompressed_headers.clear(); |
- EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers->c_str(), |
- serialized_headers->size(), |
- &decompressed_headers)); |
- EXPECT_EQ(3u, decompressed_headers.size()); |
- EXPECT_EQ(kValue1, decompressed_headers[kHeader1]); |
- EXPECT_EQ(kValue2, decompressed_headers[kHeader2]); |
- EXPECT_EQ(kValue3, decompressed_headers[kHeader3]); |
- |
- // We didn't have data streams, so we shouldn't have (de)compressors. |
- EXPECT_EQ(0, send_framer.num_stream_compressors()); |
- EXPECT_EQ(0, send_framer.num_stream_decompressors()); |
- EXPECT_EQ(0, recv_framer.num_stream_compressors()); |
- EXPECT_EQ(0, recv_framer.num_stream_decompressors()); |
-} |
- |
-// Verify we don't leak when we leave streams unclosed |
-TEST_F(SpdyFramerSpdy3Test, UnclosedStreamDataCompressors) { |
- SpdyFramer send_framer(kVer); |
- |
- send_framer.set_enable_compression(true); |
- |
- const char kHeader1[] = "header1"; |
- const char kHeader2[] = "header2"; |
- const char kValue1[] = "value1"; |
- const char kValue2[] = "value2"; |
- |
- SpdyHeaderBlock block; |
- block[kHeader1] = kValue1; |
- block[kHeader2] = kValue2; |
- SpdyControlFlags flags(CONTROL_FLAG_NONE); |
- scoped_ptr<SpdyFrame> syn_frame( |
- send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); |
- EXPECT_TRUE(syn_frame.get() != NULL); |
- |
- const char bytes[] = "this is a test test test test test!"; |
- scoped_ptr<SpdyFrame> send_frame( |
- send_framer.CreateDataFrame( |
- 1, bytes, arraysize(bytes), |
- static_cast<SpdyDataFlags>(DATA_FLAG_FIN))); |
- EXPECT_TRUE(send_frame.get() != NULL); |
- |
- // Run the inputs through the framer. |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = true; |
- const unsigned char* data; |
- data = reinterpret_cast<const unsigned char*>(syn_frame->data()); |
- visitor.SimulateInFramer(data, syn_frame->length() + SpdyFrame::kHeaderSize); |
- data = reinterpret_cast<const unsigned char*>(send_frame->data()); |
- visitor.SimulateInFramer(data, send_frame->length() + SpdyFrame::kHeaderSize); |
- |
- EXPECT_EQ(0, visitor.error_count_); |
- EXPECT_EQ(1, visitor.syn_frame_count_); |
- EXPECT_EQ(0, visitor.syn_reply_frame_count_); |
- EXPECT_EQ(0, visitor.headers_frame_count_); |
- EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); |
- EXPECT_EQ(0, visitor.fin_frame_count_); |
- EXPECT_EQ(0, visitor.fin_flag_count_); |
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_); |
- EXPECT_EQ(1, visitor.data_frame_count_); |
- |
- // We closed the streams, so all compressors should be down. |
- EXPECT_EQ(0, visitor.framer_.num_stream_compressors()); |
- EXPECT_EQ(0, visitor.framer_.num_stream_decompressors()); |
- EXPECT_EQ(0, send_framer.num_stream_compressors()); |
- EXPECT_EQ(0, send_framer.num_stream_decompressors()); |
-} |
- |
-// Verify we can decompress the stream even if handed over to the |
-// framer 1 byte at a time. |
-TEST_F(SpdyFramerSpdy3Test, UnclosedStreamDataCompressorsOneByteAtATime) { |
- SpdyFramer send_framer(kVer); |
- |
- send_framer.set_enable_compression(true); |
- |
- const char kHeader1[] = "header1"; |
- const char kHeader2[] = "header2"; |
- const char kValue1[] = "value1"; |
- const char kValue2[] = "value2"; |
- |
- SpdyHeaderBlock block; |
- block[kHeader1] = kValue1; |
- block[kHeader2] = kValue2; |
- SpdyControlFlags flags(CONTROL_FLAG_NONE); |
- scoped_ptr<SpdyFrame> syn_frame( |
- send_framer.CreateSynStream(1, 0, 0, flags, true, &block)); |
- EXPECT_TRUE(syn_frame.get() != NULL); |
- |
- const char bytes[] = "this is a test test test test test!"; |
- scoped_ptr<SpdyFrame> send_frame( |
- send_framer.CreateDataFrame( |
- 1, bytes, arraysize(bytes), |
- static_cast<SpdyDataFlags>(DATA_FLAG_FIN))); |
- EXPECT_TRUE(send_frame.get() != NULL); |
- |
- // Run the inputs through the framer. |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = true; |
- const unsigned char* data; |
- data = reinterpret_cast<const unsigned char*>(syn_frame->data()); |
- for (size_t idx = 0; |
- idx < syn_frame->length() + SpdyFrame::kHeaderSize; |
- ++idx) { |
- visitor.SimulateInFramer(data + idx, 1); |
- ASSERT_EQ(0, visitor.error_count_); |
- } |
- data = reinterpret_cast<const unsigned char*>(send_frame->data()); |
- for (size_t idx = 0; |
- idx < send_frame->length() + SpdyFrame::kHeaderSize; |
- ++idx) { |
- visitor.SimulateInFramer(data + idx, 1); |
- ASSERT_EQ(0, visitor.error_count_); |
- } |
- |
- EXPECT_EQ(0, visitor.error_count_); |
- EXPECT_EQ(1, visitor.syn_frame_count_); |
- EXPECT_EQ(0, visitor.syn_reply_frame_count_); |
- EXPECT_EQ(0, visitor.headers_frame_count_); |
- EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); |
- EXPECT_EQ(0, visitor.fin_frame_count_); |
- EXPECT_EQ(0, visitor.fin_flag_count_); |
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_); |
- EXPECT_EQ(1, visitor.data_frame_count_); |
- |
- // We closed the streams, so all compressors should be down. |
- EXPECT_EQ(0, visitor.framer_.num_stream_compressors()); |
- EXPECT_EQ(0, visitor.framer_.num_stream_decompressors()); |
- EXPECT_EQ(0, send_framer.num_stream_compressors()); |
- EXPECT_EQ(0, send_framer.num_stream_decompressors()); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, WindowUpdateFrame) { |
- SpdyFramer framer(kVer); |
- scoped_ptr<SpdyWindowUpdateControlFrame> window_update_frame( |
- framer.CreateWindowUpdate(1, 0x12345678)); |
- |
- const unsigned char expected_data_frame[] = { |
- 0x80, kVer, 0x00, 0x09, |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x12, 0x34, 0x56, 0x78 |
- }; |
- |
- EXPECT_EQ(16u, window_update_frame->size()); |
- EXPECT_EQ(0, |
- memcmp(window_update_frame->data(), expected_data_frame, 16)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateDataFrame) { |
- SpdyFramer framer(kVer); |
- |
- { |
- const char kDescription[] = "'hello' data frame, no FIN"; |
- const unsigned char kFrameData[] = { |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x05, |
- 'h', 'e', 'l', 'l', |
- 'o' |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( |
- 1, "hello", 5, DATA_FLAG_NONE)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
- |
- { |
- const char kDescription[] = "Data frame with negative data byte, no FIN"; |
- const unsigned char kFrameData[] = { |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x01, |
- 0xff |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( |
- 1, "\xff", 1, DATA_FLAG_NONE)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
- |
- { |
- const char kDescription[] = "'hello' data frame, with FIN"; |
- const unsigned char kFrameData[] = { |
- 0x00, 0x00, 0x00, 0x01, |
- 0x01, 0x00, 0x00, 0x05, |
- 'h', 'e', 'l', 'l', |
- 'o' |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( |
- 1, "hello", 5, DATA_FLAG_FIN)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
- |
- { |
- const char kDescription[] = "Empty data frame"; |
- const unsigned char kFrameData[] = { |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( |
- 1, "", 0, DATA_FLAG_NONE)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
- |
- { |
- const char kDescription[] = "Data frame with max stream ID"; |
- const unsigned char kFrameData[] = { |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x01, 0x00, 0x00, 0x05, |
- 'h', 'e', 'l', 'l', |
- 'o' |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( |
- 0x7fffffff, "hello", 5, DATA_FLAG_FIN)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
- |
- { |
- const char kDescription[] = "Large data frame"; |
- const int kDataSize = 4 * 1024 * 1024; // 4 MB |
- const std::string kData(kDataSize, 'A'); |
- const unsigned char kFrameHeader[] = { |
- 0x00, 0x00, 0x00, 0x01, |
- 0x01, 0x40, 0x00, 0x00, |
- }; |
- |
- const int kFrameSize = arraysize(kFrameHeader) + kDataSize; |
- scoped_array<unsigned char> expected_frame_data( |
- new unsigned char[kFrameSize]); |
- memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader)); |
- memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize); |
- |
- scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame( |
- 1, kData.data(), kData.size(), DATA_FLAG_FIN)); |
- CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateSynStreamUncompressed) { |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(false); |
- |
- { |
- const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const unsigned char kPri = |
- (SPDY_VERSION_FOR_TESTS != 2) ? 0xE0 : 0xC0; |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x20, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- kPri, 0x00, 0x00, 0x02, |
- 0x00, 0x03, 'b', 'a', |
- 'r', 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x03, 'b', 'a', 'r' |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x2a, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- kPri, 0x00, 0x00, 0x00, |
- 0x00, 0x02, 0x00, 0x00, |
- 0x00, 0x03, 'b', 'a', |
- 'r', 0x00, 0x00, 0x00, |
- 0x03, 'f', 'o', 'o', |
- 0x00, 0x00, 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x00, 0x00, 0x03, 'b', |
- 'a', 'r' |
- }; |
- scoped_ptr<SpdySynStreamControlFrame> frame(framer.CreateSynStream( |
- 1, 0, framer.GetLowestPriority(), CONTROL_FLAG_NONE, false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); |
- } |
- |
- { |
- const char kDescription[] = |
- "SYN_STREAM frame with a 0-length header name, highest pri, FIN, " |
- "max stream ID"; |
- |
- SpdyHeaderBlock headers; |
- headers[""] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x01, |
- 0x01, 0x00, 0x00, 0x1D, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x03, 'f', 'o', 'o', |
- 0x00, 0x03, 'b', 'a', |
- 'r' |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x01, |
- 0x01, 0x00, 0x00, 0x27, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x02, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x03, 'f', 'o', |
- 'o', 0x00, 0x00, 0x00, |
- 0x03, 'f', 'o', 'o', |
- 0x00, 0x00, 0x00, 0x03, |
- 'b', 'a', 'r' |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( |
- 0x7fffffff, 0x7fffffff, framer.GetHighestPriority(), CONTROL_FLAG_FIN, |
- false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
- |
- { |
- const char kDescription[] = |
- "SYN_STREAM frame with a 0-length header val, high pri, FIN, " |
- "max stream ID"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = ""; |
- |
- const unsigned char kPri = |
- (SPDY_VERSION_FOR_TESTS != 2) ? 0x20 : 0x40; |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x01, |
- 0x01, 0x00, 0x00, 0x1D, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x7f, 0xff, 0xff, 0xff, |
- kPri, 0x00, 0x00, 0x02, |
- 0x00, 0x03, 'b', 'a', |
- 'r', 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x00 |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x01, |
- 0x01, 0x00, 0x00, 0x27, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x7f, 0xff, 0xff, 0xff, |
- kPri, 0x00, 0x00, 0x00, |
- 0x00, 0x02, 0x00, 0x00, |
- 0x00, 0x03, 'b', 'a', |
- 'r', 0x00, 0x00, 0x00, |
- 0x03, 'f', 'o', 'o', |
- 0x00, 0x00, 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x00, 0x00, 0x00 |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( |
- 0x7fffffff, 0x7fffffff, 1, CONTROL_FLAG_FIN, false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateSynStreamCompressed) { |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(true); |
- |
- { |
- const char kDescription[] = |
- "SYN_STREAM frame, low pri, no FIN"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const SpdyPriority priority = |
- (SPDY_VERSION_FOR_TESTS != 2) ? 4 : 2; |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x25, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x80, 0x00, 0x38, 0xea, |
- 0xdf, 0xa2, 0x51, 0xb2, |
- 0x62, 0x60, 0x62, 0x60, |
- 0x4e, 0x4a, 0x2c, 0x62, |
- 0x60, 0x4e, 0xcb, 0xcf, |
- 0x87, 0x12, 0x40, 0x2e, |
- 0x00, 0x00, 0x00, 0xff, |
- 0xff |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x27, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x80, 0x00, 0x38, 0xEA, |
- 0xE3, 0xC6, 0xA7, 0xC2, |
- 0x02, 0xE5, 0x0E, 0x50, |
- 0xC2, 0x4B, 0x4A, 0x04, |
- 0xE5, 0x0B, 0xE6, 0xB4, |
- 0xFC, 0x7C, 0x24, 0x0A, |
- 0x28, 0x08, 0x00, 0x00, |
- 0x00, 0xFF, 0xFF |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateSynStream( |
- 1, 0, priority, CONTROL_FLAG_NONE, true, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateSynReplyUncompressed) { |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(false); |
- |
- { |
- const char kDescription[] = "SYN_REPLY frame, no FIN"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x1C, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x03, 'b', 'a', |
- 'r', 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x03, 'b', 'a', 'r' |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x24, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x03, |
- 'b', 'a', 'r', 0x00, |
- 0x00, 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x00, |
- 0x00, 0x03, 'f', 'o', |
- 'o', 0x00, 0x00, 0x00, |
- 0x03, 'b', 'a', 'r' |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( |
- 1, CONTROL_FLAG_NONE, false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
- |
- { |
- const char kDescription[] = |
- "SYN_REPLY frame with a 0-length header name, FIN, max stream ID"; |
- |
- SpdyHeaderBlock headers; |
- headers[""] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x02, |
- 0x01, 0x00, 0x00, 0x19, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x03, 'f', 'o', 'o', |
- 0x00, 0x03, 'b', 'a', |
- 'r' |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x02, |
- 0x01, 0x00, 0x00, 0x21, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x00, 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x00, |
- 0x00, 0x03, 'b', 'a', |
- 'r' |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( |
- 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
- |
- { |
- const char kDescription[] = |
- "SYN_REPLY frame with a 0-length header val, FIN, max stream ID"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = ""; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x02, |
- 0x01, 0x00, 0x00, 0x19, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x03, 'b', 'a', |
- 'r', 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x00 |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x02, |
- 0x01, 0x00, 0x00, 0x21, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x03, |
- 'b', 'a', 'r', 0x00, |
- 0x00, 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x00, |
- 0x00, 0x03, 'f', 'o', |
- 'o', 0x00, 0x00, 0x00, |
- 0x00 |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( |
- 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateSynReplyCompressed) { |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(true); |
- |
- { |
- const char kDescription[] = "SYN_REPLY frame, no FIN"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x21, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x38, 0xea, |
- 0xdf, 0xa2, 0x51, 0xb2, |
- 0x62, 0x60, 0x62, 0x60, |
- 0x4e, 0x4a, 0x2c, 0x62, |
- 0x60, 0x4e, 0xcb, 0xcf, |
- 0x87, 0x12, 0x40, 0x2e, |
- 0x00, 0x00, 0x00, 0xff, |
- 0xff |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x21, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x38, 0xea, 0xe3, 0xc6, |
- 0xa7, 0xc2, 0x02, 0xe5, |
- 0x0e, 0x50, 0xc2, 0x4b, |
- 0x4a, 0x04, 0xe5, 0x0b, |
- 0xe6, 0xb4, 0xfc, 0x7c, |
- 0x24, 0x0a, 0x28, 0x08, |
- 0x00, 0x00, 0x00, 0xff, |
- 0xff |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( |
- 1, CONTROL_FLAG_NONE, true, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateRstStream) { |
- SpdyFramer framer(kVer); |
- |
- { |
- const char kDescription[] = "RST_STREAM frame"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x03, |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x01, |
- }; |
- scoped_ptr<SpdyRstStreamControlFrame> frame( |
- framer.CreateRstStream(1, PROTOCOL_ERROR)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); |
- } |
- |
- { |
- const char kDescription[] = "RST_STREAM frame with max stream ID"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x03, |
- 0x00, 0x00, 0x00, 0x08, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x01, |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF, |
- PROTOCOL_ERROR)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
- |
- { |
- const char kDescription[] = "RST_STREAM frame with max status code"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x03, |
- 0x00, 0x00, 0x00, 0x08, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x06, |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF, |
- INTERNAL_ERROR)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateSettings) { |
- SpdyFramer framer(kVer); |
- |
- { |
- const char kDescription[] = "Network byte order SETTINGS frame"; |
- |
- uint32 kValue = 0x0a0b0c0d; |
- uint8 kFlags = 0x04; |
- uint32 kId = 0x030201; |
- SettingsFlagsAndId idAndFlags(kFlags, kId); |
- |
- SpdySettings settings; |
- settings.push_back(SpdySetting(idAndFlags, kValue)); |
- |
- EXPECT_EQ(kValue, settings.back().second); |
- EXPECT_EQ(kFlags, settings.back().first.flags()); |
- EXPECT_EQ(kId, settings.back().first.id()); |
- |
- const unsigned char kFrameDatav2[] = { |
- 0x80, kVer, 0x00, 0x04, |
- 0x00, 0x00, 0x00, 0x0c, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x01, 0x02, 0x03, 0x04, |
- 0x0a, 0x0b, 0x0c, 0x0d, |
- }; |
- |
- const unsigned char kFrameDatav3[] = { |
- 0x80, kVer, 0x00, 0x04, |
- 0x00, 0x00, 0x00, 0x0c, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x04, 0x03, 0x02, 0x01, |
- 0x0a, 0x0b, 0x0c, 0x0d, |
- }; |
- |
- scoped_ptr<SpdySettingsControlFrame> frame(framer.CreateSettings(settings)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kFrameDatav2 : kFrameDatav3, |
- arraysize(kFrameDatav3)); // Size is unchanged among versions. |
- EXPECT_EQ(SpdyFramer::kInvalidStream, |
- SpdyFramer::GetControlFrameStreamId(frame.get())); |
- |
- // Make sure that ParseSettings also works as advertised. |
- SpdySettings parsed_settings; |
- EXPECT_TRUE(framer.ParseSettings(frame.get(), &parsed_settings)); |
- EXPECT_EQ(settings.size(), parsed_settings.size()); |
- EXPECT_EQ(kFlags, parsed_settings.back().first.flags()); |
- EXPECT_EQ(kId, parsed_settings.back().first.id()); |
- } |
- |
- { |
- const char kDescription[] = "Basic SETTINGS frame"; |
- |
- SpdySettings settings; |
- settings.push_back( |
- SpdySettingFromWireFormat(0x00000000, 0x00000000)); // 1st Setting |
- settings.push_back( |
- SpdySettingFromWireFormat(0xffffffff, 0x00000001)); // 2nd Setting |
- settings.push_back( |
- SpdySettingFromWireFormat(0xff000001, 0x00000002)); // 3rd Setting |
- |
- // Duplicates allowed |
- settings.push_back( |
- SpdySettingFromWireFormat(0x01000002, 0x00000003)); // 4th Setting |
- settings.push_back( |
- SpdySettingFromWireFormat(0x01000002, 0x00000003)); // 5th Setting |
- |
- settings.push_back( |
- SpdySettingFromWireFormat(0x01000003, 0x000000ff)); // 6th Setting |
- settings.push_back( |
- SpdySettingFromWireFormat(0x01000004, 0xff000001)); // 7th Setting |
- settings.push_back( |
- SpdySettingFromWireFormat(0x01000004, 0xffffffff)); // 8th Setting |
- |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x04, |
- 0x00, 0x00, 0x00, 0x44, |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x00, // 1st Setting |
- 0x00, 0x00, 0x00, 0x00, |
- 0xff, 0xff, 0xff, 0xff, // 2nd Setting |
- 0x00, 0x00, 0x00, 0x01, |
- 0x01, 0x00, 0x00, 0xff, // 3rd Setting |
- 0x00, 0x00, 0x00, 0x02, |
- 0x02, 0x00, 0x00, 0x01, // 4th Setting |
- 0x00, 0x00, 0x00, 0x03, |
- 0x02, 0x00, 0x00, 0x01, // 5th Setting |
- 0x00, 0x00, 0x00, 0x03, |
- 0x03, 0x00, 0x00, 0x01, // 6th Setting |
- 0x00, 0x00, 0x00, 0xff, |
- 0x04, 0x00, 0x00, 0x01, // 7th Setting |
- 0xff, 0x00, 0x00, 0x01, |
- 0x04, 0x00, 0x00, 0x01, // 8th Setting |
- 0xff, 0xff, 0xff, 0xff, |
- }; |
- scoped_ptr<SpdySettingsControlFrame> frame(framer.CreateSettings(settings)); |
- CompareFrame(kDescription, |
- *frame, |
- kFrameData, |
- arraysize(kFrameData)); |
- EXPECT_EQ(SpdyFramer::kInvalidStream, |
- SpdyFramer::GetControlFrameStreamId(frame.get())); |
- } |
- |
- { |
- const char kDescription[] = "Empty SETTINGS frame"; |
- |
- SpdySettings settings; |
- |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x04, |
- 0x00, 0x00, 0x00, 0x04, |
- 0x00, 0x00, 0x00, 0x00, |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreatePingFrame) { |
- SpdyFramer framer(kVer); |
- |
- { |
- const char kDescription[] = "PING frame"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x06, |
- 0x00, 0x00, 0x00, 0x04, |
- 0x12, 0x34, 0x56, 0x78, |
- }; |
- scoped_ptr<SpdyPingControlFrame> frame(framer.CreatePingFrame(0x12345678u)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- EXPECT_EQ(SpdyFramer::kInvalidStream, |
- SpdyFramer::GetControlFrameStreamId(frame.get())); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateGoAway) { |
- SpdyFramer framer(kVer); |
- |
- { |
- const char kDescription[] = "GOAWAY frame"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x07, |
- 0x00, 0x00, 0x00, 0x04, |
- 0x00, 0x00, 0x00, 0x00, |
- }; |
- scoped_ptr<SpdyGoAwayControlFrame> frame(framer.CreateGoAway(0)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- EXPECT_EQ(SpdyFramer::kInvalidStream, |
- SpdyFramer::GetControlFrameStreamId(frame.get())); |
- } |
- |
- { |
- const char kDescription[] = "GOAWAY frame with max stream ID"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x07, |
- 0x00, 0x00, 0x00, 0x04, |
- 0x7f, 0xff, 0xff, 0xff, |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateHeadersUncompressed) { |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(false); |
- |
- { |
- const char kDescription[] = "HEADERS frame, no FIN"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x1C, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x03, 'b', 'a', |
- 'r', 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x03, 'b', 'a', 'r' |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x24, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x03, |
- 'b', 'a', 'r', 0x00, |
- 0x00, 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x00, |
- 0x00, 0x03, 'f', 'o', |
- 'o', 0x00, 0x00, 0x00, |
- 0x03, 'b', 'a', 'r' |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( |
- 1, CONTROL_FLAG_NONE, false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
- |
- { |
- const char kDescription[] = |
- "HEADERS frame with a 0-length header name, FIN, max stream ID"; |
- |
- SpdyHeaderBlock headers; |
- headers[""] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x08, |
- 0x01, 0x00, 0x00, 0x19, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x03, 'f', 'o', 'o', |
- 0x00, 0x03, 'b', 'a', |
- 'r' |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x08, |
- 0x01, 0x00, 0x00, 0x21, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x00, 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x00, |
- 0x00, 0x03, 'b', 'a', |
- 'r' |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( |
- 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
- |
- { |
- const char kDescription[] = |
- "HEADERS frame with a 0-length header val, FIN, max stream ID"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = ""; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x08, |
- 0x01, 0x00, 0x00, 0x19, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x03, 'b', 'a', |
- 'r', 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x03, |
- 'f', 'o', 'o', 0x00, |
- 0x00 |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x08, |
- 0x01, 0x00, 0x00, 0x21, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x02, |
- 0x00, 0x00, 0x00, 0x03, |
- 'b', 'a', 'r', 0x00, |
- 0x00, 0x00, 0x03, 'f', |
- 'o', 'o', 0x00, 0x00, |
- 0x00, 0x03, 'f', 'o', |
- 'o', 0x00, 0x00, 0x00, |
- 0x00 |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( |
- 0x7fffffff, CONTROL_FLAG_FIN, false, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateHeadersCompressed) { |
- SpdyFramer framer(kVer); |
- framer.set_enable_compression(true); |
- |
- { |
- const char kDescription[] = "HEADERS frame, no FIN"; |
- |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = "bar"; |
- |
- const unsigned char kV2FrameData[] = { |
- 0x80, kVer, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x21, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x38, 0xea, |
- 0xdf, 0xa2, 0x51, 0xb2, |
- 0x62, 0x60, 0x62, 0x60, |
- 0x4e, 0x4a, 0x2c, 0x62, |
- 0x60, 0x4e, 0xcb, 0xcf, |
- 0x87, 0x12, 0x40, 0x2e, |
- 0x00, 0x00, 0x00, 0xff, |
- 0xff |
- }; |
- const unsigned char kV3FrameData[] = { |
- 0x80, kVer, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x21, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x38, 0xea, 0xe3, 0xc6, |
- 0xa7, 0xc2, 0x02, 0xe5, |
- 0x0e, 0x50, 0xc2, 0x4b, |
- 0x4a, 0x04, 0xe5, 0x0b, |
- 0xe6, 0xb4, 0xfc, 0x7c, |
- 0x24, 0x0a, 0x28, 0x08, |
- 0x00, 0x00, 0x00, 0xff, |
- 0xff |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( |
- 1, CONTROL_FLAG_NONE, true, &headers)); |
- CompareFrame(kDescription, |
- *frame, |
- (SPDY_VERSION_FOR_TESTS < 3) ? kV2FrameData : kV3FrameData, |
- (SPDY_VERSION_FOR_TESTS < 3) ? arraysize(kV2FrameData) |
- : arraysize(kV3FrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CreateWindowUpdate) { |
- SpdyFramer framer(kVer); |
- |
- { |
- const char kDescription[] = "WINDOW_UPDATE frame"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x09, |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x00, 0x00, 0x00, 0x01, |
- }; |
- scoped_ptr<SpdyWindowUpdateControlFrame> frame( |
- framer.CreateWindowUpdate(1, 1)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- EXPECT_EQ(1u, SpdyFramer::GetControlFrameStreamId(frame.get())); |
- } |
- |
- { |
- const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x09, |
- 0x00, 0x00, 0x00, 0x08, |
- 0x7f, 0xff, 0xff, 0xff, |
- 0x00, 0x00, 0x00, 0x01, |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
- |
- { |
- const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x09, |
- 0x00, 0x00, 0x00, 0x08, |
- 0x00, 0x00, 0x00, 0x01, |
- 0x7f, 0xff, 0xff, 0xff, |
- }; |
- scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF)); |
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData)); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, DuplicateFrame) { |
- SpdyFramer framer(kVer); |
- |
- { |
- const char kDescription[] = "PING frame"; |
- const unsigned char kFrameData[] = { |
- 0x80, kVer, 0x00, 0x06, |
- 0x00, 0x00, 0x00, 0x04, |
- 0x12, 0x34, 0x56, 0x78, |
- }; |
- scoped_ptr<SpdyFrame> frame1(framer.CreatePingFrame(0x12345678u)); |
- CompareFrame(kDescription, *frame1, kFrameData, arraysize(kFrameData)); |
- |
- scoped_ptr<SpdyFrame> frame2(framer.DuplicateFrame(*frame1)); |
- CompareFrame(kDescription, *frame2, kFrameData, arraysize(kFrameData)); |
- } |
-} |
- |
-// This test case reproduces conditions that caused ExpandControlFrameBuffer to |
-// fail to expand the buffer control frame buffer when it should have, allowing |
-// the framer to overrun the buffer, and smash other heap contents. This test |
-// relies on the debug version of the heap manager, which checks for buffer |
-// overrun errors during delete processing. Regression test for b/2974814. |
-TEST_F(SpdyFramerSpdy3Test, ExpandBuffer_HeapSmash) { |
- // Sweep through the area of problematic values, to make sure we always cover |
- // the danger zone, even if it moves around at bit due to SPDY changes. |
- for (uint16 val2_len = SpdyFramer::kControlFrameBufferInitialSize - 50; |
- val2_len < SpdyFramer::kControlFrameBufferInitialSize; |
- val2_len++) { |
- std::string val2 = std::string(val2_len, 'a'); |
- SpdyHeaderBlock headers; |
- headers["bar"] = "foo"; |
- headers["foo"] = "baz"; |
- headers["grue"] = val2.c_str(); |
- SpdyFramer framer(kVer); |
- scoped_ptr<SpdySynStreamControlFrame> template_frame( |
- framer.CreateSynStream(1, // stream_id |
- 0, // associated_stream_id |
- 1, // priority |
- CONTROL_FLAG_NONE, |
- false, // compress |
- &headers)); |
- EXPECT_TRUE(template_frame.get() != NULL); |
- TestSpdyVisitor visitor; |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(template_frame.get()->data()), |
- template_frame.get()->length() + SpdyControlFrame::kHeaderSize); |
- EXPECT_EQ(1, visitor.syn_frame_count_); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ControlFrameSizesAreValidated) { |
- // Create a GoAway frame that has a few extra bytes at the end. |
- // We create enough overhead to require the framer to expand its frame buffer. |
- size_t overhead = SpdyFramer::kUncompressedControlFrameBufferInitialSize; |
- SpdyFramer framer(kVer); |
- scoped_ptr<SpdyGoAwayControlFrame> goaway(framer.CreateGoAway(1)); |
- goaway->set_length(goaway->length() + overhead); |
- std::string pad('A', overhead); |
- TestSpdyVisitor visitor; |
- |
- // First attempt without validation on. |
- visitor.framer_.set_validate_control_frame_sizes(false); |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(goaway->data()), |
- goaway->length() - overhead + SpdyControlFrame::kHeaderSize); |
- visitor.SimulateInFramer( |
- reinterpret_cast<const unsigned char*>(pad.c_str()), |
- overhead); |
- EXPECT_EQ(0, visitor.error_count_); // Not an error. |
- EXPECT_EQ(1, visitor.goaway_count_); // The goaway was parsed. |
- |
- // Attempt with validation on. |
- visitor.framer_.set_validate_control_frame_sizes(true); |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(goaway->data()), |
- goaway->length() - overhead + SpdyControlFrame::kHeaderSize); |
- visitor.SimulateInFramer( |
- reinterpret_cast<const unsigned char*>(pad.c_str()), |
- overhead); |
- EXPECT_EQ(1, visitor.error_count_); // This generated an error. |
- EXPECT_EQ(1, visitor.goaway_count_); // Unchanged from before. |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ReadZeroLenSettingsFrame) { |
- SpdyFramer framer(kVer); |
- SpdySettings settings; |
- scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
- control_frame->set_length(0); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(control_frame->data()), |
- control_frame.get()->length() + SpdyControlFrame::kHeaderSize); |
- // Should generate an error, since zero-len settings frames are unsupported. |
- EXPECT_EQ(1, visitor.error_count_); |
-} |
- |
-// Tests handling of SETTINGS frames with invalid length. |
-TEST_F(SpdyFramerSpdy3Test, ReadBogusLenSettingsFrame) { |
- SpdyFramer framer(kVer); |
- SpdySettings settings; |
- // Add a setting to pad the frame so that we don't get a buffer overflow when |
- // calling SimulateInFramer() below. |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); |
- scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
- control_frame->set_length(5); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(control_frame->data()), |
- control_frame.get()->length() + SpdyControlFrame::kHeaderSize); |
- // Should generate an error, since zero-len settings frames are unsupported. |
- EXPECT_EQ(1, visitor.error_count_); |
-} |
- |
-// Tests handling of SETTINGS frames larger than the frame buffer size. |
-TEST_F(SpdyFramerSpdy3Test, ReadLargeSettingsFrame) { |
- SpdyFramer framer(kVer); |
- SpdySettings settings; |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 2), 0x00000003)); |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000004)); |
- scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
- EXPECT_LT(SpdyFramer::kUncompressedControlFrameBufferInitialSize, |
- control_frame->length() + SpdyControlFrame::kHeaderSize); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- |
- // Read all at once. |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(control_frame->data()), |
- control_frame->length() + SpdyControlFrame::kHeaderSize); |
- EXPECT_EQ(0, visitor.error_count_); |
- EXPECT_EQ(settings.size(), static_cast<unsigned>(visitor.setting_count_)); |
- EXPECT_EQ(1, visitor.settings_frame_count_); |
- |
- // Read data in small chunks. |
- size_t framed_data = 0; |
- size_t unframed_data = control_frame->length() + |
- SpdyControlFrame::kHeaderSize; |
- size_t kReadChunkSize = 5; // Read five bytes at a time. |
- while (unframed_data > 0) { |
- size_t to_read = std::min(kReadChunkSize, unframed_data); |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(control_frame->data() + framed_data), |
- to_read); |
- unframed_data -= to_read; |
- framed_data += to_read; |
- } |
- EXPECT_EQ(0, visitor.error_count_); |
- EXPECT_EQ(settings.size() * 2, static_cast<unsigned>(visitor.setting_count_)); |
- EXPECT_EQ(2, visitor.settings_frame_count_); |
-} |
- |
-// Tests handling of SETTINGS frame with duplicate entries. |
-TEST_F(SpdyFramerSpdy3Test, ReadDuplicateSettings) { |
- SpdyFramer framer(kVer); |
- SpdySettings settings; |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000002)); |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000003)); |
- // This last setting should not be processed due to error above. |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000003)); |
- scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(control_frame->data()), |
- control_frame->length() + SpdyControlFrame::kHeaderSize); |
- EXPECT_EQ(1, visitor.error_count_); |
- EXPECT_EQ(1, visitor.setting_count_); |
- EXPECT_EQ(1, visitor.settings_frame_count_); |
-} |
- |
-// Tests handling of SETTINGS frame with entries out of order. |
-TEST_F(SpdyFramerSpdy3Test, ReadOutOfOrderSettings) { |
- SpdyFramer framer(kVer); |
- SpdySettings settings; |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 2), 0x00000002)); |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 1), 0x00000003)); |
- // This last setting should not be processed due to error above. |
- settings.push_back(SpdySetting(SettingsFlagsAndId(0, 3), 0x00000003)); |
- scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings)); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(control_frame->data()), |
- control_frame->length() + SpdyControlFrame::kHeaderSize); |
- EXPECT_EQ(1, visitor.error_count_); |
- EXPECT_EQ(1, visitor.setting_count_); |
- EXPECT_EQ(1, visitor.settings_frame_count_); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ReadCredentialFrame) { |
- SpdyCredential credential; |
- credential.slot = 3; |
- credential.proof = "proof"; |
- credential.certs.push_back("a cert"); |
- credential.certs.push_back("another cert"); |
- credential.certs.push_back("final cert"); |
- SpdyFramer framer(kVer); |
- scoped_ptr<SpdyFrame> control_frame( |
- framer.CreateCredentialFrame(credential)); |
- EXPECT_TRUE(control_frame.get() != NULL); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(control_frame.get()->data()), |
- control_frame.get()->length() + SpdyControlFrame::kHeaderSize); |
- EXPECT_EQ(0, visitor.error_count_); |
- EXPECT_EQ(1, visitor.credential_count_); |
- EXPECT_EQ(control_frame->length(), visitor.credential_buffer_length_); |
- EXPECT_EQ(credential.slot, visitor.credential_.slot); |
- EXPECT_EQ(credential.proof, visitor.credential_.proof); |
- EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size()); |
- for (size_t i = 0; i < credential.certs.size(); i++) { |
- EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ReadCredentialFrameWithCorruptProof) { |
- SpdyCredential credential; |
- credential.slot = 3; |
- credential.proof = "proof"; |
- credential.certs.push_back("a cert"); |
- credential.certs.push_back("another cert"); |
- credential.certs.push_back("final cert"); |
- SpdyFramer framer(kVer); |
- scoped_ptr<SpdyFrame> control_frame( |
- framer.CreateCredentialFrame(credential)); |
- EXPECT_TRUE(control_frame.get() != NULL); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- unsigned char* data = |
- reinterpret_cast<unsigned char*>(control_frame.get()->data()); |
- size_t offset = SpdyControlFrame::kHeaderSize + 4; |
- data[offset] = 0xFF; // Proof length is past the end of the frame |
- visitor.SimulateInFramer( |
- data, control_frame.get()->length() + SpdyControlFrame::kHeaderSize); |
- EXPECT_EQ(1, visitor.error_count_); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ReadCredentialFrameWithCorruptCertificate) { |
- SpdyCredential credential; |
- credential.slot = 3; |
- credential.proof = "proof"; |
- credential.certs.push_back("a cert"); |
- credential.certs.push_back("another cert"); |
- credential.certs.push_back("final cert"); |
- SpdyFramer framer(kVer); |
- scoped_ptr<SpdyFrame> control_frame( |
- framer.CreateCredentialFrame(credential)); |
- EXPECT_TRUE(control_frame.get() != NULL); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- unsigned char* data = |
- reinterpret_cast<unsigned char*>(control_frame.get()->data()); |
- size_t offset = SpdyControlFrame::kHeaderSize + credential.proof.length(); |
- data[offset] = 0xFF; // Certificate length is past the end of the frame |
- visitor.SimulateInFramer( |
- data, control_frame.get()->length() + SpdyControlFrame::kHeaderSize); |
- EXPECT_EQ(1, visitor.error_count_); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ReadGarbage) { |
- SpdyFramer framer(kVer); |
- unsigned char garbage_frame[256]; |
- memset(garbage_frame, ~0, sizeof(garbage_frame)); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame)); |
- EXPECT_EQ(1, visitor.error_count_); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ReadGarbageWithValidVersion) { |
- SpdyFramer framer(kVer); |
- char garbage_frame[256]; |
- memset(garbage_frame, ~0, sizeof(garbage_frame)); |
- SpdyControlFrame control_frame(&garbage_frame[0], false); |
- control_frame.set_version(SPDY_VERSION_FOR_TESTS); |
- TestSpdyVisitor visitor; |
- visitor.use_compression_ = false; |
- visitor.SimulateInFramer( |
- reinterpret_cast<unsigned char*>(control_frame.data()), |
- sizeof(garbage_frame)); |
- EXPECT_EQ(1, visitor.error_count_); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, StateToStringTest) { |
- EXPECT_STREQ("ERROR", |
- SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR)); |
- EXPECT_STREQ("DONE", |
- SpdyFramer::StateToString(SpdyFramer::SPDY_DONE)); |
- EXPECT_STREQ("AUTO_RESET", |
- SpdyFramer::StateToString(SpdyFramer::SPDY_AUTO_RESET)); |
- EXPECT_STREQ("RESET", |
- SpdyFramer::StateToString(SpdyFramer::SPDY_RESET)); |
- EXPECT_STREQ("READING_COMMON_HEADER", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_READING_COMMON_HEADER)); |
- EXPECT_STREQ("CONTROL_FRAME_PAYLOAD", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD)); |
- EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD)); |
- EXPECT_STREQ("FORWARD_STREAM_FRAME", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_FORWARD_STREAM_FRAME)); |
- EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK)); |
- EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK)); |
- EXPECT_STREQ("SPDY_CREDENTIAL_FRAME_PAYLOAD", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD)); |
- EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD)); |
- EXPECT_STREQ("UNKNOWN_STATE", |
- SpdyFramer::StateToString( |
- SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD + 1)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ErrorCodeToStringTest) { |
- EXPECT_STREQ("NO_ERROR", |
- SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR)); |
- EXPECT_STREQ("INVALID_CONTROL_FRAME", |
- SpdyFramer::ErrorCodeToString( |
- SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); |
- EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE", |
- SpdyFramer::ErrorCodeToString( |
- SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); |
- EXPECT_STREQ("ZLIB_INIT_FAILURE", |
- SpdyFramer::ErrorCodeToString( |
- SpdyFramer::SPDY_ZLIB_INIT_FAILURE)); |
- EXPECT_STREQ("UNSUPPORTED_VERSION", |
- SpdyFramer::ErrorCodeToString( |
- SpdyFramer::SPDY_UNSUPPORTED_VERSION)); |
- EXPECT_STREQ("DECOMPRESS_FAILURE", |
- SpdyFramer::ErrorCodeToString( |
- SpdyFramer::SPDY_DECOMPRESS_FAILURE)); |
- EXPECT_STREQ("COMPRESS_FAILURE", |
- SpdyFramer::ErrorCodeToString( |
- SpdyFramer::SPDY_COMPRESS_FAILURE)); |
- EXPECT_STREQ("UNKNOWN_ERROR", |
- SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, StatusCodeToStringTest) { |
- EXPECT_STREQ("INVALID", |
- SpdyFramer::StatusCodeToString(INVALID)); |
- EXPECT_STREQ("PROTOCOL_ERROR", |
- SpdyFramer::StatusCodeToString(PROTOCOL_ERROR)); |
- EXPECT_STREQ("INVALID_STREAM", |
- SpdyFramer::StatusCodeToString(INVALID_STREAM)); |
- EXPECT_STREQ("REFUSED_STREAM", |
- SpdyFramer::StatusCodeToString(REFUSED_STREAM)); |
- EXPECT_STREQ("UNSUPPORTED_VERSION", |
- SpdyFramer::StatusCodeToString(UNSUPPORTED_VERSION)); |
- EXPECT_STREQ("CANCEL", |
- SpdyFramer::StatusCodeToString(CANCEL)); |
- EXPECT_STREQ("INTERNAL_ERROR", |
- SpdyFramer::StatusCodeToString(INTERNAL_ERROR)); |
- EXPECT_STREQ("FLOW_CONTROL_ERROR", |
- SpdyFramer::StatusCodeToString(FLOW_CONTROL_ERROR)); |
- EXPECT_STREQ("UNKNOWN_STATUS", |
- SpdyFramer::StatusCodeToString(NUM_STATUS_CODES)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, ControlTypeToStringTest) { |
- EXPECT_STREQ("SYN_STREAM", |
- SpdyFramer::ControlTypeToString(SYN_STREAM)); |
- EXPECT_STREQ("SYN_REPLY", |
- SpdyFramer::ControlTypeToString(SYN_REPLY)); |
- EXPECT_STREQ("RST_STREAM", |
- SpdyFramer::ControlTypeToString(RST_STREAM)); |
- EXPECT_STREQ("SETTINGS", |
- SpdyFramer::ControlTypeToString(SETTINGS)); |
- EXPECT_STREQ("NOOP", |
- SpdyFramer::ControlTypeToString(NOOP)); |
- EXPECT_STREQ("PING", |
- SpdyFramer::ControlTypeToString(PING)); |
- EXPECT_STREQ("GOAWAY", |
- SpdyFramer::ControlTypeToString(GOAWAY)); |
- EXPECT_STREQ("HEADERS", |
- SpdyFramer::ControlTypeToString(HEADERS)); |
- EXPECT_STREQ("WINDOW_UPDATE", |
- SpdyFramer::ControlTypeToString(WINDOW_UPDATE)); |
- EXPECT_STREQ("CREDENTIAL", |
- SpdyFramer::ControlTypeToString(CREDENTIAL)); |
- EXPECT_STREQ("UNKNOWN_CONTROL_TYPE", |
- SpdyFramer::ControlTypeToString(NUM_CONTROL_FRAME_TYPES)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, GetMinimumControlFrameSizeTest) { |
- EXPECT_EQ(SpdySynStreamControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(SYN_STREAM)); |
- EXPECT_EQ(SpdySynReplyControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(SYN_REPLY)); |
- EXPECT_EQ(SpdyRstStreamControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(RST_STREAM)); |
- EXPECT_EQ(SpdySettingsControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(SETTINGS)); |
- EXPECT_EQ(SpdyFrame::kHeaderSize, |
- SpdyFramer::GetMinimumControlFrameSize(NOOP)); |
- EXPECT_EQ(SpdyPingControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(PING)); |
- EXPECT_EQ(SpdyGoAwayControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(GOAWAY)); |
- EXPECT_EQ(SpdyHeadersControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(HEADERS)); |
- EXPECT_EQ(SpdyWindowUpdateControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(WINDOW_UPDATE)); |
- EXPECT_EQ(SpdyCredentialControlFrame::size(), |
- SpdyFramer::GetMinimumControlFrameSize(CREDENTIAL)); |
- EXPECT_EQ(static_cast<size_t>(0x7FFFFFFF), |
- SpdyFramer::GetMinimumControlFrameSize(NUM_CONTROL_FRAME_TYPES)); |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, CatchProbableHttpResponse) { |
- SpdyFramerTestUtil::DecompressionVisitor visitor; |
- visitor.set_allow_data_frames(true); |
- { |
- SpdyFramer framer(kVer); |
- framer.set_visitor(&visitor); |
- framer.ProcessInput("HTTP/1.1", 8); |
- EXPECT_TRUE(framer.probable_http_response()); |
- } |
- { |
- SpdyFramer framer(kVer); |
- framer.set_visitor(&visitor); |
- framer.ProcessInput("HTTP/1.0", 8); |
- EXPECT_TRUE(framer.probable_http_response()); |
- } |
-} |
- |
-TEST_F(SpdyFramerSpdy3Test, SettingsFlagsAndId) { |
- const uint32 kId = 0x020304; |
- const uint32 kFlags = 0x01; |
- const uint32 kWireFormat = |
- htonl((SPDY_VERSION_FOR_TESTS < 3) ? 0x04030201 : 0x01020304); |
- |
- SettingsFlagsAndId id_and_flags = |
- SettingsFlagsAndId::FromWireFormat(SPDY_VERSION_FOR_TESTS, kWireFormat); |
- EXPECT_EQ(kId, id_and_flags.id()); |
- EXPECT_EQ(kFlags, id_and_flags.flags()); |
- EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(SPDY_VERSION_FOR_TESTS)); |
-} |
- |
-} // namespace |