Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Unified Diff: net/spdy/spdy_framer_test.cc

Issue 2832973003: Split net/spdy into core and chromium subdirectories. (Closed)
Patch Set: Fix some more build rules. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/spdy/spdy_framer_decoder_adapter.cc ('k') | net/spdy/spdy_header_block.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_framer_test.cc
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
deleted file mode 100644
index a4c1253ca274cd21097ddd534f7dbfe248d32946..0000000000000000000000000000000000000000
--- a/net/spdy/spdy_framer_test.cc
+++ /dev/null
@@ -1,4831 +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 "net/spdy/spdy_framer.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <algorithm>
-#include <cstdint>
-#include <limits>
-#include <memory>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/quic/platform/api/quic_flags.h"
-#include "net/spdy/array_output_buffer.h"
-#include "net/spdy/hpack/hpack_constants.h"
-#include "net/spdy/mock_spdy_framer_visitor.h"
-#include "net/spdy/spdy_flags.h"
-#include "net/spdy/spdy_frame_builder.h"
-#include "net/spdy/spdy_frame_reader.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/spdy/spdy_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-using testing::_;
-
-namespace net {
-
-namespace test {
-
-namespace {
-
-const int64_t kSize = 64 * 1024;
-char output_buffer[kSize] = "";
-
-// frame_list_char is used to hold frames to be compared with output_buffer.
-const int64_t buffer_size = 64 * 1024;
-char frame_list_char[buffer_size] = "";
-}
-
-class MockDebugVisitor : public SpdyFramerDebugVisitorInterface {
- public:
- MOCK_METHOD4(OnSendCompressedFrame,
- void(SpdyStreamId stream_id,
- SpdyFrameType type,
- size_t payload_len,
- size_t frame_len));
-
- MOCK_METHOD3(OnReceiveCompressedFrame,
- void(SpdyStreamId stream_id,
- SpdyFrameType type,
- size_t frame_len));
-};
-
-class SpdyFramerTestUtil {
- public:
- // Decompress a single frame using the decompression context held by
- // the SpdyFramer. The implemention is meant for use only in tests
- // and will CHECK fail if the input is anything other than a single,
- // well-formed compressed frame.
- //
- // Returns a new decompressed SpdySerializedFrame.
- template <class SpdyFrameType>
- static SpdySerializedFrame DecompressFrame(SpdyFramer* framer,
- const SpdyFrameType& frame) {
- DecompressionVisitor visitor;
- framer->set_visitor(&visitor);
- CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size()));
- CHECK_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer->state());
- framer->set_visitor(nullptr);
- SpdyFramer serializer(SpdyFramer::DISABLE_COMPRESSION);
- return serializer.SerializeFrame(visitor.GetFrame());
- }
-
- class DecompressionVisitor : public SpdyFramerVisitorInterface {
- public:
- DecompressionVisitor() : finished_(false) {}
-
- const SpdyFrameIR& GetFrame() const {
- CHECK(finished_);
- return *frame_;
- }
-
- SpdyHeadersHandlerInterface* OnHeaderFrameStart(
- SpdyStreamId stream_id) override {
- if (headers_handler_ == nullptr) {
- headers_handler_ = base::MakeUnique<TestHeadersHandler>();
- }
- return headers_handler_.get();
- }
-
- void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override {
- CHECK(!finished_);
- frame_->set_header_block(headers_handler_->decoded_block().Clone());
- finished_ = true;
- if (end_headers) {
- headers_handler_.reset();
- }
- }
-
- void OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- bool end) override {
- auto headers = base::MakeUnique<SpdyHeadersIR>(stream_id);
- headers->set_has_priority(has_priority);
- headers->set_weight(weight);
- headers->set_parent_stream_id(parent_stream_id);
- headers->set_exclusive(exclusive);
- headers->set_fin(fin);
- frame_ = std::move(headers);
- }
-
- void OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- bool end) override {
- frame_ =
- base::MakeUnique<SpdyPushPromiseIR>(stream_id, promised_stream_id);
- }
-
- // TODO(birenroy): Add support for CONTINUATION.
- void OnContinuation(SpdyStreamId stream_id, bool end) override {
- LOG(FATAL);
- }
-
- // All other methods just LOG(FATAL).
- void OnError(SpdyFramer* framer) override { LOG(FATAL); }
- void OnDataFrameHeader(SpdyStreamId stream_id,
- size_t length,
- bool fin) override {
- LOG(FATAL) << "Unexpected data frame header";
- }
- void OnStreamFrameData(SpdyStreamId stream_id,
- const char* data,
- size_t len) override {
- LOG(FATAL);
- }
-
- void OnStreamEnd(SpdyStreamId stream_id) override { LOG(FATAL); }
-
- void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
- LOG(FATAL);
- }
-
- void OnRstStream(SpdyStreamId stream_id,
- SpdyErrorCode error_code) override {
- LOG(FATAL);
- }
- void OnSetting(SpdySettingsIds id, uint32_t value) override { LOG(FATAL); }
- void OnPing(SpdyPingId unique_id, bool is_ack) override { LOG(FATAL); }
- void OnSettingsEnd() override { LOG(FATAL); }
- void OnGoAway(SpdyStreamId last_accepted_stream_id,
- SpdyErrorCode error_code) override {
- LOG(FATAL);
- }
-
- void OnWindowUpdate(SpdyStreamId stream_id,
- int delta_window_size) override {
- LOG(FATAL);
- }
-
- void OnPriority(SpdyStreamId stream_id,
- SpdyStreamId parent_stream_id,
- int weight,
- bool exclusive) override {
- // Do nothing.
- }
-
- bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override {
- LOG(FATAL);
- return false;
- }
-
- private:
- std::unique_ptr<TestHeadersHandler> headers_handler_;
- std::unique_ptr<SpdyFrameWithHeaderBlockIR> frame_;
- bool finished_;
-
- DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor);
- };
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil);
-};
-
-MATCHER_P(IsFrameUnionOf, frame_list, "") {
- size_t size_verified = 0;
- for (const auto& frame : *frame_list) {
- if (arg.size() < size_verified + frame.size()) {
- LOG(FATAL) << "Incremental header serialization should not lead to a "
- << "higher total frame length than non-incremental method.";
- return false;
- }
- if (memcmp(arg.data() + size_verified, frame.data(), frame.size())) {
- CompareCharArraysWithHexError(
- "Header serialization methods should be equivalent: ",
- reinterpret_cast<unsigned char*>(arg.data() + size_verified),
- frame.size(), reinterpret_cast<unsigned char*>(frame.data()),
- frame.size());
- return false;
- }
- size_verified += frame.size();
- }
- return size_verified == arg.size();
-}
-
-class SpdyFramerPeer {
- public:
- static size_t ControlFrameBufferSize() {
- return SpdyFramer::kControlFrameBufferSize;
- }
- static size_t GetNumberRequiredContinuationFrames(SpdyFramer* framer,
- size_t size) {
- return framer->GetNumberRequiredContinuationFrames(size);
- }
- static void SetError(SpdyFramer* framer, SpdyFramer::SpdyFramerError error) {
- framer->set_error(error);
- }
-
- // TODO(dahollings): Remove these methods when deprecating non-incremental
- // header serialization path.
- static std::unique_ptr<SpdyHeadersIR> CloneSpdyHeadersIR(
- const SpdyHeadersIR& headers) {
- auto newHeaders = base::MakeUnique<SpdyHeadersIR>(
- headers.stream_id(), headers.header_block().Clone());
- newHeaders->set_fin(headers.fin());
- newHeaders->set_has_priority(headers.has_priority());
- newHeaders->set_weight(headers.weight());
- newHeaders->set_parent_stream_id(headers.parent_stream_id());
- newHeaders->set_exclusive(headers.exclusive());
- if (headers.padded()) {
- newHeaders->set_padding_len(headers.padding_payload_len() + 1);
- }
- newHeaders->set_end_headers(headers.end_headers());
- return newHeaders;
- }
-
- static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer,
- const SpdyHeadersIR& headers) {
- SpdySerializedFrame serialized_headers_old_version(
- framer->SerializeHeaders(headers));
- framer->hpack_encoder_.reset(nullptr);
- auto* saved_debug_visitor = framer->debug_visitor_;
- framer->debug_visitor_ = nullptr;
-
- std::vector<SpdySerializedFrame> frame_list;
- ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size);
- SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers));
- while (it.HasNextFrame()) {
- size_t size_before = frame_list_buffer.Size();
- it.NextFrame(&frame_list_buffer);
- frame_list.emplace_back(
- SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
- frame_list_buffer.Size() - size_before, false));
- }
- framer->debug_visitor_ = saved_debug_visitor;
-
- EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list));
- return serialized_headers_old_version;
- }
-
- static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer,
- const SpdyHeadersIR& headers,
- ArrayOutputBuffer* output) {
- if (output == nullptr) {
- return SerializeHeaders(framer, headers);
- }
- output->Reset();
- EXPECT_TRUE(framer->SerializeHeaders(headers, output));
- SpdySerializedFrame serialized_headers_old_version(output->Begin(),
- output->Size(), false);
- framer->hpack_encoder_.reset(nullptr);
- auto* saved_debug_visitor = framer->debug_visitor_;
- framer->debug_visitor_ = nullptr;
-
- std::vector<SpdySerializedFrame> frame_list;
- ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size);
- SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers));
- while (it.HasNextFrame()) {
- size_t size_before = frame_list_buffer.Size();
- it.NextFrame(&frame_list_buffer);
- frame_list.emplace_back(
- SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
- frame_list_buffer.Size() - size_before, false));
- }
- framer->debug_visitor_ = saved_debug_visitor;
-
- EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list));
- return serialized_headers_old_version;
- }
-
- static std::unique_ptr<SpdyPushPromiseIR> CloneSpdyPushPromiseIR(
- const SpdyPushPromiseIR& push_promise) {
- auto new_push_promise = base::MakeUnique<SpdyPushPromiseIR>(
- push_promise.stream_id(), push_promise.promised_stream_id(),
- push_promise.header_block().Clone());
- new_push_promise->set_fin(push_promise.fin());
- if (push_promise.padded()) {
- new_push_promise->set_padding_len(push_promise.padding_payload_len() + 1);
- }
- new_push_promise->set_end_headers(push_promise.end_headers());
- return new_push_promise;
- }
-
- static SpdySerializedFrame SerializePushPromise(
- SpdyFramer* framer,
- const SpdyPushPromiseIR& push_promise) {
- SpdySerializedFrame serialized_headers_old_version =
- framer->SerializePushPromise(push_promise);
- framer->hpack_encoder_.reset(nullptr);
- auto* saved_debug_visitor = framer->debug_visitor_;
- framer->debug_visitor_ = nullptr;
-
- std::vector<SpdySerializedFrame> frame_list;
- ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size);
- frame_list_buffer.Reset();
- SpdyFramer::SpdyPushPromiseFrameIterator it(
- framer, CloneSpdyPushPromiseIR(push_promise));
- while (it.HasNextFrame()) {
- size_t size_before = frame_list_buffer.Size();
- it.NextFrame(&frame_list_buffer);
- frame_list.emplace_back(
- SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
- frame_list_buffer.Size() - size_before, false));
- }
- framer->debug_visitor_ = saved_debug_visitor;
-
- EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list));
- return serialized_headers_old_version;
- }
-
- static SpdySerializedFrame SerializePushPromise(
- SpdyFramer* framer,
- const SpdyPushPromiseIR& push_promise,
- ArrayOutputBuffer* output) {
- if (output == nullptr) {
- return SerializePushPromise(framer, push_promise);
- }
- output->Reset();
- EXPECT_TRUE(framer->SerializePushPromise(push_promise, output));
- SpdySerializedFrame serialized_headers_old_version(output->Begin(),
- output->Size(), false);
- framer->hpack_encoder_.reset(nullptr);
- auto* saved_debug_visitor = framer->debug_visitor_;
- framer->debug_visitor_ = nullptr;
-
- std::vector<SpdySerializedFrame> frame_list;
- ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size);
- frame_list_buffer.Reset();
- SpdyFramer::SpdyPushPromiseFrameIterator it(
- framer, CloneSpdyPushPromiseIR(push_promise));
- while (it.HasNextFrame()) {
- size_t size_before = frame_list_buffer.Size();
- it.NextFrame(&frame_list_buffer);
- frame_list.emplace_back(
- SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
- frame_list_buffer.Size() - size_before, false));
- }
- framer->debug_visitor_ = saved_debug_visitor;
-
- EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list));
- return serialized_headers_old_version;
- }
-};
-
-class TestSpdyVisitor : public SpdyFramerVisitorInterface,
- public SpdyFramerDebugVisitorInterface {
- public:
- // This is larger than our max frame size because header blocks that
- // are too long can spill over into CONTINUATION frames.
- static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024;
-
- explicit TestSpdyVisitor(SpdyFramer::CompressionOption option)
- : framer_(option),
- error_count_(0),
- headers_frame_count_(0),
- push_promise_frame_count_(0),
- goaway_count_(0),
- setting_count_(0),
- settings_ack_sent_(0),
- settings_ack_received_(0),
- continuation_count_(0),
- altsvc_count_(0),
- priority_count_(0),
- test_altsvc_ir_(0),
- on_unknown_frame_result_(false),
- last_window_update_stream_(0),
- last_window_update_delta_(0),
- last_push_promise_stream_(0),
- last_push_promise_promised_stream_(0),
- data_bytes_(0),
- fin_frame_count_(0),
- fin_flag_count_(0),
- end_of_stream_count_(0),
- control_frame_header_data_count_(0),
- zero_length_control_frame_header_data_count_(0),
- data_frame_count_(0),
- last_payload_len_(0),
- last_frame_len_(0),
- header_buffer_(kDefaultHeaderBufferSize),
- header_buffer_length_(0),
- header_stream_id_(static_cast<SpdyStreamId>(-1)),
- header_control_type_(SpdyFrameType::DATA),
- header_buffer_valid_(false) {}
-
- void OnError(SpdyFramer* f) override {
- VLOG(1) << "SpdyFramer Error: "
- << SpdyFramer::SpdyFramerErrorToString(f->spdy_framer_error());
- ++error_count_;
- }
-
- void OnDataFrameHeader(SpdyStreamId stream_id,
- size_t length,
- bool fin) override {
- VLOG(1) << "OnDataFrameHeader(" << stream_id << ", " << length << ", "
- << fin << ")";
- ++data_frame_count_;
- header_stream_id_ = stream_id;
- }
-
- void OnStreamFrameData(SpdyStreamId stream_id,
- const char* data,
- size_t len) override {
- VLOG(1) << "OnStreamFrameData(" << stream_id << ", data, " << len << ", "
- << ") data:\n"
- << base::HexEncode(data, len);
- EXPECT_EQ(header_stream_id_, stream_id);
- data_bytes_ += len;
- }
-
- void OnStreamEnd(SpdyStreamId stream_id) override {
- VLOG(1) << "OnStreamEnd(" << stream_id << ")";
- EXPECT_EQ(header_stream_id_, stream_id);
- ++end_of_stream_count_;
- }
-
- void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
- VLOG(1) << "OnStreamPadding(" << stream_id << ", " << len << ")\n";
- EXPECT_EQ(header_stream_id_, stream_id);
- data_bytes_ += len;
- }
-
- SpdyHeadersHandlerInterface* OnHeaderFrameStart(
- SpdyStreamId stream_id) override {
- if (headers_handler_ == nullptr) {
- headers_handler_ = base::MakeUnique<TestHeadersHandler>();
- }
- return headers_handler_.get();
- }
-
- void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override {
- CHECK(headers_handler_ != nullptr);
- headers_ = headers_handler_->decoded_block().Clone();
- header_bytes_received_ = headers_handler_->header_bytes_parsed();
- if (end_headers) {
- headers_handler_.reset();
- }
- }
-
- void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override {
- VLOG(1) << "OnRstStream(" << stream_id << ", " << error_code << ")";
- ++fin_frame_count_;
- }
-
- void OnSetting(SpdySettingsIds id, uint32_t value) override {
- VLOG(1) << "OnSetting(" << id << ", " << std::hex << ", " << value << ")";
- ++setting_count_;
- }
-
- void OnSettingsAck() override {
- VLOG(1) << "OnSettingsAck";
- ++settings_ack_received_;
- }
-
- void OnSettingsEnd() override {
- VLOG(1) << "OnSettingsEnd";
- ++settings_ack_sent_;
- }
-
- void OnPing(SpdyPingId unique_id, bool is_ack) override {
- LOG(DFATAL) << "OnPing(" << unique_id << ", " << (is_ack ? 1 : 0) << ")";
- }
-
- void OnGoAway(SpdyStreamId last_accepted_stream_id,
- SpdyErrorCode error_code) override {
- VLOG(1) << "OnGoAway(" << last_accepted_stream_id << ", " << error_code
- << ")";
- ++goaway_count_;
- }
-
- void OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- bool end) override {
- VLOG(1) << "OnHeaders(" << stream_id << ", " << has_priority << ", "
- << weight << ", " << parent_stream_id << ", " << exclusive << ", "
- << fin << ", " << end << ")";
- ++headers_frame_count_;
- InitHeaderStreaming(SpdyFrameType::HEADERS, stream_id);
- if (fin) {
- ++fin_flag_count_;
- }
- header_has_priority_ = has_priority;
- header_parent_stream_id_ = parent_stream_id;
- header_exclusive_ = exclusive;
- }
-
- void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {
- VLOG(1) << "OnWindowUpdate(" << stream_id << ", " << delta_window_size
- << ")";
- last_window_update_stream_ = stream_id;
- last_window_update_delta_ = delta_window_size;
- }
-
- void OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- bool end) override {
- VLOG(1) << "OnPushPromise(" << stream_id << ", " << promised_stream_id
- << ", " << end << ")";
- ++push_promise_frame_count_;
- InitHeaderStreaming(SpdyFrameType::PUSH_PROMISE, stream_id);
- last_push_promise_stream_ = stream_id;
- last_push_promise_promised_stream_ = promised_stream_id;
- }
-
- void OnContinuation(SpdyStreamId stream_id, bool end) override {
- VLOG(1) << "OnContinuation(" << stream_id << ", " << end << ")";
- ++continuation_count_;
- }
-
- void OnAltSvc(SpdyStreamId stream_id,
- SpdyStringPiece origin,
- const SpdyAltSvcWireFormat::AlternativeServiceVector&
- altsvc_vector) override {
- VLOG(1) << "OnAltSvc(" << stream_id << ", \"" << origin
- << "\", altsvc_vector)";
- test_altsvc_ir_.set_stream_id(stream_id);
- if (origin.length() > 0) {
- test_altsvc_ir_.set_origin(SpdyString(origin));
- }
- for (const auto& altsvc : altsvc_vector) {
- test_altsvc_ir_.add_altsvc(altsvc);
- }
- ++altsvc_count_;
- }
-
- void OnPriority(SpdyStreamId stream_id,
- SpdyStreamId parent_stream_id,
- int weight,
- bool exclusive) override {
- VLOG(1) << "OnPriority(" << stream_id << ", " << parent_stream_id << ", "
- << weight << ", " << (exclusive ? 1 : 0) << ")";
- ++priority_count_;
- }
-
- bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override {
- VLOG(1) << "OnUnknownFrame(" << stream_id << ", " << frame_type << ")";
- return on_unknown_frame_result_;
- }
-
- void OnSendCompressedFrame(SpdyStreamId stream_id,
- SpdyFrameType type,
- size_t payload_len,
- size_t frame_len) override {
- VLOG(1) << "OnSendCompressedFrame(" << stream_id << ", " << type << ", "
- << payload_len << ", " << frame_len << ")";
- last_payload_len_ = payload_len;
- last_frame_len_ = frame_len;
- }
-
- void OnReceiveCompressedFrame(SpdyStreamId stream_id,
- SpdyFrameType type,
- size_t frame_len) override {
- VLOG(1) << "OnReceiveCompressedFrame(" << stream_id << ", " << type << ", "
- << frame_len << ")";
- last_frame_len_ = frame_len;
- }
-
- // Convenience function which runs a framer simulation with particular input.
- void SimulateInFramer(const unsigned char* input, size_t size) {
- framer_.set_visitor(this);
- size_t input_remaining = size;
- const char* input_ptr = reinterpret_cast<const char*>(input);
- while (input_remaining > 0 &&
- framer_.spdy_framer_error() == SpdyFramer::SPDY_NO_ERROR) {
- // To make the tests more interesting, we feed random (and 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;
- }
- }
-
- void InitHeaderStreaming(SpdyFrameType header_control_type,
- SpdyStreamId stream_id) {
- if (!IsDefinedFrameType(SerializeFrameType(header_control_type))) {
- DLOG(FATAL) << "Attempted to init header streaming with "
- << "invalid control frame type: " << header_control_type;
- }
- std::fill(header_buffer_.begin(), header_buffer_.end(), 0);
- header_buffer_length_ = 0;
- header_stream_id_ = stream_id;
- header_control_type_ = header_control_type;
- header_buffer_valid_ = true;
- DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
- }
-
- void set_extension_visitor(ExtensionVisitorInterface* extension) {
- framer_.set_extension_visitor(extension);
- }
-
- // Override the default buffer size (16K). Call before using the framer!
- void set_header_buffer_size(size_t header_buffer_size) {
- header_buffer_.resize(header_buffer_size);
- }
-
- // Largest control frame that the SPDY implementation sends, including the
- // size of the header.
- static size_t sent_control_frame_max_size() {
- return SpdyFramer::kMaxControlFrameSize;
- }
-
- // Largest control frame that the SPDY implementation is willing to receive,
- // excluding the size of the header.
- static size_t received_control_frame_max_size() {
- return kSpdyInitialFrameSizeLimit;
- }
-
- static size_t header_data_chunk_max_size() {
- return SpdyFramer::kHeaderDataChunkMaxSize;
- }
-
- SpdyFramer framer_;
-
- // Counters from the visitor callbacks.
- int error_count_;
- int headers_frame_count_;
- int push_promise_frame_count_;
- int goaway_count_;
- int setting_count_;
- int settings_ack_sent_;
- int settings_ack_received_;
- int continuation_count_;
- int altsvc_count_;
- int priority_count_;
- SpdyAltSvcIR test_altsvc_ir_;
- bool on_unknown_frame_result_;
- SpdyStreamId last_window_update_stream_;
- int last_window_update_delta_;
- SpdyStreamId last_push_promise_stream_;
- SpdyStreamId last_push_promise_promised_stream_;
- 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 end_of_stream_count_; // The count of zero-length data frames.
- 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_;
- size_t last_payload_len_;
- size_t last_frame_len_;
-
- // Header block streaming state:
- std::vector<char> header_buffer_;
- size_t header_buffer_length_;
- size_t header_bytes_received_;
- SpdyStreamId header_stream_id_;
- SpdyFrameType header_control_type_;
- bool header_buffer_valid_;
- std::unique_ptr<TestHeadersHandler> headers_handler_;
- SpdyHeaderBlock headers_;
- bool header_has_priority_;
- SpdyStreamId header_parent_stream_id_;
- bool header_exclusive_;
-};
-
-class TestExtension : public ExtensionVisitorInterface {
- public:
- void OnSetting(uint16_t id, uint32_t value) override {
- settings_received_.push_back({id, value});
- }
-
- // Called when non-standard frames are received.
- bool OnFrameHeader(SpdyStreamId stream_id,
- size_t length,
- uint8_t type,
- uint8_t flags) override {
- stream_id_ = stream_id;
- length_ = length;
- type_ = type;
- flags_ = flags;
- return true;
- }
-
- // The payload for a single frame may be delivered as multiple calls to
- // OnFramePayload.
- void OnFramePayload(const char* data, size_t len) override {
- payload_.append(data, len);
- }
-
- std::vector<std::pair<uint16_t, uint32_t>> settings_received_;
- SpdyStreamId stream_id_ = 0;
- size_t length_ = 0;
- uint8_t type_ = 0;
- uint8_t flags_ = 0;
- SpdyString payload_;
-};
-
-// Retrieves serialized headers from a HEADERS frame.
-SpdyStringPiece GetSerializedHeaders(const SpdySerializedFrame& frame,
- const SpdyFramer& framer) {
- SpdyFrameReader reader(frame.data(), frame.size());
- reader.Seek(3); // Seek past the frame length.
-
- uint8_t serialized_type;
- reader.ReadUInt8(&serialized_type);
-
- SpdyFrameType type = ParseFrameType(serialized_type);
- DCHECK_EQ(SpdyFrameType::HEADERS, type);
- uint8_t flags;
- reader.ReadUInt8(&flags);
-
- return SpdyStringPiece(frame.data() + framer.GetHeadersMinimumSize(),
- frame.size() - framer.GetHeadersMinimumSize());
-}
-
-enum DecoderChoice { DECODER_SELF, DECODER_NESTED, DECODER_HTTP2 };
-enum HpackChoice { HPACK_DECODER_1, HPACK_DECODER_3 };
-enum Output { USE, NOT_USE };
-
-class SpdyFramerTest : public ::testing::TestWithParam<
- std::tuple<DecoderChoice, HpackChoice, Output>> {
- public:
- SpdyFramerTest() : output_(output_buffer, kSize) {}
-
- protected:
- void SetUp() override {
- auto param = GetParam();
- switch (std::get<0>(param)) {
- case DECODER_SELF:
- FLAGS_use_nested_spdy_framer_decoder = false;
- FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = false;
- break;
- case DECODER_NESTED:
- FLAGS_use_nested_spdy_framer_decoder = true;
- FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = false;
- break;
- case DECODER_HTTP2:
- FLAGS_use_nested_spdy_framer_decoder = false;
- FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = true;
- break;
- }
- switch (std::get<1>(param)) {
- case HPACK_DECODER_1:
- FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false;
- break;
- case HPACK_DECODER_3:
- FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = true;
- break;
- }
- switch (std::get<2>(param)) {
- case USE:
- use_output_ = true;
- break;
- case NOT_USE:
- // TODO(yasong): remove this case after
- // FLAGS_chromium_http2_flag_remove_rewritelength deprecates.
- use_output_ = false;
- break;
- }
- }
-
- void CompareFrame(const SpdyString& description,
- const SpdySerializedFrame& actual_frame,
- const unsigned char* expected,
- const int expected_len) {
- const unsigned char* actual =
- reinterpret_cast<const unsigned char*>(actual_frame.data());
- CompareCharArraysWithHexError(description, actual, actual_frame.size(),
- expected, expected_len);
- }
-
- void CompareFrames(const SpdyString& description,
- const SpdySerializedFrame& expected_frame,
- const SpdySerializedFrame& actual_frame) {
- CompareCharArraysWithHexError(
- description,
- reinterpret_cast<const unsigned char*>(expected_frame.data()),
- expected_frame.size(),
- reinterpret_cast<const unsigned char*>(actual_frame.data()),
- actual_frame.size());
- }
-
- bool use_output_ = false;
- ArrayOutputBuffer output_;
-};
-
-INSTANTIATE_TEST_CASE_P(SpdyFramerTests,
- SpdyFramerTest,
- ::testing::Combine(::testing::Values(DECODER_SELF,
- DECODER_NESTED,
- DECODER_HTTP2),
- ::testing::Values(HPACK_DECODER_1,
- HPACK_DECODER_3),
- ::testing::Values(USE, NOT_USE)));
-
-// Test that we can encode and decode a SpdyHeaderBlock in serialized form.
-TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
-
- // Encode the header block into a Headers frame.
- SpdyHeadersIR headers(1);
- headers.SetHeader("alpha", "beta");
- headers.SetHeader("gamma", "charlie");
- headers.SetHeader("cookie", "key1=value1; key2=value2");
- SpdySerializedFrame frame(
- SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()),
- frame.size());
-
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(headers.header_block(), visitor.headers_);
-}
-
-// Test that if there's not a full frame, we fail to parse it.
-TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
-
- // Encode the header block into a Headers frame.
- SpdyHeadersIR headers(1);
- headers.SetHeader("alpha", "beta");
- headers.SetHeader("gamma", "charlie");
- SpdySerializedFrame frame(
- SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()),
- frame.size() - 2);
-
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(0u, visitor.headers_.size());
-}
-
-// Test that we treat incoming upper-case or mixed-case header values as
-// malformed.
-TEST_P(SpdyFramerTest, RejectUpperCaseHeaderBlockValue) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
-
- SpdyFrameBuilder frame(1024);
- frame.BeginNewFrame(framer, SpdyFrameType::HEADERS, 0, 1);
- frame.WriteUInt32(1);
- frame.WriteStringPiece32("Name1");
- frame.WriteStringPiece32("value1");
- frame.OverwriteLength(framer, frame.length() - framer.GetFrameHeaderSize());
-
- SpdyFrameBuilder frame2(1024);
- frame2.BeginNewFrame(framer, SpdyFrameType::HEADERS, 0, 1);
- frame2.WriteUInt32(2);
- frame2.WriteStringPiece32("name1");
- frame2.WriteStringPiece32("value1");
- frame2.WriteStringPiece32("nAmE2");
- frame2.WriteStringPiece32("value2");
- frame.OverwriteLength(framer, frame2.length() - framer.GetFrameHeaderSize());
-
- SpdySerializedFrame control_frame(frame.take());
- SpdyStringPiece serialized_headers =
- GetSerializedHeaders(control_frame, framer);
- SpdySerializedFrame control_frame2(frame2.take());
- SpdyStringPiece serialized_headers2 =
- GetSerializedHeaders(control_frame2, framer);
-
- SpdyHeaderBlock new_headers;
- EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(
- serialized_headers.data(), serialized_headers.size(), &new_headers));
- EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(
- serialized_headers2.data(), serialized_headers2.size(), &new_headers));
-}
-
-// Test that we can encode and decode stream dependency values in a header
-// frame.
-TEST_P(SpdyFramerTest, HeaderStreamDependencyValues) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
-
- const SpdyStreamId parent_stream_id_test_array[] = {0, 3};
- for (SpdyStreamId parent_stream_id : parent_stream_id_test_array) {
- const bool exclusive_test_array[] = {true, false};
- for (bool exclusive : exclusive_test_array) {
- SpdyHeadersIR headers(1);
- headers.set_has_priority(true);
- headers.set_parent_stream_id(parent_stream_id);
- headers.set_exclusive(exclusive);
- SpdySerializedFrame frame(
- SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()),
- frame.size());
-
- EXPECT_TRUE(visitor.header_has_priority_);
- EXPECT_EQ(parent_stream_id, visitor.header_parent_stream_id_);
- EXPECT_EQ(exclusive, visitor.header_exclusive_);
- }
- }
-}
-
-// Test that if we receive a frame with payload length field at the
-// advertised max size, we do not set an error in ProcessInput.
-TEST_P(SpdyFramerTest, AcceptMaxFrameSizeSetting) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // DATA frame with maximum allowed payload length.
- unsigned char kH2FrameData[] = {
- 0x00, 0x40, 0x00, // Length: 2^14
- 0x00, // Type: HEADERS
- 0x00, // Flags: None
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Junk payload
- };
-
- SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData),
- sizeof(kH2FrameData), false);
-
- EXPECT_CALL(visitor, OnDataFrameHeader(1, 1 << 14, false));
- EXPECT_CALL(visitor, OnStreamFrameData(1, _, 4));
- framer.ProcessInput(frame.data(), frame.size());
- EXPECT_FALSE(framer.HasError());
-}
-
-// Test that if we receive a frame with payload length larger than the
-// advertised max size, we set an error of SPDY_INVALID_CONTROL_FRAME_SIZE.
-TEST_P(SpdyFramerTest, ExceedMaxFrameSizeSetting) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // DATA frame with too large payload length.
- unsigned char kH2FrameData[] = {
- 0x00, 0x40, 0x01, // Length: 2^14 + 1
- 0x00, // Type: HEADERS
- 0x00, // Flags: None
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Junk payload
- };
-
- SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData),
- sizeof(kH2FrameData), false);
-
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- framer.ProcessInput(frame.data(), frame.size());
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_OVERSIZED_PAYLOAD, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a DATA frame with padding length larger than the
-// payload length, we set an error of SPDY_INVALID_PADDING
-TEST_P(SpdyFramerTest, OversizedDataPaddingError) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // DATA frame with invalid padding length.
- // |kH2FrameData| has to be |unsigned char|, because Chromium on Windows uses
- // MSVC, where |char| is signed by default, which would not compile because of
- // the element exceeding 127.
- unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x00, // Type: DATA
- 0x09, // Flags: END_STREAM|PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0xff, // PadLen: 255 trailing bytes (Too Long)
- 0x00, 0x00, 0x00, 0x00, // Padding
- };
-
- SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData),
- sizeof(kH2FrameData), false);
-
- {
- testing::InSequence seq;
- EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, 1));
- EXPECT_CALL(visitor, OnStreamPadding(1, 1));
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- }
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_PADDING, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a DATA frame with padding length not larger than the
-// payload length, we do not set an error of SPDY_INVALID_PADDING
-TEST_P(SpdyFramerTest, CorrectlySizedDataPaddingNoError) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // DATA frame with valid Padding length
- char kH2FrameData[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x00, // Type: DATA
- 0x08, // Flags: PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x04, // PadLen: 4 trailing bytes
- 0x00, 0x00, 0x00, 0x00, // Padding
- };
-
- SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false);
-
- {
- testing::InSequence seq;
- EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, false));
- EXPECT_CALL(visitor, OnStreamPadding(1, 1));
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer))).Times(0);
- // Note that OnStreamFrameData(1, _, 1)) is never called
- // since there is no data, only padding
- EXPECT_CALL(visitor, OnStreamPadding(1, 4));
- }
-
- EXPECT_EQ(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_FALSE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a HEADERS frame with padding length larger than the
-// payload length, we set an error of SPDY_INVALID_PADDING
-TEST_P(SpdyFramerTest, OversizedHeadersPaddingError) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // HEADERS frame with invalid padding length.
- // |kH2FrameData| has to be |unsigned char|, because Chromium on Windows uses
- // MSVC, where |char| is signed by default, which would not compile because of
- // the element exceeding 127.
- unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x01, // Type: HEADERS
- 0x08, // Flags: PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0xff, // PadLen: 255 trailing bytes (Too Long)
- 0x00, 0x00, 0x00, 0x00, // Padding
- };
-
- SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData),
- sizeof(kH2FrameData), false);
-
- EXPECT_CALL(visitor, OnHeaders(1, false, 0, 0, false, false, false));
- EXPECT_CALL(visitor, OnHeaderFrameStart(1)).Times(1);
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_EQ(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_PADDING, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a HEADERS frame with padding length not larger
-// than the payload length, we do not set an error of SPDY_INVALID_PADDING
-TEST_P(SpdyFramerTest, CorrectlySizedHeadersPaddingNoError) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // HEADERS frame with invalid Padding length
- char kH2FrameData[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x01, // Type: HEADERS
- 0x08, // Flags: PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x04, // PadLen: 4 trailing bytes
- 0x00, 0x00, 0x00, 0x00, // Padding
- };
-
- SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false);
-
- EXPECT_CALL(visitor, OnHeaders(1, false, 0, 0, false, false, false));
- EXPECT_CALL(visitor, OnHeaderFrameStart(1)).Times(1);
- EXPECT_EQ(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_FALSE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a DATA with stream ID zero, we signal an error
-// (but don't crash).
-TEST_P(SpdyFramerTest, DataWithStreamIdZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- const char bytes[] = "hello";
- SpdyDataIR data_ir(0, bytes);
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a HEADERS with stream ID zero, we signal an error
-// (but don't crash).
-TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyHeadersIR headers(0);
- headers.SetHeader("alpha", "beta");
- SpdySerializedFrame frame(
- SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a PRIORITY with stream ID zero, we signal an error
-// (but don't crash).
-TEST_P(SpdyFramerTest, PriorityWithStreamIdZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyPriorityIR priority_ir(0, 1, 16, true);
- SpdySerializedFrame frame(framer.SerializeFrame(priority_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeFrame(priority_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a RST_STREAM with stream ID zero, we signal an error
-// (but don't crash).
-TEST_P(SpdyFramerTest, RstStreamWithStreamIdZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyRstStreamIR rst_stream_ir(0, ERROR_CODE_PROTOCOL_ERROR);
- SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeRstStream(rst_stream_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a SETTINGS with stream ID other than zero,
-// we signal an error (but don't crash).
-TEST_P(SpdyFramerTest, SettingsWithStreamIdNotZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // Settings frame with invalid StreamID of 0x01
- char kH2FrameData[] = {
- 0x00, 0x00, 0x06, // Length: 6
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE
- 0x0a, 0x0b, 0x0c, 0x0d, // Value: 168496141
- };
-
- SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false);
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a GOAWAY with stream ID other than zero,
-// we signal an error (but don't crash).
-TEST_P(SpdyFramerTest, GoawayWithStreamIdNotZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // GOAWAY frame with invalid StreamID of 0x01
- char kH2FrameData[] = {
- 0x00, 0x00, 0x0a, // Length: 10
- 0x07, // Type: GOAWAY
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Last: 0
- 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR
- 0x47, 0x41, // Description
- };
-
- SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false);
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a CONTINUATION with stream ID zero, we signal an
-// SPDY_INVALID_STREAM_ID.
-TEST_P(SpdyFramerTest, ContinuationWithStreamIdZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyContinuationIR continuation(0);
- auto some_nonsense_encoding =
- base::MakeUnique<SpdyString>("some nonsense encoding");
- continuation.take_encoding(std::move(some_nonsense_encoding));
- continuation.set_end_headers(true);
- SpdySerializedFrame frame(framer.SerializeContinuation(continuation));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a PUSH_PROMISE with stream ID zero, we signal an
-// SPDY_INVALID_STREAM_ID.
-TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyPushPromiseIR push_promise(0, 4);
- push_promise.SetHeader("alpha", "beta");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test that if we receive a PUSH_PROMISE with promised stream ID zero, we
-// signal SPDY_INVALID_STREAM_ID.
-TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyPushPromiseIR push_promise(3, 0);
- push_promise.SetHeader("alpha", "beta");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
-
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- framer.ProcessInput(frame.data(), frame.size());
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-TEST_P(SpdyFramerTest, DuplicateHeader) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- // Frame builder with plentiful buffer size.
- SpdyFrameBuilder frame(1024);
- frame.BeginNewFrame(framer, SpdyFrameType::HEADERS, 0, 3);
-
- frame.WriteUInt32(2); // Number of headers.
- frame.WriteStringPiece32("name");
- frame.WriteStringPiece32("value1");
- frame.WriteStringPiece32("name");
- frame.WriteStringPiece32("value2");
- // write the length
- frame.OverwriteLength(framer, frame.length() - framer.GetFrameHeaderSize());
-
- SpdyHeaderBlock new_headers;
- SpdySerializedFrame control_frame(frame.take());
- SpdyStringPiece serialized_headers =
- GetSerializedHeaders(control_frame, framer);
- // This should fail because duplicate headers are verboten by the spec.
- EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(
- serialized_headers.data(), serialized_headers.size(), &new_headers));
-}
-
-TEST_P(SpdyFramerTest, MultiValueHeader) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- // Frame builder with plentiful buffer size.
- SpdyFrameBuilder frame(1024);
- frame.BeginNewFrame(framer, SpdyFrameType::HEADERS,
- HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS, 3);
- frame.WriteUInt32(0); // Priority exclusivity and dependent stream.
- frame.WriteUInt8(255); // Priority weight.
-
- SpdyString value("value1\0value2", 13);
- // TODO(jgraettinger): If this pattern appears again, move to test class.
- SpdyHeaderBlock header_set;
- header_set["name"] = value;
- SpdyString buffer;
- HpackEncoder encoder(ObtainHpackHuffmanTable());
- encoder.DisableCompression();
- encoder.EncodeHeaderSet(header_set, &buffer);
- frame.WriteBytes(&buffer[0], buffer.size());
- // write the length
- frame.OverwriteLength(framer, frame.length() - framer.GetFrameHeaderSize());
-
- SpdySerializedFrame control_frame(frame.take());
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
-
- EXPECT_THAT(visitor.headers_, testing::ElementsAre(testing::Pair(
- "name", SpdyStringPiece(value))));
-}
-
-TEST_P(SpdyFramerTest, CompressEmptyHeaders) {
- // See crbug.com/172383
- SpdyHeadersIR headers(1);
- headers.SetHeader("server", "SpdyServer 1.0");
- headers.SetHeader("date", "Mon 12 Jan 2009 12:12:12 PST");
- headers.SetHeader("status", "200");
- headers.SetHeader("version", "HTTP/1.1");
- headers.SetHeader("content-type", "text/html");
- headers.SetHeader("content-length", "12");
- headers.SetHeader("x-empty-header", "");
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdySerializedFrame frame1(
- SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
-}
-
-TEST_P(SpdyFramerTest, Basic) {
- // Send HEADERS frames with PRIORITY and END_HEADERS set.
- // frame-format off
- const unsigned char kH2Input[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x01, // Type: HEADERS
- 0x24, // Flags: END_HEADERS|PRIORITY
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Parent: 0
- 0x82, // Weight: 131
-
- 0x00, 0x00, 0x01, // Length: 1
- 0x01, // Type: HEADERS
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x8c, // :status: 200
-
- 0x00, 0x00, 0x0c, // Length: 12
- 0x00, // Type: DATA
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0xde, 0xad, 0xbe, 0xef, // Payload
- 0xde, 0xad, 0xbe, 0xef, //
- 0xde, 0xad, 0xbe, 0xef, //
-
- 0x00, 0x00, 0x05, // Length: 5
- 0x01, // Type: HEADERS
- 0x24, // Flags: END_HEADERS|PRIORITY
- 0x00, 0x00, 0x00, 0x03, // Stream: 3
- 0x00, 0x00, 0x00, 0x00, // Parent: 0
- 0x82, // Weight: 131
-
- 0x00, 0x00, 0x08, // Length: 8
- 0x00, // Type: DATA
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x03, // Stream: 3
- 0xde, 0xad, 0xbe, 0xef, // Payload
- 0xde, 0xad, 0xbe, 0xef, //
-
- 0x00, 0x00, 0x04, // Length: 4
- 0x00, // Type: DATA
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0xde, 0xad, 0xbe, 0xef, // Payload
-
- 0x00, 0x00, 0x04, // Length: 4
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x08, // Error: CANCEL
-
- 0x00, 0x00, 0x00, // Length: 0
- 0x00, // Type: DATA
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x03, // Stream: 3
-
- 0x00, 0x00, 0x04, // Length: 4
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x03, // Stream: 3
- 0x00, 0x00, 0x00, 0x08, // Error: CANCEL
- };
- // frame-format on
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kH2Input, sizeof(kH2Input));
-
- EXPECT_EQ(24, visitor.data_bytes_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(2, visitor.fin_frame_count_);
-
- EXPECT_EQ(3, visitor.headers_frame_count_);
-
- EXPECT_EQ(0, visitor.fin_flag_count_);
- EXPECT_EQ(0, visitor.end_of_stream_count_);
- EXPECT_EQ(4, visitor.data_frame_count_);
-}
-
-// Test that the FIN flag on a data frame signifies EOF.
-TEST_P(SpdyFramerTest, FinOnDataFrame) {
- // Send HEADERS frames with END_HEADERS set.
- // frame-format off
- const unsigned char kH2Input[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x01, // Type: HEADERS
- 0x24, // Flags: END_HEADERS|PRIORITY
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Parent: 0
- 0x82, // Weight: 131
-
- 0x00, 0x00, 0x01, // Length: 1
- 0x01, // Type: HEADERS
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x8c, // :status: 200
-
- 0x00, 0x00, 0x0c, // Length: 12
- 0x00, // Type: DATA
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0xde, 0xad, 0xbe, 0xef, // Payload
- 0xde, 0xad, 0xbe, 0xef, //
- 0xde, 0xad, 0xbe, 0xef, //
-
- 0x00, 0x00, 0x04, // Length: 4
- 0x00, // Type: DATA
- 0x01, // Flags: END_STREAM
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0xde, 0xad, 0xbe, 0xef, // Payload
- };
- // frame-format on
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kH2Input, sizeof(kH2Input));
-
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(2, 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.end_of_stream_count_);
- EXPECT_EQ(2, visitor.data_frame_count_);
-}
-
-TEST_P(SpdyFramerTest, FinOnHeadersFrame) {
- // Send HEADERS frames with END_HEADERS set.
- // frame-format off
- const unsigned char kH2Input[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x01, // Type: HEADERS
- 0x24, // Flags: END_HEADERS|PRIORITY
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Parent: 0
- 0x82, // Weight: 131
-
- 0x00, 0x00, 0x01, // Length: 1
- 0x01, // Type: HEADERS
- 0x05, // Flags: END_STREAM|END_HEADERS
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x8c, // :status: 200
- };
- // frame-format on
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kH2Input, sizeof(kH2Input));
-
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(2, 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.end_of_stream_count_);
- EXPECT_EQ(0, visitor.data_frame_count_);
-}
-
-// Verify we can decompress the stream even if handed over to the
-// framer 1 byte at a time.
-TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- const char kHeader1[] = "header1";
- const char kHeader2[] = "header2";
- const char kValue1[] = "value1";
- const char kValue2[] = "value2";
-
- SpdyHeadersIR headers(1);
- headers.SetHeader(kHeader1, kValue1);
- headers.SetHeader(kHeader2, kValue2);
- SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers, use_output_ ? &output_ : nullptr));
-
- const char bytes[] = "this is a test test test test test!";
- SpdyDataIR data_ir(1, SpdyStringPiece(bytes, arraysize(bytes)));
- data_ir.set_fin(true);
- SpdySerializedFrame send_frame(framer.SerializeData(data_ir));
-
- // Run the inputs through the framer.
- TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
- const unsigned char* data;
- data = reinterpret_cast<const unsigned char*>(headers_frame.data());
- for (size_t idx = 0; idx < headers_frame.size(); ++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.size(); ++idx) {
- visitor.SimulateInFramer(data + idx, 1);
- ASSERT_EQ(0, visitor.error_count_);
- }
-
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, 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.end_of_stream_count_);
- EXPECT_EQ(1, visitor.data_frame_count_);
-}
-
-TEST_P(SpdyFramerTest, WindowUpdateFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdyWindowUpdateIR window_update(1, 0x12345678);
- SpdySerializedFrame frame(framer.SerializeWindowUpdate(window_update));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeWindowUpdate(window_update, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
-
- const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x08, // Type: WINDOW_UPDATE
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x12, 0x34, 0x56, 0x78, // Increment: 305419896
- };
-
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
-}
-
-TEST_P(SpdyFramerTest, CreateDataFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- {
- const char kDescription[] = "'hello' data frame, no FIN";
- // frame-format off
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x00, // Type: DATA
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 'h', 'e', 'l', 'l', // Payload
- 'o', //
- };
- // frame-format on
- const char bytes[] = "hello";
-
- SpdyDataIR data_ir(1, bytes);
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
-
- SpdyDataIR data_header_ir(1);
- data_header_ir.SetDataShallow(bytes);
- frame =
- framer.SerializeDataFrameHeaderWithPaddingLengthField(data_header_ir);
- CompareCharArraysWithHexError(
- kDescription, reinterpret_cast<const unsigned char*>(frame.data()),
- framer.GetDataFrameMinimumSize(), kH2FrameData,
- framer.GetDataFrameMinimumSize());
- }
-
- {
- const char kDescription[] = "'hello' data frame with more padding, no FIN";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0xfd, // Length: 253
- 0x00, // Type: DATA
- 0x08, // Flags: PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0xf7, // PadLen: 247 trailing bytes
- 'h', 'e', 'l', 'l', // Payload
- 'o', //
- // Padding of 247 0x00(s).
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- };
- // frame-format on
- // clang-format on
- const char bytes[] = "hello";
-
- SpdyDataIR data_ir(1, bytes);
- // 247 zeros and the pad length field make the overall padding to be 248
- // bytes.
- data_ir.set_padding_len(248);
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
-
- frame = framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir);
- CompareCharArraysWithHexError(
- kDescription, reinterpret_cast<const unsigned char*>(frame.data()),
- framer.GetDataFrameMinimumSize(), kH2FrameData,
- framer.GetDataFrameMinimumSize());
- }
-
- {
- const char kDescription[] = "'hello' data frame with few padding, no FIN";
- // frame-format off
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x0d, // Length: 13
- 0x00, // Type: DATA
- 0x08, // Flags: PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x07, // PadLen: 7 trailing bytes
- 'h', 'e', 'l', 'l', // Payload
- 'o', //
- 0x00, 0x00, 0x00, 0x00, // Padding
- 0x00, 0x00, 0x00, // Padding
- };
- // frame-format on
- const char bytes[] = "hello";
-
- SpdyDataIR data_ir(1, bytes);
- // 7 zeros and the pad length field make the overall padding to be 8 bytes.
- data_ir.set_padding_len(8);
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] =
- "'hello' data frame with 1 byte padding, no FIN";
- // frame-format off
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x06, // Length: 6
- 0x00, // Type: DATA
- 0x08, // Flags: PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, // PadLen: 0 trailing bytes
- 'h', 'e', 'l', 'l', // Payload
- 'o', //
- };
- // frame-format on
- const char bytes[] = "hello";
-
- SpdyDataIR data_ir(1, bytes);
- // The pad length field itself is used for the 1-byte padding and no padding
- // payload is needed.
- data_ir.set_padding_len(1);
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
-
- frame = framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir);
- CompareCharArraysWithHexError(
- kDescription, reinterpret_cast<const unsigned char*>(frame.data()),
- framer.GetDataFrameMinimumSize(), kH2FrameData,
- framer.GetDataFrameMinimumSize());
- }
-
- {
- const char kDescription[] = "Data frame with negative data byte, no FIN";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x01, // Length: 1
- 0x00, // Type: DATA
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0xff, // Payload
- };
- SpdyDataIR data_ir(1, "\xff");
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "'hello' data frame, with FIN";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x00, // Type: DATA
- 0x01, // Flags: END_STREAM
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x68, 0x65, 0x6c, 0x6c, // Payload
- 0x6f, //
- };
- SpdyDataIR data_ir(1, "hello");
- data_ir.set_fin(true);
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "Empty data frame";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x00, // Length: 0
- 0x00, // Type: DATA
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- };
- SpdyDataIR data_ir(1, "");
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
-
- frame = framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir);
- CompareCharArraysWithHexError(
- kDescription, reinterpret_cast<const unsigned char*>(frame.data()),
- framer.GetDataFrameMinimumSize(), kH2FrameData,
- framer.GetDataFrameMinimumSize());
- }
-
- {
- const char kDescription[] = "Data frame with max stream ID";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x00, // Type: DATA
- 0x01, // Flags: END_STREAM
- 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff
- 0x68, 0x65, 0x6c, 0x6c, // Payload
- 0x6f, //
- };
- SpdyDataIR data_ir(0x7fffffff, "hello");
- data_ir.set_fin(true);
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-}
-
-TEST_P(SpdyFramerTest, CreateRstStream) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- {
- const char kDescription[] = "RST_STREAM frame";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x01, // Error: PROTOCOL_ERROR
- };
- SpdyRstStreamIR rst_stream(1, ERROR_CODE_PROTOCOL_ERROR);
- SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeRstStream(rst_stream, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "RST_STREAM frame with max stream ID";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff
- 0x00, 0x00, 0x00, 0x01, // Error: PROTOCOL_ERROR
- };
- SpdyRstStreamIR rst_stream(0x7FFFFFFF, ERROR_CODE_PROTOCOL_ERROR);
- SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeRstStream(rst_stream, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "RST_STREAM frame with max status code";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff
- 0x00, 0x00, 0x00, 0x02, // Error: INTERNAL_ERROR
- };
- SpdyRstStreamIR rst_stream(0x7FFFFFFF, ERROR_CODE_INTERNAL_ERROR);
- SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeRstStream(rst_stream, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-}
-
-TEST_P(SpdyFramerTest, CreateSettings) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- {
- const char kDescription[] = "Network byte order SETTINGS frame";
-
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x06, // Length: 6
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE
- 0x0a, 0x0b, 0x0c, 0x0d, // Value: 168496141
- };
-
- uint32_t kValue = 0x0a0b0c0d;
- SpdySettingsIR settings_ir;
-
- SpdySettingsIds kId = SETTINGS_INITIAL_WINDOW_SIZE;
- settings_ir.AddSetting(kId, kValue);
-
- SpdySerializedFrame frame(framer.SerializeSettings(settings_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "Basic SETTINGS frame";
- // These end up seemingly out of order because of the way that our internal
- // ordering for settings_ir works. HTTP2 has no requirement on ordering on
- // the wire.
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x18, // Length: 24
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x01, // Param: HEADER_TABLE_SIZE
- 0x00, 0x00, 0x00, 0x05, // Value: 5
- 0x00, 0x02, // Param: ENABLE_PUSH
- 0x00, 0x00, 0x00, 0x06, // Value: 6
- 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS
- 0x00, 0x00, 0x00, 0x07, // Value: 7
- 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE
- 0x00, 0x00, 0x00, 0x08, // Value: 8
- };
-
- SpdySettingsIR settings_ir;
- settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 5);
- settings_ir.AddSetting(SETTINGS_ENABLE_PUSH, 6);
- settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 7);
- settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 8);
- SpdySerializedFrame frame(framer.SerializeSettings(settings_ir));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
-
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "Empty SETTINGS frame";
-
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x00, // Length: 0
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- };
- SpdySettingsIR settings_ir;
- SpdySerializedFrame frame(framer.SerializeSettings(settings_ir));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
-
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-}
-
-TEST_P(SpdyFramerTest, CreatePingFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- {
- const char kDescription[] = "PING frame";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x08, // Length: 8
- 0x06, // Type: PING
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x12, 0x34, 0x56, 0x78, // Opaque
- 0x9a, 0xbc, 0xde, 0xff, // Data
- };
- const unsigned char kH2FrameDataWithAck[] = {
- 0x00, 0x00, 0x08, // Length: 8
- 0x06, // Type: PING
- 0x01, // Flags: ACK
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x12, 0x34, 0x56, 0x78, // Opaque
- 0x9a, 0xbc, 0xde, 0xff, // Data
- };
- SpdySerializedFrame frame;
- const SpdyPingId kPingId = 0x123456789abcdeffULL;
- SpdyPingIR ping_ir(kPingId);
- // Tests SpdyPingIR when the ping is not an ack.
- ASSERT_FALSE(ping_ir.is_ack());
- frame = framer.SerializePing(ping_ir);
- if (use_output_) {
- ASSERT_TRUE(framer.SerializePing(ping_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
-
- // Tests SpdyPingIR when the ping is an ack.
- ping_ir.set_is_ack(true);
- frame = framer.SerializePing(ping_ir);
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializePing(ping_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameDataWithAck,
- arraysize(kH2FrameDataWithAck));
- }
-}
-
-TEST_P(SpdyFramerTest, CreateGoAway) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- {
- const char kDescription[] = "GOAWAY frame";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x0a, // Length: 10
- 0x07, // Type: GOAWAY
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x00, 0x00, 0x00, // Last: 0
- 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR
- 0x47, 0x41, // Description
- };
- SpdyGoAwayIR goaway_ir(0, ERROR_CODE_NO_ERROR, "GA");
- SpdySerializedFrame frame(framer.SerializeGoAway(goaway_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeGoAway(goaway_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "GOAWAY frame with max stream ID, status";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x0a, // Length: 10
- 0x07, // Type: GOAWAY
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x7f, 0xff, 0xff, 0xff, // Last: 0x7fffffff
- 0x00, 0x00, 0x00, 0x02, // Error: INTERNAL_ERROR
- 0x47, 0x41, // Description
- };
- SpdyGoAwayIR goaway_ir(0x7FFFFFFF, ERROR_CODE_INTERNAL_ERROR, "GA");
- SpdySerializedFrame frame(framer.SerializeGoAway(goaway_ir));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeGoAway(goaway_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-}
-
-TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
-
- {
- const char kDescription[] = "HEADERS frame, no FIN";
- // frame-format off
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x12, // Length: 18
- 0x01, // Type: HEADERS
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x03, // Value Len: 3
- 0x62, 0x61, 0x72, // bar
- };
- // frame-format on
-
- SpdyHeadersIR headers(1);
- headers.SetHeader("bar", "foo");
- headers.SetHeader("foo", "bar");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers, use_output_ ? &output_ : nullptr));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] =
- "HEADERS frame with a 0-length header name, FIN, max stream ID";
- // frame-format off
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x0f, // Length: 15
- 0x01, // Type: HEADERS
- 0x05, // Flags: END_STREAM|END_HEADERS
- 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647
-
- 0x00, // Unindexed Entry
- 0x00, // Name Len: 0
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x03, // Value Len: 3
- 0x62, 0x61, 0x72, // bar
- };
- // frame-format on
- SpdyHeadersIR headers(0x7fffffff);
- headers.set_fin(true);
- headers.SetHeader("", "foo");
- headers.SetHeader("foo", "bar");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers, use_output_ ? &output_ : nullptr));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] =
- "HEADERS frame with a 0-length header val, FIN, max stream ID";
- // frame-format off
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x0f, // Length: 15
- 0x01, // Type: HEADERS
- 0x05, // Flags: END_STREAM|END_HEADERS
- 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x00, // Value Len: 0
- };
- // frame-format on
- SpdyHeadersIR headers_ir(0x7fffffff);
- headers_ir.set_fin(true);
- headers_ir.SetHeader("bar", "foo");
- headers_ir.SetHeader("foo", "");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers_ir, use_output_ ? &output_ : nullptr));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] =
- "HEADERS frame with a 0-length header val, FIN, max stream ID, pri";
-
- // frame-format off
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x14, // Length: 20
- 0x01, // Type: HEADERS
- 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY
- 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647
- 0x00, 0x00, 0x00, 0x00, // Parent: 0
- 0xdb, // Weight: 220
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x00, // Value Len: 0
- };
- // frame-format on
- SpdyHeadersIR headers_ir(0x7fffffff);
- headers_ir.set_fin(true);
- headers_ir.set_has_priority(true);
- headers_ir.set_weight(220);
- headers_ir.SetHeader("bar", "foo");
- headers_ir.SetHeader("foo", "");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers_ir, use_output_ ? &output_ : nullptr));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] =
- "HEADERS frame with a 0-length header val, FIN, max stream ID, pri, "
- "exclusive=true, parent_stream=0";
-
- // frame-format off
- const unsigned char kV4FrameData[] = {
- 0x00, 0x00, 0x14, // Length: 20
- 0x01, // Type: HEADERS
- 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY
- 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647
- 0x80, 0x00, 0x00, 0x00, // Parent: 0 (Exclusive)
- 0xdb, // Weight: 220
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x00, // Value Len: 0
- };
- // frame-format on
- SpdyHeadersIR headers_ir(0x7fffffff);
- headers_ir.set_fin(true);
- headers_ir.set_has_priority(true);
- headers_ir.set_weight(220);
- headers_ir.set_exclusive(true);
- headers_ir.set_parent_stream_id(0);
- headers_ir.SetHeader("bar", "foo");
- headers_ir.SetHeader("foo", "");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers_ir, use_output_ ? &output_ : nullptr));
- CompareFrame(kDescription, frame, kV4FrameData, arraysize(kV4FrameData));
- }
-
- {
- const char kDescription[] =
- "HEADERS frame with a 0-length header val, FIN, max stream ID, pri, "
- "exclusive=false, parent_stream=max stream ID";
-
- // frame-format off
- const unsigned char kV4FrameData[] = {
- 0x00, 0x00, 0x14, // Length: 20
- 0x01, // Type: HEADERS
- 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY
- 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647
- 0x7f, 0xff, 0xff, 0xff, // Parent: 2147483647
- 0xdb, // Weight: 220
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x00, // Value Len: 0
- };
- // frame-format on
- SpdyHeadersIR headers_ir(0x7fffffff);
- headers_ir.set_fin(true);
- headers_ir.set_has_priority(true);
- headers_ir.set_weight(220);
- headers_ir.set_exclusive(false);
- headers_ir.set_parent_stream_id(0x7fffffff);
- headers_ir.SetHeader("bar", "foo");
- headers_ir.SetHeader("foo", "");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers_ir, use_output_ ? &output_ : nullptr));
- CompareFrame(kDescription, frame, kV4FrameData, arraysize(kV4FrameData));
- }
-
- {
- const char kDescription[] =
- "HEADERS frame with a 0-length header name, FIN, max stream ID, padded";
-
- // frame-format off
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x15, // Length: 21
- 0x01, // Type: HEADERS
- 0x0d, // Flags: END_STREAM|END_HEADERS|PADDED
- 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647
- 0x05, // PadLen: 5 trailing bytes
-
- 0x00, // Unindexed Entry
- 0x00, // Name Len: 0
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x03, // Value Len: 3
- 0x62, 0x61, 0x72, // bar
-
- 0x00, 0x00, 0x00, 0x00, // Padding
- 0x00, // Padding
- };
- // frame-format on
- SpdyHeadersIR headers_ir(0x7fffffff);
- headers_ir.set_fin(true);
- headers_ir.SetHeader("", "foo");
- headers_ir.SetHeader("foo", "bar");
- headers_ir.set_padding_len(6);
- SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers_ir, use_output_ ? &output_ : nullptr));
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-}
-
-TEST_P(SpdyFramerTest, CreateWindowUpdate) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- {
- const char kDescription[] = "WINDOW_UPDATE frame";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x08, // Type: WINDOW_UPDATE
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x01, // Increment: 1
- };
- SpdySerializedFrame frame(
- framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 1)));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(
- framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 1), &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x08, // Type: WINDOW_UPDATE
- 0x00, // Flags: none
- 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff
- 0x00, 0x00, 0x00, 0x01, // Increment: 1
- };
- SpdySerializedFrame frame(
- framer.SerializeWindowUpdate(SpdyWindowUpdateIR(0x7FFFFFFF, 1)));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeWindowUpdate(
- SpdyWindowUpdateIR(0x7FFFFFFF, 1), &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-
- {
- const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x08, // Type: WINDOW_UPDATE
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x7f, 0xff, 0xff, 0xff, // Increment: 0x7fffffff
- };
- SpdySerializedFrame frame(
- framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 0x7FFFFFFF)));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeWindowUpdate(
- SpdyWindowUpdateIR(1, 0x7FFFFFFF), &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
- }
-}
-
-TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) {
- {
- // Test framing PUSH_PROMISE without padding.
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- const char kDescription[] = "PUSH_PROMISE frame without padding";
-
- // frame-format off
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x16, // Length: 22
- 0x05, // Type: PUSH_PROMISE
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x29, // Stream: 41
- 0x00, 0x00, 0x00, 0x3a, // Promise: 58
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x03, // Value Len: 3
- 0x62, 0x61, 0x72, // bar
- };
- // frame-format on
-
- SpdyPushPromiseIR push_promise(41, 58);
- push_promise.SetHeader("bar", "foo");
- push_promise.SetHeader("foo", "bar");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
- CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
- }
-
- {
- // Test framing PUSH_PROMISE with one byte of padding.
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- const char kDescription[] = "PUSH_PROMISE frame with one byte of padding";
-
- // frame-format off
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x17, // Length: 23
- 0x05, // Type: PUSH_PROMISE
- 0x0c, // Flags: END_HEADERS|PADDED
- 0x00, 0x00, 0x00, 0x29, // Stream: 41
- 0x00, // PadLen: 0 trailing bytes
- 0x00, 0x00, 0x00, 0x3a, // Promise: 58
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x03, // Value Len: 3
- 0x62, 0x61, 0x72, // bar
- };
- // frame-format on
-
- SpdyPushPromiseIR push_promise(41, 58);
- push_promise.set_padding_len(1);
- push_promise.SetHeader("bar", "foo");
- push_promise.SetHeader("foo", "bar");
- output_.Reset();
- SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
-
- CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
- }
-
- {
- // Test framing PUSH_PROMISE with 177 bytes of padding.
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- const char kDescription[] = "PUSH_PROMISE frame with 177 bytes of padding";
-
- // frame-format off
- // clang-format off
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0xc7, // Length: 199
- 0x05, // Type: PUSH_PROMISE
- 0x0c, // Flags: END_HEADERS|PADDED
- 0x00, 0x00, 0x00, 0x2a, // Stream: 42
- 0xb0, // PadLen: 176 trailing bytes
- 0x00, 0x00, 0x00, 0x39, // Promise: 57
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x03, // Value Len: 3
- 0x62, 0x61, 0x72, // bar
-
- // Padding of 176 0x00(s).
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- };
- // clang-format on
- // frame-format on
-
- SpdyPushPromiseIR push_promise(42, 57);
- push_promise.set_padding_len(177);
- push_promise.SetHeader("bar", "foo");
- push_promise.SetHeader("foo", "bar");
- output_.Reset();
- SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
-
- CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
- }
-}
-
-// Regression test for https://crbug.com/464748.
-TEST_P(SpdyFramerTest, GetNumberRequiredContinuationFrames) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- EXPECT_EQ(1u, SpdyFramerPeer::GetNumberRequiredContinuationFrames(
- &framer, 16383 + 16374));
- EXPECT_EQ(2u, SpdyFramerPeer::GetNumberRequiredContinuationFrames(
- &framer, 16383 + 16374 + 1));
- EXPECT_EQ(2u, SpdyFramerPeer::GetNumberRequiredContinuationFrames(
- &framer, 16383 + 2 * 16374));
- EXPECT_EQ(3u, SpdyFramerPeer::GetNumberRequiredContinuationFrames(
- &framer, 16383 + 2 * 16374 + 1));
-}
-
-TEST_P(SpdyFramerTest, CreateContinuationUncompressed) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- const char kDescription[] = "CONTINUATION frame";
-
- // frame-format off
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x12, // Length: 18
- 0x09, // Type: CONTINUATION
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x2a, // Stream: 42
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x03, // Value Len: 3
- 0x62, 0x61, 0x72, // bar
- };
- // frame-format on
-
- SpdyHeaderBlock header_block;
- header_block["bar"] = "foo";
- header_block["foo"] = "bar";
- auto buffer = base::MakeUnique<SpdyString>();
- HpackEncoder encoder(ObtainHpackHuffmanTable());
- encoder.DisableCompression();
- encoder.EncodeHeaderSet(header_block, buffer.get());
-
- SpdyContinuationIR continuation(42);
- continuation.take_encoding(std::move(buffer));
- continuation.set_end_headers(true);
-
- SpdySerializedFrame frame(framer.SerializeContinuation(continuation));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
-}
-
-// Test that if we send an unexpected CONTINUATION
-// we signal an error (but don't crash).
-TEST_P(SpdyFramerTest, SendUnexpectedContinuation) {
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- // frame-format off
- char kH2FrameData[] = {
- 0x00, 0x00, 0x12, // Length: 18
- 0x09, // Type: CONTINUATION
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x2a, // Stream: 42
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x62, 0x61, 0x72, // bar
- 0x03, // Value Len: 3
- 0x66, 0x6f, 0x6f, // foo
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x66, 0x6f, 0x6f, // foo
- 0x03, // Value Len: 3
- 0x62, 0x61, 0x72, // bar
- };
- // frame-format on
-
- SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false);
-
- // We shouldn't have to read the whole frame before we signal an error.
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
- EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size()));
- EXPECT_TRUE(framer.HasError());
- EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) {
- {
- // Test framing in a case such that a PUSH_PROMISE frame, with one byte of
- // padding, cannot hold all the data payload, which is overflowed to the
- // consecutive CONTINUATION frame.
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- const char kDescription[] =
- "PUSH_PROMISE and CONTINUATION frames with one byte of padding";
-
- // frame-format off
- const unsigned char kPartialPushPromiseFrameData[] = {
- 0x00, 0x3f, 0xf6, // Length: 16374
- 0x05, // Type: PUSH_PROMISE
- 0x08, // Flags: PADDED
- 0x00, 0x00, 0x00, 0x2a, // Stream: 42
- 0x00, // PadLen: 0 trailing bytes
- 0x00, 0x00, 0x00, 0x39, // Promise: 57
-
- 0x00, // Unindexed Entry
- 0x03, // Name Len: 3
- 0x78, 0x78, 0x78, // xxx
- 0x7f, 0x80, 0x7f, // Value Len: 16361
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- };
- const unsigned char kContinuationFrameData[] = {
- 0x00, 0x00, 0x16, // Length: 22
- 0x09, // Type: CONTINUATION
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x2a, // Stream: 42
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, 0x78, 0x78, 0x78, // xxxx
- 0x78, // x
- };
- // frame-format on
-
- SpdyPushPromiseIR push_promise(42, 57);
- push_promise.set_padding_len(1);
- SpdyString big_value(TestSpdyVisitor::sent_control_frame_max_size(), 'x');
- push_promise.SetHeader("xxx", big_value);
- SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
-
- // The entire frame should look like below:
- // Name Length in Byte
- // ------------------------------------------- Begin of PUSH_PROMISE frame
- // PUSH_PROMISE header 9
- // Pad length field 1
- // Promised stream 4
- // Length field of key 2
- // Content of key 3
- // Length field of value 3
- // Part of big_value 16361
- // ------------------------------------------- Begin of CONTINUATION frame
- // CONTINUATION header 9
- // Remaining of big_value 22
- // ------------------------------------------- End
-
- // Length of everything listed above except big_value.
- int len_non_data_payload = 31;
- EXPECT_EQ(
- TestSpdyVisitor::sent_control_frame_max_size() + len_non_data_payload,
- frame.size());
-
- // Partially compare the PUSH_PROMISE frame against the template.
- const unsigned char* frame_data =
- reinterpret_cast<const unsigned char*>(frame.data());
- CompareCharArraysWithHexError(
- kDescription, frame_data, arraysize(kPartialPushPromiseFrameData),
- kPartialPushPromiseFrameData, arraysize(kPartialPushPromiseFrameData));
-
- // Compare the CONTINUATION frame against the template.
- frame_data += TestSpdyVisitor::sent_control_frame_max_size();
- CompareCharArraysWithHexError(
- kDescription, frame_data, arraysize(kContinuationFrameData),
- kContinuationFrameData, arraysize(kContinuationFrameData));
- }
-}
-
-TEST_P(SpdyFramerTest, CreateAltSvc) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- const char kDescription[] = "ALTSVC frame";
- const unsigned char kType = SerializeFrameType(SpdyFrameType::ALTSVC);
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x49, kType, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 'o',
- 'r', 'i', 'g', 'i', 'n', 'p', 'i', 'd', '1', '=', '"', 'h',
- 'o', 's', 't', ':', '4', '4', '3', '"', ';', ' ', 'm', 'a',
- '=', '5', ',', 'p', '%', '2', '2', '%', '3', 'D', 'i', '%',
- '3', 'A', 'd', '=', '"', 'h', '_', '\\', '\\', 'o', '\\', '"',
- 's', 't', ':', '1', '2', '3', '"', ';', ' ', 'm', 'a', '=',
- '4', '2', ';', ' ', 'v', '=', '"', '2', '4', '"'};
- SpdyAltSvcIR altsvc_ir(3);
- altsvc_ir.set_origin("origin");
- altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService(
- "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()));
- altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService(
- "p\"=i:d", "h_\\o\"st", 123, 42,
- SpdyAltSvcWireFormat::VersionVector{24}));
- SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
-}
-
-TEST_P(SpdyFramerTest, CreatePriority) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- const char kDescription[] = "PRIORITY frame";
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x05, // Length: 5
- 0x02, // Type: PRIORITY
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x02, // Stream: 2
- 0x80, 0x00, 0x00, 0x01, // Parent: 1 (Exclusive)
- 0x10, // Weight: 17
- };
- SpdyPriorityIR priority_ir(2, 1, 17, true);
- SpdySerializedFrame frame(framer.SerializeFrame(priority_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeFrame(priority_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
- SpdyPriorityIR priority2(2);
- priority2.set_parent_stream_id(1);
- priority2.set_weight(17);
- priority2.set_exclusive(true);
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeFrame(priority2, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- } else {
- frame = framer.SerializeFrame(priority2);
- }
- CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
-}
-
-TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdyHeadersIR headers_ir(1);
- headers_ir.SetHeader("alpha", "beta");
- headers_ir.SetHeader("gamma", "delta");
- SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers_ir, use_output_ ? &output_ : nullptr));
- TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.control_frame_header_data_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(0, visitor.end_of_stream_count_);
- EXPECT_EQ(headers_ir.header_block(), visitor.headers_);
-}
-
-TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdyHeadersIR headers_ir(1);
- headers_ir.set_fin(true);
- headers_ir.SetHeader("alpha", "beta");
- headers_ir.SetHeader("gamma", "delta");
- SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers_ir, use_output_ ? &output_ : nullptr));
- TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.control_frame_header_data_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(1, visitor.end_of_stream_count_);
- EXPECT_EQ(headers_ir.header_block(), visitor.headers_);
-}
-
-TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- SpdyHeadersIR headers(1);
- headers.set_padding_len(256);
-
- // Exact payload length will change with HPACK, but this should be long
- // enough to cause an overflow.
- const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size();
- SpdyString big_value(kBigValueSize, 'x');
- headers.SetHeader("aa", big_value);
- SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers, use_output_ ? &output_ : nullptr));
- EXPECT_GT(control_frame.size(),
- TestSpdyVisitor::sent_control_frame_max_size());
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- EXPECT_TRUE(visitor.header_buffer_valid_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(1, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
-}
-
-TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- auto headers = base::MakeUnique<SpdyHeadersIR>(1);
- headers->set_padding_len(256);
-
- // Exact payload length will change with HPACK, but this should be long
- // enough to cause an overflow.
- const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size();
- SpdyString big_valuex(kBigValueSize, 'x');
- headers->SetHeader("aa", big_valuex);
- SpdyString big_valuez(kBigValueSize, 'z');
- headers->SetHeader("bb", big_valuez);
-
- SpdyFramer::SpdyHeaderFrameIterator frame_it(&framer, std::move(headers));
-
- EXPECT_TRUE(frame_it.HasNextFrame());
- EXPECT_TRUE(frame_it.NextFrame(&output_));
- SpdySerializedFrame headers_frame(output_.Begin(), output_.Size(), false);
- EXPECT_EQ(headers_frame.size(),
- TestSpdyVisitor::sent_control_frame_max_size());
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(headers_frame.data()),
- headers_frame.size());
- EXPECT_TRUE(visitor.header_buffer_valid_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
-
- output_.Reset();
- EXPECT_TRUE(frame_it.HasNextFrame());
- EXPECT_TRUE(frame_it.NextFrame(&output_));
- SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false);
- EXPECT_EQ(first_cont_frame.size(),
- TestSpdyVisitor::sent_control_frame_max_size());
-
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(first_cont_frame.data()),
- first_cont_frame.size());
- EXPECT_TRUE(visitor.header_buffer_valid_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(1, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
-
- output_.Reset();
- EXPECT_TRUE(frame_it.HasNextFrame());
- EXPECT_TRUE(frame_it.NextFrame(&output_));
- SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false);
- EXPECT_LT(second_cont_frame.size(),
- TestSpdyVisitor::sent_control_frame_max_size());
-
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(second_cont_frame.data()),
- second_cont_frame.size());
- EXPECT_TRUE(visitor.header_buffer_valid_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(2, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
-
- EXPECT_FALSE(frame_it.HasNextFrame());
-}
-
-TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- auto push_promise = base::MakeUnique<SpdyPushPromiseIR>(1, 2);
- push_promise->set_padding_len(256);
-
- // Exact payload length will change with HPACK, but this should be long
- // enough to cause an overflow.
- const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size();
- SpdyString big_valuex(kBigValueSize, 'x');
- push_promise->SetHeader("aa", big_valuex);
- SpdyString big_valuez(kBigValueSize, 'z');
- push_promise->SetHeader("bb", big_valuez);
-
- SpdyFramer::SpdyPushPromiseFrameIterator frame_it(&framer,
- std::move(push_promise));
-
- EXPECT_TRUE(frame_it.HasNextFrame());
- EXPECT_TRUE(frame_it.NextFrame(&output_));
- SpdySerializedFrame push_promise_frame(output_.Begin(), output_.Size(),
- false);
- EXPECT_EQ(push_promise_frame.size(),
- TestSpdyVisitor::sent_control_frame_max_size());
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(push_promise_frame.data()),
- push_promise_frame.size());
- EXPECT_TRUE(visitor.header_buffer_valid_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.push_promise_frame_count_);
- EXPECT_EQ(0, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
-
- EXPECT_TRUE(frame_it.HasNextFrame());
- output_.Reset();
- EXPECT_TRUE(frame_it.NextFrame(&output_));
- SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false);
-
- EXPECT_EQ(first_cont_frame.size(),
- TestSpdyVisitor::sent_control_frame_max_size());
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(first_cont_frame.data()),
- first_cont_frame.size());
- EXPECT_TRUE(visitor.header_buffer_valid_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.push_promise_frame_count_);
- EXPECT_EQ(1, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
-
- EXPECT_TRUE(frame_it.HasNextFrame());
- output_.Reset();
- EXPECT_TRUE(frame_it.NextFrame(&output_));
- SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false);
- EXPECT_LT(second_cont_frame.size(),
- TestSpdyVisitor::sent_control_frame_max_size());
-
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(second_cont_frame.data()),
- second_cont_frame.size());
- EXPECT_TRUE(visitor.header_buffer_valid_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.push_promise_frame_count_);
- EXPECT_EQ(2, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
-
- EXPECT_FALSE(frame_it.HasNextFrame());
-}
-
-TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) {
- SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
- SpdyPushPromiseIR push_promise(1, 2);
- push_promise.set_padding_len(256);
-
- // Exact payload length will change with HPACK, but this should be long
- // enough to cause an overflow.
- const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size();
- SpdyString big_value(kBigValueSize, 'x');
- push_promise.SetHeader("aa", big_value);
- SpdySerializedFrame control_frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
- EXPECT_GT(control_frame.size(),
- TestSpdyVisitor::sent_control_frame_max_size());
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- EXPECT_TRUE(visitor.header_buffer_valid_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.push_promise_frame_count_);
- EXPECT_EQ(1, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
-}
-
-// Check that the framer stops delivering header data chunks once the visitor
-// declares it doesn't want any more. This is important to guard against
-// "zip bomb" types of attacks.
-TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
- const size_t kHeaderBufferChunks = 4;
- const size_t kHeaderBufferSize =
- TestSpdyVisitor::header_data_chunk_max_size() * kHeaderBufferChunks;
- const size_t kBigValueSize = kHeaderBufferSize * 2;
- SpdyString big_value(kBigValueSize, 'x');
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdyHeadersIR headers(1);
- headers.set_fin(true);
- headers.SetHeader("aa", big_value);
- SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers, use_output_ ? &output_ : nullptr));
- TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
- visitor.set_header_buffer_size(kHeaderBufferSize);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- // It's up to the visitor to ignore extraneous header data; the framer
- // won't throw an error.
- EXPECT_GT(visitor.header_bytes_received_, visitor.header_buffer_.size());
- EXPECT_EQ(1, visitor.end_of_stream_count_);
-}
-
-TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- // Create a GoAway frame that has a few extra bytes at the end.
- // We create enough overhead to overflow the framer's control frame buffer.
- ASSERT_LE(SpdyFramerPeer::ControlFrameBufferSize(), 250u);
- const size_t length = SpdyFramerPeer::ControlFrameBufferSize() + 1;
-
- // HTTP/2 GOAWAY frames are only bound by a minimal length, since they may
- // carry opaque data. Verify that minimal length is tested.
- ASSERT_GT(framer.GetGoAwayMinimumSize(), kFrameHeaderSize);
- const size_t less_than_min_length =
- framer.GetGoAwayMinimumSize() - kFrameHeaderSize - 1;
- ASSERT_LE(less_than_min_length, std::numeric_limits<unsigned char>::max());
- const unsigned char kH2Len = static_cast<unsigned char>(less_than_min_length);
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, kH2Len, // Length: min length - 1
- 0x07, // Type: GOAWAY
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x00, 0x00, 0x00, // Last: 0
- 0x00, 0x00, 0x00, // Truncated Status Field
- };
- const size_t pad_length = length + kFrameHeaderSize - sizeof(kH2FrameData);
- SpdyString pad(pad_length, 'A');
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
-
- visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
- visitor.SimulateInFramer(reinterpret_cast<const unsigned char*>(pad.c_str()),
- pad.length());
-
- EXPECT_EQ(1, visitor.error_count_); // This generated an error.
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
- EXPECT_EQ(0, visitor.goaway_count_); // Frame not parsed.
-}
-
-TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdySettingsIR settings_ir;
- SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_));
- control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- SetFrameLength(&control_frame, 0);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- framer.GetFrameHeaderSize());
- // Zero-len settings frames are permitted as of HTTP/2.
- EXPECT_EQ(0, visitor.error_count_);
-}
-
-// Tests handling of SETTINGS frames with invalid length.
-TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdySettingsIR settings_ir;
-
- // Add settings to more than fill the frame so that we don't get a buffer
- // overflow when calling SimulateInFramer() below. These settings must be
- // distinct parameters because SpdySettingsIR has a map for settings, and will
- // collapse multiple copies of the same parameter.
- settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 0x00000002);
- settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0x00000002);
- SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_));
- control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- const size_t kNewLength = 8;
- SetFrameLength(&control_frame, kNewLength);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- framer.GetFrameHeaderSize() + kNewLength);
- // Should generate an error, since its not possible to have a
- // settings frame of length kNewLength.
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
-}
-
-// Tests handling of SETTINGS frames larger than the frame buffer size.
-TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdySettingsIR settings_ir;
- settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 5);
- settings_ir.AddSetting(SETTINGS_ENABLE_PUSH, 6);
- settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 7);
-
- SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_));
- control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
-
- EXPECT_LT(SpdyFramerPeer::ControlFrameBufferSize(), control_frame.size());
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
-
- // Read all at once.
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(3, visitor.setting_count_);
- EXPECT_EQ(1, visitor.settings_ack_sent_);
-
- // Read data in small chunks.
- size_t framed_data = 0;
- size_t unframed_data = control_frame.size();
- 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(3 * 2, visitor.setting_count_);
- EXPECT_EQ(2, visitor.settings_ack_sent_);
-}
-
-// Tests handling of SETTINGS frame with duplicate entries.
-TEST_P(SpdyFramerTest, ReadDuplicateSettings) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x12, // Length: 18
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x01, // Param: HEADER_TABLE_SIZE
- 0x00, 0x00, 0x00, 0x02, // Value: 2
- 0x00, 0x01, // Param: HEADER_TABLE_SIZE
- 0x00, 0x00, 0x00, 0x03, // Value: 3
- 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS
- 0x00, 0x00, 0x00, 0x03, // Value: 3
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
-
- // In HTTP/2, duplicate settings are allowed;
- // each setting replaces the previous value for that setting.
- EXPECT_EQ(3, visitor.setting_count_);
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.settings_ack_sent_);
-}
-
-// Tests handling of SETTINGS frame with a setting we don't recognize.
-TEST_P(SpdyFramerTest, ReadUnknownSettingsId) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x06, // Length: 6
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x10, // Param: 16
- 0x00, 0x00, 0x00, 0x02, // Value: 2
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
-
- // In HTTP/2, we ignore unknown settings because of extensions.
- EXPECT_EQ(0, visitor.setting_count_);
- EXPECT_EQ(0, visitor.error_count_);
-}
-
-TEST_P(SpdyFramerTest, ReadUnknownSettingsWithExtension) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x0c, // Length: 12
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x10, // Param: 16
- 0x00, 0x00, 0x00, 0x02, // Value: 2
- 0x00, 0x5f, // Param: 95
- 0x00, 0x01, 0x00, 0x02, // Value: 65538
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- TestExtension extension;
- visitor.set_extension_visitor(&extension);
- visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
-
- // In HTTP/2, we ignore unknown settings because of extensions.
- EXPECT_EQ(0, visitor.setting_count_);
- EXPECT_EQ(0, visitor.error_count_);
-
- EXPECT_THAT(
- extension.settings_received_,
- testing::ElementsAre(testing::Pair(16, 2), testing::Pair(95, 65538)));
-}
-
-// Tests handling of SETTINGS frame with entries out of order.
-TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x12, // Length: 18
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x02, // Param: ENABLE_PUSH
- 0x00, 0x00, 0x00, 0x02, // Value: 2
- 0x00, 0x01, // Param: HEADER_TABLE_SIZE
- 0x00, 0x00, 0x00, 0x03, // Value: 3
- 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS
- 0x00, 0x00, 0x00, 0x03, // Value: 3
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData));
-
- // In HTTP/2, settings are allowed in any order.
- EXPECT_EQ(3, visitor.setting_count_);
- EXPECT_EQ(0, visitor.error_count_);
-}
-
-TEST_P(SpdyFramerTest, ProcessSettingsAckFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x00, // Length: 0
- 0x04, // Type: SETTINGS
- 0x01, // Flags: ACK
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kFrameData, sizeof(kFrameData));
-
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(0, visitor.setting_count_);
- EXPECT_EQ(1, visitor.settings_ack_received_);
-}
-
-TEST_P(SpdyFramerTest, ProcessDataFrameWithPadding) {
- const int kPaddingLen = 119;
- const char data_payload[] = "hello";
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyDataIR data_ir(1, data_payload);
- data_ir.set_padding_len(kPaddingLen);
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
-
- int bytes_consumed = 0;
-
- // Send the frame header.
- EXPECT_CALL(visitor,
- OnDataFrameHeader(1, kPaddingLen + strlen(data_payload), false));
- CHECK_EQ(framer.GetDataFrameMinimumSize(),
- framer.ProcessInput(frame.data(), framer.GetDataFrameMinimumSize()));
- CHECK_EQ(framer.state(), SpdyFramer::SPDY_READ_DATA_FRAME_PADDING_LENGTH);
- CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR);
- bytes_consumed += framer.GetDataFrameMinimumSize();
-
- // Send the padding length field.
- EXPECT_CALL(visitor, OnStreamPadding(1, 1));
- CHECK_EQ(1u, framer.ProcessInput(frame.data() + bytes_consumed, 1));
- CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME);
- CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR);
- bytes_consumed += 1;
-
- // Send the first two bytes of the data payload, i.e., "he".
- EXPECT_CALL(visitor, OnStreamFrameData(1, _, 2));
- CHECK_EQ(2u, framer.ProcessInput(frame.data() + bytes_consumed, 2));
- CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME);
- CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR);
- bytes_consumed += 2;
-
- // Send the rest three bytes of the data payload, i.e., "llo".
- EXPECT_CALL(visitor, OnStreamFrameData(1, _, 3));
- CHECK_EQ(3u, framer.ProcessInput(frame.data() + bytes_consumed, 3));
- CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING);
- CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR);
- bytes_consumed += 3;
-
- // Send the first 100 bytes of the padding payload.
- EXPECT_CALL(visitor, OnStreamPadding(1, 100));
- CHECK_EQ(100u, framer.ProcessInput(frame.data() + bytes_consumed, 100));
- CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING);
- CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR);
- bytes_consumed += 100;
-
- // Send rest of the padding payload.
- EXPECT_CALL(visitor, OnStreamPadding(1, 18));
- CHECK_EQ(18u, framer.ProcessInput(frame.data() + bytes_consumed, 18));
- CHECK_EQ(framer.state(), SpdyFramer::SPDY_READY_FOR_FRAME);
- CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR);
-}
-
-TEST_P(SpdyFramerTest, ReadWindowUpdate) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdySerializedFrame control_frame(
- framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2)));
- if (use_output_) {
- ASSERT_TRUE(
- framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2), &output_));
- control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- EXPECT_EQ(1u, visitor.last_window_update_stream_);
- EXPECT_EQ(2, visitor.last_window_update_delta_);
-}
-
-TEST_P(SpdyFramerTest, ReadCompressedPushPromise) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdyPushPromiseIR push_promise(42, 57);
- push_promise.SetHeader("foo", "bar");
- push_promise.SetHeader("bar", "foofoo");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
- TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
- visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()),
- frame.size());
- EXPECT_EQ(42u, visitor.last_push_promise_stream_);
- EXPECT_EQ(57u, visitor.last_push_promise_promised_stream_);
- EXPECT_EQ(push_promise.header_block(), visitor.headers_);
-}
-
-TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) {
- // frame-format off
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x14, // Length: 20
- 0x01, // Type: HEADERS
- 0x08, // Flags: PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x03, // PadLen: 3 trailing bytes
- 0x00, // Unindexed Entry
- 0x06, // Name Len: 6
- 'c', 'o', 'o', 'k', 'i', 'e', // Name
- 0x07, // Value Len: 7
- 'f', 'o', 'o', '=', 'b', 'a', 'r', // Value
- 0x00, 0x00, 0x00, // Padding
-
- 0x00, 0x00, 0x14, // Length: 20
- 0x09, // Type: CONTINUATION
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, // Unindexed Entry
- 0x06, // Name Len: 6
- 'c', 'o', 'o', 'k', 'i', 'e', // Name
- 0x08, // Value Len: 7
- 'b', 'a', 'z', '=', 'b', 'i', 'n', 'g', // Value
- 0x00, // Unindexed Entry
- 0x06, // Name Len: 6
- 'c', // Name (split)
-
- 0x00, 0x00, 0x12, // Length: 18
- 0x09, // Type: CONTINUATION
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 'o', 'o', 'k', 'i', 'e', // Name (continued)
- 0x00, // Value Len: 0
- 0x00, // Unindexed Entry
- 0x04, // Name Len: 4
- 'n', 'a', 'm', 'e', // Name
- 0x05, // Value Len: 5
- 'v', 'a', 'l', 'u', 'e', // Value
- };
- // frame-format on
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(2, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(0, visitor.end_of_stream_count_);
-
- EXPECT_THAT(
- visitor.headers_,
- testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "),
- testing::Pair("name", "value")));
-}
-
-TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) {
- // frame-format off
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x10, // Length: 20
- 0x01, // Type: HEADERS
- 0x01, // Flags: END_STREAM
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, // Unindexed Entry
- 0x06, // Name Len: 6
- 'c', 'o', 'o', 'k', 'i', 'e', // Name
- 0x07, // Value Len: 7
- 'f', 'o', 'o', '=', 'b', 'a', 'r', // Value
-
- 0x00, 0x00, 0x14, // Length: 20
- 0x09, // Type: CONTINUATION
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, // Unindexed Entry
- 0x06, // Name Len: 6
- 'c', 'o', 'o', 'k', 'i', 'e', // Name
- 0x08, // Value Len: 7
- 'b', 'a', 'z', '=', 'b', 'i', 'n', 'g', // Value
- 0x00, // Unindexed Entry
- 0x06, // Name Len: 6
- 'c', // Name (split)
-
- 0x00, 0x00, 0x12, // Length: 18
- 0x09, // Type: CONTINUATION
- 0x04, // Flags: END_HEADERS
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 'o', 'o', 'k', 'i', 'e', // Name (continued)
- 0x00, // Value Len: 0
- 0x00, // Unindexed Entry
- 0x04, // Name Len: 4
- 'n', 'a', 'm', 'e', // Name
- 0x05, // Value Len: 5
- 'v', 'a', 'l', 'u', 'e', // Value
- };
- // frame-format on
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(2, visitor.continuation_count_);
- EXPECT_EQ(1, visitor.fin_flag_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(1, visitor.end_of_stream_count_);
-
- EXPECT_THAT(
- visitor.headers_,
- testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "),
- testing::Pair("name", "value")));
-}
-
-TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {
- // frame-format off
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x17, 0x05, // PUSH_PROMISE
- 0x08, 0x00, 0x00, 0x00, // PADDED
- 0x01, 0x02, 0x00, 0x00, // Stream 1, Pad length field
- 0x00, 0x2A, 0x00, 0x06, // Promised stream 42
- 'c', 'o', 'o', 'k',
- 'i', 'e', 0x07, 'f',
- 'o', 'o', '=', 'b',
- 'a', 'r', 0x00, 0x00,
-
- 0x00, 0x00, 0x14, 0x09, // CONTINUATION
- 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x06, 'c', // Stream 1
- 'o', 'o', 'k', 'i',
- 'e', 0x08, 'b', 'a',
- 'z', '=', 'b', 'i',
- 'n', 'g', 0x00, 0x06,
- 'c',
-
- 0x00, 0x00, 0x12, 0x09, // CONTINUATION
- 0x04, 0x00, 0x00, 0x00, // END_HEADERS
- 0x01, 'o', 'o', 'k', // Stream 1
- 'i', 'e', 0x00, 0x00,
- 0x04, 'n', 'a', 'm',
- 'e', 0x05, 'v', 'a',
- 'l', 'u', 'e',
- };
- // frame-format on
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1u, visitor.last_push_promise_stream_);
- EXPECT_EQ(42u, visitor.last_push_promise_promised_stream_);
- EXPECT_EQ(2, visitor.continuation_count_);
- EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(0, visitor.end_of_stream_count_);
-
- EXPECT_THAT(
- visitor.headers_,
- testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "),
- testing::Pair("name", "value")));
-}
-
-// Receiving an unknown frame when a continuation is expected should
-// result in a SPDY_UNEXPECTED_FRAME error
-TEST_P(SpdyFramerTest, ReceiveUnknownMidContinuation) {
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x10, // Length: 16
- 0x01, // Type: HEADERS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // HPACK
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x07, 0x66, 0x6f, 0x6f, //
- 0x3d, 0x62, 0x61, 0x72, //
-
- 0x00, 0x00, 0x14, // Length: 20
- 0xa9, // Type: UnknownFrameType(169)
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // Payload
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x08, 0x62, 0x61, 0x7a, //
- 0x3d, 0x62, 0x69, 0x6e, //
- 0x67, 0x00, 0x06, 0x63, //
- };
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- // Assume the unknown frame is allowed
- visitor.on_unknown_frame_result_ = true;
- framer.set_visitor(&visitor);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.continuation_count_);
- EXPECT_EQ(0u, visitor.header_buffer_length_);
-}
-
-// Receiving an unknown frame when a continuation is expected should
-// result in a SPDY_UNEXPECTED_FRAME error
-TEST_P(SpdyFramerTest, ReceiveUnknownMidContinuationWithExtension) {
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x10, // Length: 16
- 0x01, // Type: HEADERS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // HPACK
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x07, 0x66, 0x6f, 0x6f, //
- 0x3d, 0x62, 0x61, 0x72, //
-
- 0x00, 0x00, 0x14, // Length: 20
- 0xa9, // Type: UnknownFrameType(169)
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // Payload
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x08, 0x62, 0x61, 0x7a, //
- 0x3d, 0x62, 0x69, 0x6e, //
- 0x67, 0x00, 0x06, 0x63, //
- };
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- TestExtension extension;
- visitor.set_extension_visitor(&extension);
- framer.set_visitor(&visitor);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.continuation_count_);
- EXPECT_EQ(0u, visitor.header_buffer_length_);
-}
-
-TEST_P(SpdyFramerTest, ReceiveContinuationOnWrongStream) {
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x10, // Length: 16
- 0x01, // Type: HEADERS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // HPACK
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x07, 0x66, 0x6f, 0x6f, //
- 0x3d, 0x62, 0x61, 0x72, //
-
- 0x00, 0x00, 0x14, // Length: 20
- 0x09, // Type: CONTINUATION
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x02, // Stream: 2
- 0x00, 0x06, 0x63, 0x6f, // HPACK
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x08, 0x62, 0x61, 0x7a, //
- 0x3d, 0x62, 0x69, 0x6e, //
- 0x67, 0x00, 0x06, 0x63, //
- };
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.continuation_count_);
- EXPECT_EQ(0u, visitor.header_buffer_length_);
-}
-
-TEST_P(SpdyFramerTest, ReadContinuationOutOfOrder) {
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x18, // Length: 24
- 0x09, // Type: CONTINUATION
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // HPACK
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x07, 0x66, 0x6f, 0x6f, //
- 0x3d, 0x62, 0x61, 0x72, //
- };
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
- EXPECT_EQ(0, visitor.continuation_count_);
- EXPECT_EQ(0u, visitor.header_buffer_length_);
-}
-
-TEST_P(SpdyFramerTest, ExpectContinuationReceiveData) {
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x10, // Length: 16
- 0x01, // Type: HEADERS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // HPACK
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x07, 0x66, 0x6f, 0x6f, //
- 0x3d, 0x62, 0x61, 0x72, //
-
- 0x00, 0x00, 0x00, // Length: 0
- 0x00, // Type: DATA
- 0x01, // Flags: END_STREAM
- 0x00, 0x00, 0x00, 0x04, // Stream: 4
-
- 0xde, 0xad, 0xbe, 0xef, // Truncated Frame Header
- };
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.continuation_count_);
- EXPECT_EQ(0u, visitor.header_buffer_length_);
- EXPECT_EQ(0, visitor.data_frame_count_);
-}
-
-TEST_P(SpdyFramerTest, ExpectContinuationReceiveControlFrame) {
- const unsigned char kInput[] = {
- 0x00, 0x00, 0x10, // Length: 16
- 0x01, // Type: HEADERS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // HPACK
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x07, 0x66, 0x6f, 0x6f, //
- 0x3d, 0x62, 0x61, 0x72, //
-
- 0x00, 0x00, 0x10, // Length: 16
- 0x01, // Type: HEADERS
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x06, 0x63, 0x6f, // HPACK
- 0x6f, 0x6b, 0x69, 0x65, //
- 0x07, 0x66, 0x6f, 0x6f, //
- 0x3d, 0x62, 0x61, 0x72, //
- };
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- visitor.SimulateInFramer(kInput, sizeof(kInput));
-
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
- EXPECT_EQ(1, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.continuation_count_);
- EXPECT_EQ(0u, visitor.header_buffer_length_);
- EXPECT_EQ(0, visitor.data_frame_count_);
-}
-
-TEST_P(SpdyFramerTest, ReadGarbage) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- unsigned char garbage_frame[256];
- memset(garbage_frame, ~0, sizeof(garbage_frame));
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame));
- EXPECT_EQ(1, visitor.error_count_);
-}
-
-TEST_P(SpdyFramerTest, ReadUnknownExtensionFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- // The unrecognized frame type should still have a valid length.
- const unsigned char unknown_frame[] = {
- 0x00, 0x00, 0x08, // Length: 8
- 0xff, // Type: UnknownFrameType(255)
- 0xff, // Flags: 0xff
- 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set)
- 0xff, 0xff, 0xff, 0xff, // Payload
- 0xff, 0xff, 0xff, 0xff, //
- };
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
-
- // Simulate the case where the stream id validation checks out.
- visitor.on_unknown_frame_result_ = true;
- visitor.SimulateInFramer(unknown_frame, arraysize(unknown_frame));
- EXPECT_EQ(0, visitor.error_count_);
-
- // Follow it up with a valid control frame to make sure we handle
- // subsequent frames correctly.
- SpdySettingsIR settings_ir;
- settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 10);
- SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir));
- if (use_output_) {
- ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_));
- control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1u, static_cast<unsigned>(visitor.setting_count_));
- EXPECT_EQ(1u, static_cast<unsigned>(visitor.settings_ack_sent_));
-}
-
-TEST_P(SpdyFramerTest, ReadUnknownExtensionFrameWithExtension) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
-
- // The unrecognized frame type should still have a valid length.
- const unsigned char unknown_frame[] = {
- 0x00, 0x00, 0x14, // Length: 20
- 0xff, // Type: UnknownFrameType(255)
- 0xff, // Flags: 0xff
- 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set)
- 0xff, 0xff, 0xff, 0xff, // Payload
- 0xff, 0xff, 0xff, 0xff, //
- 0xff, 0xff, 0xff, 0xff, //
- 0xff, 0xff, 0xff, 0xff, //
- 0xff, 0xff, 0xff, 0xff, //
- };
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- TestExtension extension;
- visitor.set_extension_visitor(&extension);
- visitor.SimulateInFramer(unknown_frame, arraysize(unknown_frame));
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(0x7fffffffu, extension.stream_id_);
- EXPECT_EQ(20u, extension.length_);
- EXPECT_EQ(255, extension.type_);
- EXPECT_EQ(0xff, extension.flags_);
- EXPECT_EQ(SpdyString(20, '\xff'), extension.payload_);
-
- // Follow it up with a valid control frame to make sure we handle
- // subsequent frames correctly.
- SpdySettingsIR settings_ir;
- settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 10);
- SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir));
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.data()),
- control_frame.size());
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1u, static_cast<unsigned>(visitor.setting_count_));
- EXPECT_EQ(1u, static_cast<unsigned>(visitor.settings_ack_sent_));
-}
-
-TEST_P(SpdyFramerTest, ReadGarbageWithValidLength) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x08, // Length: 8
- 0xff, // Type: UnknownFrameType(255)
- 0xff, // Flags: 0xff
- 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set)
- 0xff, 0xff, 0xff, 0xff, // Payload
- 0xff, 0xff, 0xff, 0xff, //
- };
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kFrameData, arraysize(kFrameData));
- EXPECT_EQ(1, visitor.error_count_);
-}
-
-TEST_P(SpdyFramerTest, ReadGarbageHPACKEncoding) {
- const unsigned char kInput[] = {
- 0x00, 0x12, 0x01, // Length: 4609
- 0x04, // Type: SETTINGS
- 0x00, // Flags: none
- 0x00, 0x00, 0x01, 0xef, // Stream: 495
- 0xef, 0xff, // Param: 61439
- 0xff, 0xff, 0xff, 0xff, // Value: 4294967295
- 0xff, 0xff, // Param: 0xffff
- 0xff, 0xff, 0xff, 0xff, // Value: 4294967295
- 0xff, 0xff, 0xff, 0xff, // Settings (Truncated)
- 0xff, //
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kInput, arraysize(kInput));
- EXPECT_EQ(1, visitor.error_count_);
-}
-
-TEST_P(SpdyFramerTest, SizesTest) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- EXPECT_EQ(9u, framer.GetDataFrameMinimumSize());
- EXPECT_EQ(9u, framer.GetFrameHeaderSize());
- EXPECT_EQ(13u, framer.GetRstStreamSize());
- EXPECT_EQ(9u, framer.GetSettingsMinimumSize());
- EXPECT_EQ(17u, framer.GetPingSize());
- EXPECT_EQ(17u, framer.GetGoAwayMinimumSize());
- EXPECT_EQ(9u, framer.GetHeadersMinimumSize());
- EXPECT_EQ(13u, framer.GetWindowUpdateSize());
- EXPECT_EQ(13u, framer.GetPushPromiseMinimumSize());
- EXPECT_EQ(11u, framer.GetAltSvcMinimumSize());
- EXPECT_EQ(9u, framer.GetFrameMinimumSize());
- EXPECT_EQ(16393u, framer.GetFrameMaximumSize());
- EXPECT_EQ(16384u, framer.GetDataFrameMaximumPayload());
-}
-
-TEST_P(SpdyFramerTest, StateToStringTest) {
- EXPECT_STREQ("ERROR", SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR));
- EXPECT_STREQ("FRAME_COMPLETE",
- SpdyFramer::StateToString(SpdyFramer::SPDY_FRAME_COMPLETE));
- EXPECT_STREQ("READY_FOR_FRAME",
- SpdyFramer::StateToString(SpdyFramer::SPDY_READY_FOR_FRAME));
- 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_SETTINGS_FRAME_PAYLOAD",
- SpdyFramer::StateToString(SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD));
- EXPECT_STREQ(
- "SPDY_ALTSVC_FRAME_PAYLOAD",
- SpdyFramer::StateToString(SpdyFramer::SPDY_ALTSVC_FRAME_PAYLOAD));
- EXPECT_STREQ("UNKNOWN_STATE", SpdyFramer::StateToString(
- SpdyFramer::SPDY_ALTSVC_FRAME_PAYLOAD + 1));
-}
-
-TEST_P(SpdyFramerTest, SpdyFramerErrorToStringTest) {
- EXPECT_STREQ("NO_ERROR",
- SpdyFramer::SpdyFramerErrorToString(SpdyFramer::SPDY_NO_ERROR));
- EXPECT_STREQ("INVALID_STREAM_ID", SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_INVALID_STREAM_ID));
- EXPECT_STREQ("INVALID_CONTROL_FRAME",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
- EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE));
- EXPECT_STREQ("ZLIB_INIT_FAILURE", SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_ZLIB_INIT_FAILURE));
- EXPECT_STREQ("UNSUPPORTED_VERSION",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_UNSUPPORTED_VERSION));
- EXPECT_STREQ("DECOMPRESS_FAILURE", SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_DECOMPRESS_FAILURE));
- EXPECT_STREQ("COMPRESS_FAILURE", SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_COMPRESS_FAILURE));
- EXPECT_STREQ("GOAWAY_FRAME_CORRUPT",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT));
- EXPECT_STREQ("RST_STREAM_FRAME_CORRUPT",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_RST_STREAM_FRAME_CORRUPT));
- EXPECT_STREQ("INVALID_PADDING", SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_INVALID_PADDING));
- EXPECT_STREQ("INVALID_DATA_FRAME_FLAGS",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS));
- EXPECT_STREQ("INVALID_CONTROL_FRAME_FLAGS",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS));
- EXPECT_STREQ("UNEXPECTED_FRAME", SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_UNEXPECTED_FRAME));
- EXPECT_STREQ("INTERNAL_FRAMER_ERROR",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_INTERNAL_FRAMER_ERROR));
- EXPECT_STREQ("INVALID_CONTROL_FRAME_SIZE",
- SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE));
- EXPECT_STREQ("OVERSIZED_PAYLOAD", SpdyFramer::SpdyFramerErrorToString(
- SpdyFramer::SPDY_OVERSIZED_PAYLOAD));
- EXPECT_STREQ("UNKNOWN_ERROR",
- SpdyFramer::SpdyFramerErrorToString(SpdyFramer::LAST_ERROR));
- EXPECT_STREQ("UNKNOWN_ERROR", SpdyFramer::SpdyFramerErrorToString(
- static_cast<SpdyFramer::SpdyFramerError>(
- SpdyFramer::LAST_ERROR + 1)));
-}
-
-TEST_P(SpdyFramerTest, DataFrameFlagsV4) {
- uint8_t valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_PADDED;
-
- uint8_t flags = 0;
- do {
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyDataIR data_ir(1, "hello");
- SpdySerializedFrame frame(framer.SerializeData(data_ir));
- SetFrameFlags(&frame, flags);
-
- if (flags & ~valid_data_flags) {
- EXPECT_CALL(visitor, OnError(_));
- } else {
- EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN));
- if (flags & DATA_FLAG_PADDED) {
- // The first byte of payload is parsed as padding length, but 'h'
- // (0x68) is too large a padding length for a 5 byte payload.
- EXPECT_CALL(visitor, OnStreamPadding(_, 1));
- // Expect Error since the frame ends prematurely.
- EXPECT_CALL(visitor, OnError(_));
- } else {
- EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5));
- if (flags & DATA_FLAG_FIN) {
- EXPECT_CALL(visitor, OnStreamEnd(_));
- }
- }
- }
-
- framer.ProcessInput(frame.data(), frame.size());
- if (flags & ~valid_data_flags) {
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS,
- framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } else if (flags & DATA_FLAG_PADDED) {
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_PADDING, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } else {
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- }
- } while (++flags != 0);
-}
-
-TEST_P(SpdyFramerTest, RstStreamFrameFlags) {
- uint8_t flags = 0;
- do {
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyRstStreamIR rst_stream(13, ERROR_CODE_CANCEL);
- SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeRstStream(rst_stream, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- SetFrameFlags(&frame, flags);
-
- EXPECT_CALL(visitor, OnRstStream(13, ERROR_CODE_CANCEL));
-
- framer.ProcessInput(frame.data(), frame.size());
-
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } while (++flags != 0);
-}
-
-TEST_P(SpdyFramerTest, SettingsFrameFlags) {
- uint8_t flags = 0;
- do {
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdySettingsIR settings_ir;
- settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 16);
- SpdySerializedFrame frame(framer.SerializeSettings(settings_ir));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- SetFrameFlags(&frame, flags);
-
- if (flags & SETTINGS_FLAG_ACK) {
- EXPECT_CALL(visitor, OnError(_));
- } else {
- EXPECT_CALL(visitor, OnSettings(flags & SETTINGS_FLAG_ACK));
- EXPECT_CALL(visitor, OnSetting(SETTINGS_INITIAL_WINDOW_SIZE, 16));
- EXPECT_CALL(visitor, OnSettingsEnd());
- }
-
- framer.ProcessInput(frame.data(), frame.size());
- if (flags & SETTINGS_FLAG_ACK) {
- // The frame is invalid because ACK frames should have no payload.
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE,
- framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } else {
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- }
- } while (++flags != 0);
-}
-
-TEST_P(SpdyFramerTest, GoawayFrameFlags) {
- uint8_t flags = 0;
- do {
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyGoAwayIR goaway_ir(97, ERROR_CODE_NO_ERROR, "test");
- SpdySerializedFrame frame(framer.SerializeGoAway(goaway_ir));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeGoAway(goaway_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- SetFrameFlags(&frame, flags);
-
- EXPECT_CALL(visitor, OnGoAway(97, ERROR_CODE_NO_ERROR));
-
- framer.ProcessInput(frame.data(), frame.size());
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } while (++flags != 0);
-}
-
-TEST_P(SpdyFramerTest, HeadersFrameFlags) {
- uint8_t flags = 0;
- do {
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyHeadersIR headers_ir(57);
- if (flags & HEADERS_FLAG_PRIORITY) {
- headers_ir.set_weight(3);
- headers_ir.set_has_priority(true);
- headers_ir.set_parent_stream_id(5);
- headers_ir.set_exclusive(true);
- }
- headers_ir.SetHeader("foo", "bar");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers_ir, use_output_ ? &output_ : nullptr));
- uint8_t set_flags = flags & ~HEADERS_FLAG_PADDED;
- SetFrameFlags(&frame, set_flags);
-
- // Expected callback values
- SpdyStreamId stream_id = 57;
- bool has_priority = false;
- SpdyPriority priority = 0;
- SpdyStreamId parent_stream_id = 0;
- bool exclusive = false;
- bool fin = flags & CONTROL_FLAG_FIN;
- bool end = flags & HEADERS_FLAG_END_HEADERS;
- if (flags & HEADERS_FLAG_PRIORITY) {
- has_priority = true;
- priority = 3;
- parent_stream_id = 5;
- exclusive = true;
- }
- EXPECT_CALL(visitor, OnHeaders(stream_id, has_priority, priority,
- parent_stream_id, exclusive, fin, end));
- EXPECT_CALL(visitor, OnHeaderFrameStart(57)).Times(1);
- if (end) {
- EXPECT_CALL(visitor, OnHeaderFrameEnd(57, _)).Times(1);
- }
- if (flags & DATA_FLAG_FIN && end) {
- EXPECT_CALL(visitor, OnStreamEnd(_));
- } else {
- // Do not close the stream if we are expecting a CONTINUATION frame.
- EXPECT_CALL(visitor, OnStreamEnd(_)).Times(0);
- }
-
- framer.ProcessInput(frame.data(), frame.size());
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } while (++flags != 0);
-}
-
-TEST_P(SpdyFramerTest, PingFrameFlags) {
- uint8_t flags = 0;
- do {
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdySerializedFrame frame(framer.SerializePing(SpdyPingIR(42)));
- SetFrameFlags(&frame, flags);
-
- EXPECT_CALL(visitor, OnPing(42, flags & PING_FLAG_ACK));
-
- framer.ProcessInput(frame.data(), frame.size());
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } while (++flags != 0);
-}
-
-TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) {
- uint8_t flags = 0;
- do {
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdySerializedFrame frame(
- framer.SerializeWindowUpdate(SpdyWindowUpdateIR(4, 1024)));
- SetFrameFlags(&frame, flags);
-
- EXPECT_CALL(visitor, OnWindowUpdate(4, 1024));
-
- framer.ProcessInput(frame.data(), frame.size());
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } while (++flags != 0);
-}
-
-TEST_P(SpdyFramerTest, PushPromiseFrameFlags) {
- const SpdyStreamId client_id = 123; // Must be odd.
- const SpdyStreamId promised_id = 22; // Must be even.
- uint8_t flags = 0;
- do {
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- testing::StrictMock<test::MockDebugVisitor> debug_visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- framer.set_debug_visitor(&debug_visitor);
-
- EXPECT_CALL(
- debug_visitor,
- OnSendCompressedFrame(client_id, SpdyFrameType::PUSH_PROMISE, _, _));
-
- SpdyPushPromiseIR push_promise(client_id, promised_id);
- push_promise.SetHeader("foo", "bar");
- SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise(
- &framer, push_promise, use_output_ ? &output_ : nullptr));
- // TODO(jgraettinger): Add padding to SpdyPushPromiseIR,
- // and implement framing.
- SetFrameFlags(&frame, flags & ~HEADERS_FLAG_PADDED);
-
- bool end = flags & PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
- EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(
- client_id, SpdyFrameType::PUSH_PROMISE, _));
- EXPECT_CALL(visitor, OnPushPromise(client_id, promised_id, end));
- EXPECT_CALL(visitor, OnHeaderFrameStart(client_id)).Times(1);
- if (end) {
- EXPECT_CALL(visitor, OnHeaderFrameEnd(client_id, _)).Times(1);
- }
-
- framer.ProcessInput(frame.data(), frame.size());
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } while (++flags != 0);
-}
-
-TEST_P(SpdyFramerTest, ContinuationFrameFlags) {
- uint8_t flags = 0;
- do {
- if (use_output_) {
- output_.Reset();
- }
- SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex
- << static_cast<int>(flags));
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- testing::StrictMock<test::MockDebugVisitor> debug_visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- framer.set_debug_visitor(&debug_visitor);
-
- EXPECT_CALL(debug_visitor,
- OnSendCompressedFrame(42, SpdyFrameType::HEADERS, _, _));
- EXPECT_CALL(debug_visitor,
- OnReceiveCompressedFrame(42, SpdyFrameType::HEADERS, _));
- EXPECT_CALL(visitor, OnHeaders(42, false, 0, 0, false, false, false));
- EXPECT_CALL(visitor, OnHeaderFrameStart(42)).Times(1);
-
- SpdyHeadersIR headers_ir(42);
- headers_ir.SetHeader("foo", "bar");
- SpdySerializedFrame frame0;
- if (use_output_) {
- EXPECT_TRUE(framer.SerializeHeaders(headers_ir, &output_));
- frame0 = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- } else {
- frame0 = framer.SerializeHeaders(headers_ir);
- }
- SetFrameFlags(&frame0, 0);
-
- SpdyContinuationIR continuation(42);
- SpdySerializedFrame frame1;
- if (use_output_) {
- char* begin = output_.Begin() + output_.Size();
- ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_));
- frame1 =
- SpdySerializedFrame(begin, output_.Size() - frame0.size(), false);
- } else {
- frame1 = framer.SerializeContinuation(continuation);
- }
- SetFrameFlags(&frame1, flags);
-
- EXPECT_CALL(debug_visitor,
- OnReceiveCompressedFrame(42, SpdyFrameType::CONTINUATION, _));
- EXPECT_CALL(visitor, OnContinuation(42, flags & HEADERS_FLAG_END_HEADERS));
- bool end = flags & HEADERS_FLAG_END_HEADERS;
- if (end) {
- EXPECT_CALL(visitor, OnHeaderFrameEnd(42, _)).Times(1);
- }
-
- framer.ProcessInput(frame0.data(), frame0.size());
- framer.ProcessInput(frame1.data(), frame1.size());
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- } while (++flags != 0);
-}
-
-// TODO(mlavan): Add TEST_F(SpdyFramerTest, AltSvcFrameFlags)
-
-// Test handling of a RST_STREAM with out-of-bounds status codes.
-TEST_P(SpdyFramerTest, RstStreamStatusBounds) {
- const unsigned char kH2RstStreamInvalid[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR
- };
- const unsigned char kH2RstStreamNumStatusCodes[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0xff, // Error: 255
- };
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- EXPECT_CALL(visitor, OnRstStream(1, ERROR_CODE_NO_ERROR));
- framer.ProcessInput(reinterpret_cast<const char*>(kH2RstStreamInvalid),
- arraysize(kH2RstStreamInvalid));
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-
- framer.Reset();
-
- EXPECT_CALL(visitor, OnRstStream(1, ERROR_CODE_INTERNAL_ERROR));
- framer.ProcessInput(reinterpret_cast<const char*>(kH2RstStreamNumStatusCodes),
- arraysize(kH2RstStreamNumStatusCodes));
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Test handling of GOAWAY frames with out-of-bounds status code.
-TEST_P(SpdyFramerTest, GoAwayStatusBounds) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x0a, // Length: 10
- 0x07, // Type: GOAWAY
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x00, 0x00, 0x01, // Last: 1
- 0xff, 0xff, 0xff, 0xff, // Error: 0xffffffff
- 0x47, 0x41, // Description
- };
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- framer.set_visitor(&visitor);
-
- EXPECT_CALL(visitor, OnGoAway(1, ERROR_CODE_INTERNAL_ERROR));
- framer.ProcessInput(reinterpret_cast<const char*>(kH2FrameData),
- arraysize(kH2FrameData));
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Tests handling of a GOAWAY frame with out-of-bounds stream ID.
-TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) {
- const unsigned char kH2FrameData[] = {
- 0x00, 0x00, 0x08, // Length: 8
- 0x07, // Type: GOAWAY
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0xff, 0xff, 0xff, 0xff, // Last: 0x7fffffff (R-bit set)
- 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR
- };
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- EXPECT_CALL(visitor, OnGoAway(0x7fffffff, ERROR_CODE_NO_ERROR));
- framer.ProcessInput(reinterpret_cast<const char*>(kH2FrameData),
- arraysize(kH2FrameData));
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-TEST_P(SpdyFramerTest, OnAltSvcWithOrigin) {
- const SpdyStreamId kStreamId = 0; // Stream id must be zero if origin given.
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyAltSvcWireFormat::AlternativeService altsvc1(
- "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector());
- SpdyAltSvcWireFormat::AlternativeService altsvc2(
- "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24});
- SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
- altsvc_vector.push_back(altsvc1);
- altsvc_vector.push_back(altsvc2);
- EXPECT_CALL(visitor,
- OnAltSvc(kStreamId, SpdyStringPiece("o_r|g!n"), altsvc_vector));
-
- SpdyAltSvcIR altsvc_ir(kStreamId);
- altsvc_ir.set_origin("o_r|g!n");
- altsvc_ir.add_altsvc(altsvc1);
- altsvc_ir.add_altsvc(altsvc2);
- SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- framer.ProcessInput(frame.data(), frame.size());
-
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-TEST_P(SpdyFramerTest, OnAltSvcNoOrigin) {
- const SpdyStreamId kStreamId = 1;
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- SpdyAltSvcWireFormat::AlternativeService altsvc1(
- "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector());
- SpdyAltSvcWireFormat::AlternativeService altsvc2(
- "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24});
- SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
- altsvc_vector.push_back(altsvc1);
- altsvc_vector.push_back(altsvc2);
- EXPECT_CALL(visitor, OnAltSvc(kStreamId, SpdyStringPiece(""), altsvc_vector));
-
- SpdyAltSvcIR altsvc_ir(kStreamId);
- altsvc_ir.add_altsvc(altsvc1);
- altsvc_ir.add_altsvc(altsvc2);
- SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir));
- framer.ProcessInput(frame.data(), frame.size());
-
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-TEST_P(SpdyFramerTest, OnAltSvcEmptyProtocolId) {
- const SpdyStreamId kStreamId = 0; // Stream id must be zero if origin given.
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
-
- EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
-
- SpdyAltSvcIR altsvc_ir(kStreamId);
- altsvc_ir.set_origin("o1");
- altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService(
- "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()));
- altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService(
- "", "h1", 443, 10, SpdyAltSvcWireFormat::VersionVector()));
- SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- framer.ProcessInput(frame.data(), frame.size());
-
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-TEST_P(SpdyFramerTest, OnAltSvcBadLengths) {
- const unsigned char kType = SerializeFrameType(SpdyFrameType::ALTSVC);
- const unsigned char kFrameDataOriginLenLargerThanFrame[] = {
- 0x00, 0x00, 0x05, kType, 0x00, 0x00, 0x00,
- 0x00, 0x03, 0x42, 0x42, 'f', 'o', 'o',
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- visitor.SimulateInFramer(kFrameDataOriginLenLargerThanFrame,
- sizeof(kFrameDataOriginLenLargerThanFrame));
-
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME,
- visitor.framer_.spdy_framer_error());
-}
-
-// Tests handling of ALTSVC frames delivered in small chunks.
-TEST_P(SpdyFramerTest, ReadChunkedAltSvcFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdyAltSvcIR altsvc_ir(1);
- SpdyAltSvcWireFormat::AlternativeService altsvc1(
- "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector());
- SpdyAltSvcWireFormat::AlternativeService altsvc2(
- "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24});
- altsvc_ir.add_altsvc(altsvc1);
- altsvc_ir.add_altsvc(altsvc2);
-
- SpdySerializedFrame control_frame(framer.SerializeAltSvc(altsvc_ir));
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
-
- // Read data in small chunks.
- size_t framed_data = 0;
- size_t unframed_data = control_frame.size();
- 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(1, visitor.altsvc_count_);
- ASSERT_EQ(2u, visitor.test_altsvc_ir_.altsvc_vector().size());
- EXPECT_TRUE(visitor.test_altsvc_ir_.altsvc_vector()[0] == altsvc1);
- EXPECT_TRUE(visitor.test_altsvc_ir_.altsvc_vector()[1] == altsvc2);
-}
-
-// While RFC7838 Section 4 says that an ALTSVC frame on stream 0 with empty
-// origin MUST be ignored, it is not implemented at the framer level: instead,
-// such frames are passed on to the consumer.
-TEST_P(SpdyFramerTest, ReadAltSvcFrame) {
- constexpr struct {
- uint32_t stream_id;
- const char* origin;
- } test_cases[] = {{0, ""},
- {1, ""},
- {0, "https://www.example.com"},
- {1, "https://www.example.com"}};
- for (const auto& test_case : test_cases) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdyAltSvcIR altsvc_ir(test_case.stream_id);
- SpdyAltSvcWireFormat::AlternativeService altsvc(
- "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector());
- altsvc_ir.add_altsvc(altsvc);
- altsvc_ir.set_origin(test_case.origin);
- SpdySerializedFrame frame(framer.SerializeAltSvc(altsvc_ir));
-
- TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- framer.ProcessInput(frame.data(), frame.size());
-
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.altsvc_count_);
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- }
-}
-
-// An ALTSVC frame with invalid Alt-Svc-Field-Value results in an error.
-TEST_P(SpdyFramerTest, ErrorOnAltSvcFrameWithInvalidValue) {
- // Alt-Svc-Field-Value must be "clear" or must contain an "=" character
- // per RFC7838 Section 3.
- const char kFrameData[] = {
- 0x00, 0x00, 0x16, // Length: 22
- 0x0a, // Type: ALTSVC
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, // Origin-Len: 0
- 0x74, 0x68, 0x69, 0x73, // thisisnotavalidvalue
- 0x69, 0x73, 0x6e, 0x6f, 0x74, 0x61, 0x76, 0x61,
- 0x6c, 0x69, 0x64, 0x76, 0x61, 0x6c, 0x75, 0x65,
- };
-
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_visitor(&visitor);
- framer.ProcessInput(kFrameData, sizeof(kFrameData));
-
- EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(0, visitor.altsvc_count_);
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
-}
-
-// Tests handling of PRIORITY frames.
-TEST_P(SpdyFramerTest, ReadPriority) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- SpdyPriorityIR priority(3, 1, 256, false);
- SpdySerializedFrame frame(framer.SerializePriority(priority));
- if (use_output_) {
- output_.Reset();
- ASSERT_TRUE(framer.SerializePriority(priority, &output_));
- frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
- }
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- framer.set_visitor(&visitor);
- EXPECT_CALL(visitor, OnPriority(3, 1, 256, false));
- framer.ProcessInput(frame.data(), frame.size());
-
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error());
- // TODO(mlavan): once we actually maintain a priority tree,
- // check that state is adjusted correctly.
-}
-
-// Tests handling of PRIORITY frame with incorrect size.
-TEST_P(SpdyFramerTest, ReadIncorrectlySizedPriority) {
- // PRIORITY frame of size 4, which isn't correct.
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x02, // Type: PRIORITY
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x03, // Stream: 3
- 0x00, 0x00, 0x00, 0x01, // Priority (Truncated)
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kFrameData, sizeof(kFrameData));
-
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
-}
-
-// Tests handling of PING frame with incorrect size.
-TEST_P(SpdyFramerTest, ReadIncorrectlySizedPing) {
- // PING frame of size 4, which isn't correct.
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x04, // Length: 4
- 0x06, // Type: PING
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x00, // Stream: 0
- 0x00, 0x00, 0x00, 0x01, // Ping (Truncated)
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kFrameData, sizeof(kFrameData));
-
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
-}
-
-// Tests handling of WINDOW_UPDATE frame with incorrect size.
-TEST_P(SpdyFramerTest, ReadIncorrectlySizedWindowUpdate) {
- // WINDOW_UPDATE frame of size 3, which isn't correct.
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x03, // Length: 3
- 0x08, // Type: WINDOW_UPDATE
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x03, // Stream: 3
- 0x00, 0x00, 0x01, // WindowUpdate (Truncated)
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kFrameData, sizeof(kFrameData));
-
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
-}
-
-// Tests handling of RST_STREAM frame with incorrect size.
-TEST_P(SpdyFramerTest, ReadIncorrectlySizedRstStream) {
- // RST_STREAM frame of size 3, which isn't correct.
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x03, // Length: 3
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x03, // Stream: 3
- 0x00, 0x00, 0x01, // RstStream (Truncated)
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kFrameData, sizeof(kFrameData));
-
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
-}
-
-// Regression test for https://crbug.com/548674:
-// RST_STREAM with payload must not be accepted.
-TEST_P(SpdyFramerTest, ReadInvalidRstStreamWithPayload) {
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x07, // Length: 7
- 0x03, // Type: RST_STREAM
- 0x00, // Flags: none
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR
- 'f', 'o', 'o' // Payload: "foo"
- };
-
- TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
- visitor.SimulateInFramer(kFrameData, sizeof(kFrameData));
-
- EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state());
- EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE,
- visitor.framer_.spdy_framer_error())
- << SpdyFramer::SpdyFramerErrorToString(
- visitor.framer_.spdy_framer_error());
-}
-
-// Test that SpdyFramer processes, by default, all passed input in one call
-// to ProcessInput (i.e. will not be calling set_process_single_input_frame()).
-TEST_P(SpdyFramerTest, ProcessAllInput) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- auto visitor =
- base::MakeUnique<TestSpdyVisitor>(SpdyFramer::DISABLE_COMPRESSION);
- framer.set_visitor(visitor.get());
-
- // Create two input frames.
- SpdyHeadersIR headers(1);
- headers.SetHeader("alpha", "beta");
- headers.SetHeader("gamma", "charlie");
- headers.SetHeader("cookie", "key1=value1; key2=value2");
- SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers, use_output_ ? &output_ : nullptr));
-
- const char four_score[] = "Four score and seven years ago";
- SpdyDataIR four_score_ir(1, four_score);
- SpdySerializedFrame four_score_frame(framer.SerializeData(four_score_ir));
-
- // Put them in a single buffer (new variables here to make it easy to
- // change the order and type of frames).
- SpdySerializedFrame frame1 = std::move(headers_frame);
- SpdySerializedFrame frame2 = std::move(four_score_frame);
-
- const size_t frame1_size = frame1.size();
- const size_t frame2_size = frame2.size();
-
- VLOG(1) << "frame1_size = " << frame1_size;
- VLOG(1) << "frame2_size = " << frame2_size;
-
- SpdyString input_buffer;
- input_buffer.append(frame1.data(), frame1_size);
- input_buffer.append(frame2.data(), frame2_size);
-
- const char* buf = input_buffer.data();
- const size_t buf_size = input_buffer.size();
-
- VLOG(1) << "buf_size = " << buf_size;
-
- size_t processed = framer.ProcessInput(buf, buf_size);
- EXPECT_EQ(buf_size, processed);
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- EXPECT_EQ(1, visitor->headers_frame_count_);
- EXPECT_EQ(1, visitor->data_frame_count_);
- EXPECT_EQ(strlen(four_score), static_cast<unsigned>(visitor->data_bytes_));
-}
-
-// Test that SpdyFramer stops after processing a full frame if
-// process_single_input_frame is set. Input to ProcessInput has two frames, but
-// only processes the first when we give it the first frame split at any point,
-// or give it more than one frame in the input buffer.
-TEST_P(SpdyFramerTest, ProcessAtMostOneFrame) {
- SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
- framer.set_process_single_input_frame(true);
-
- // Create two input frames.
- const char four_score[] = "Four score and ...";
- SpdyDataIR four_score_ir(1, four_score);
- SpdySerializedFrame four_score_frame(framer.SerializeData(four_score_ir));
-
- SpdyHeadersIR headers(2);
- headers.SetHeader("alpha", "beta");
- headers.SetHeader("gamma", "charlie");
- headers.SetHeader("cookie", "key1=value1; key2=value2");
- SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders(
- &framer, headers, use_output_ ? &output_ : nullptr));
-
- // Put them in a single buffer (new variables here to make it easy to
- // change the order and type of frames).
- SpdySerializedFrame frame1 = std::move(four_score_frame);
- SpdySerializedFrame frame2 = std::move(headers_frame);
-
- const size_t frame1_size = frame1.size();
- const size_t frame2_size = frame2.size();
-
- VLOG(1) << "frame1_size = " << frame1_size;
- VLOG(1) << "frame2_size = " << frame2_size;
-
- SpdyString input_buffer;
- input_buffer.append(frame1.data(), frame1_size);
- input_buffer.append(frame2.data(), frame2_size);
-
- const char* buf = input_buffer.data();
- const size_t buf_size = input_buffer.size();
-
- VLOG(1) << "buf_size = " << buf_size;
-
- for (size_t first_size = 0; first_size <= buf_size; ++first_size) {
- VLOG(1) << "first_size = " << first_size;
- auto visitor =
- base::MakeUnique<TestSpdyVisitor>(SpdyFramer::DISABLE_COMPRESSION);
- framer.set_visitor(visitor.get());
-
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
-
- size_t processed_first = framer.ProcessInput(buf, first_size);
- if (first_size < frame1_size) {
- EXPECT_EQ(first_size, processed_first);
-
- if (first_size == 0) {
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- } else {
- EXPECT_NE(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
- }
-
- const char* rest = buf + processed_first;
- const size_t remaining = buf_size - processed_first;
- VLOG(1) << "remaining = " << remaining;
-
- size_t processed_second = framer.ProcessInput(rest, remaining);
-
- // Redundant tests just to make it easier to think about.
- EXPECT_EQ(frame1_size - processed_first, processed_second);
- size_t processed_total = processed_first + processed_second;
- EXPECT_EQ(frame1_size, processed_total);
- } else {
- EXPECT_EQ(frame1_size, processed_first);
- }
-
- EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
-
- // At this point should have processed the entirety of the first frame,
- // and none of the second frame.
-
- EXPECT_EQ(1, visitor->data_frame_count_);
- EXPECT_EQ(strlen(four_score), static_cast<unsigned>(visitor->data_bytes_));
- EXPECT_EQ(0, visitor->headers_frame_count_);
- }
-}
-
-} // namespace test
-
-} // namespace net
« no previous file with comments | « net/spdy/spdy_framer_decoder_adapter.cc ('k') | net/spdy/spdy_header_block.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698