Remove SpdyDeframerVisitor. PiperOrigin-RevId: 342158952 Change-Id: I12145c852b8fae38a9baf53037829da3cc337a19
diff --git a/spdy/core/spdy_deframer_visitor.cc b/spdy/core/spdy_deframer_visitor.cc deleted file mode 100644 index 835fea9..0000000 --- a/spdy/core/spdy_deframer_visitor.cc +++ /dev/null
@@ -1,1031 +0,0 @@ -// Copyright 2016 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/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h" - -#include <stdlib.h> - -#include <algorithm> -#include <cstdint> -#include <limits> -#include <memory> - -#include "absl/strings/string_view.h" -#include "net/third_party/quiche/src/http2/platform/api/http2_macros.h" -#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.h" -#include "net/third_party/quiche/src/spdy/core/recording_headers_handler.h" -#include "net/third_party/quiche/src/spdy/core/spdy_frame_reader.h" -#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" -#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" -#include "net/third_party/quiche/src/spdy/platform/api/spdy_flags.h" -#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h" - -using ::testing::AssertionFailure; -using ::testing::AssertionResult; -using ::testing::AssertionSuccess; - -namespace spdy { -namespace test { - -// Specify whether to process headers as request or response in visitor-related -// params. -enum class HeaderDirection { REQUEST, RESPONSE }; - -// Types of HTTP/2 frames, per RFC 7540. -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -enum Http2FrameType { - DATA = 0, - HEADERS = 1, - PRIORITY = 2, - RST_STREAM = 3, - SETTINGS = 4, - PUSH_PROMISE = 5, - PING = 6, - GOAWAY = 7, - WINDOW_UPDATE = 8, - CONTINUATION = 9, - ALTSVC = 10, - - // Not a frame type. - UNSET = -1, - UNKNOWN = -2, -}; - -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -const char* Http2FrameTypeToString(Http2FrameType v) { - switch (v) { - case DATA: - return "DATA"; - case HEADERS: - return "HEADERS"; - case PRIORITY: - return "PRIORITY"; - case RST_STREAM: - return "RST_STREAM"; - case SETTINGS: - return "SETTINGS"; - case PUSH_PROMISE: - return "PUSH_PROMISE"; - case PING: - return "PING"; - case GOAWAY: - return "GOAWAY"; - case WINDOW_UPDATE: - return "WINDOW_UPDATE"; - case CONTINUATION: - return "CONTINUATION"; - case ALTSVC: - return "ALTSVC"; - case UNSET: - return "UNSET"; - case UNKNOWN: - return "UNKNOWN"; - default: - return "Invalid Http2FrameType"; - } -} - -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -inline std::ostream& operator<<(std::ostream& out, Http2FrameType v) { - return out << Http2FrameTypeToString(v); -} - -// Flag bits in the flag field of the common header of HTTP/2 frames -// (see https://httpwg.github.io/specs/rfc7540.html#FrameHeader for details on -// the fixed 9-octet header structure shared by all frames). -// Flag bits are only valid for specified frame types. -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -enum Http2HeaderFlag { - NO_FLAGS = 0, - - END_STREAM_FLAG = 0x1, - ACK_FLAG = 0x1, - END_HEADERS_FLAG = 0x4, - PADDED_FLAG = 0x8, - PRIORITY_FLAG = 0x20, -}; - -// Returns name of frame type. -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -const char* Http2FrameTypeToString(Http2FrameType v); - -void SpdyDeframerVisitorInterface::OnPingAck( - std::unique_ptr<SpdyPingIR> frame) { - OnPing(std::move(frame)); -} - -void SpdyDeframerVisitorInterface::OnSettingsAck( - std::unique_ptr<SpdySettingsIR> frame) { - OnSettings(std::move(frame), nullptr); -} - -class SpdyTestDeframerImpl : public SpdyTestDeframer, - public SpdyHeadersHandlerInterface { - public: - explicit SpdyTestDeframerImpl( - std::unique_ptr<SpdyDeframerVisitorInterface> listener) - : listener_(std::move(listener)) { - CHECK(listener_ != nullptr); - } - SpdyTestDeframerImpl(const SpdyTestDeframerImpl&) = delete; - SpdyTestDeframerImpl& operator=(const SpdyTestDeframerImpl&) = delete; - ~SpdyTestDeframerImpl() override = default; - - bool AtFrameEnd() override; - - // Callbacks defined in SpdyFramerVisitorInterface. These are in the - // alphabetical order for ease of navigation, and are not in same order - // as in SpdyFramerVisitorInterface. - void OnAltSvc(SpdyStreamId stream_id, - absl::string_view origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& - altsvc_vector) override; - void OnContinuation(SpdyStreamId stream_id, bool end) override; - SpdyHeadersHandlerInterface* OnHeaderFrameStart( - SpdyStreamId stream_id) override; - void OnHeaderFrameEnd(SpdyStreamId stream_id) override; - void OnDataFrameHeader(SpdyStreamId stream_id, - size_t length, - bool fin) override; - void OnError(http2::Http2DecoderAdapter::SpdyFramerError error, - std::string detailed_error) override; - void OnGoAway(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code) override; - bool OnGoAwayFrameData(const char* goaway_data, size_t len) override; - void OnHeaders(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end) override; - void OnPing(SpdyPingId unique_id, bool is_ack) override; - void OnPriority(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive) override; - void OnPushPromise(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end) override; - void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override; - void OnSetting(SpdySettingsId id, uint32_t value) override; - void OnSettings() override; - void OnSettingsAck() override; - void OnSettingsEnd() override; - void OnStreamFrameData(SpdyStreamId stream_id, - const char* data, - size_t len) override; - void OnStreamEnd(SpdyStreamId stream_id) override; - void OnStreamPadLength(SpdyStreamId stream_id, size_t value) override; - void OnStreamPadding(SpdyStreamId stream_id, size_t len) override; - bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override; - void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override; - - // Callbacks defined in SpdyHeadersHandlerInterface. - - void OnHeaderBlockStart() override; - void OnHeader(absl::string_view key, absl::string_view value) override; - void OnHeaderBlockEnd(size_t header_bytes_parsed, - size_t compressed_header_bytes_parsed) override; - - protected: - void AtDataEnd(); - void AtGoAwayEnd(); - void AtHeadersEnd(); - void AtPushPromiseEnd(); - - // Per-physical frame state. - // Frame type of the frame currently being processed. - Http2FrameType frame_type_ = UNSET; - // Stream id of the frame currently being processed. - SpdyStreamId stream_id_; - // Did the most recent frame header include the END_HEADERS flag? - bool end_ = false; - // Did the most recent frame header include the ack flag? - bool ack_ = false; - - // Per-HPACK block state. Only valid while processing a HEADERS or - // PUSH_PROMISE frame, and its CONTINUATION frames. - // Did the most recent HEADERS or PUSH_PROMISE include the END_STREAM flag? - // Note that this does not necessarily indicate that the current frame is - // the last frame for the stream (may be followed by CONTINUATION frames, - // may only half close). - bool fin_ = false; - bool got_hpack_end_ = false; - - std::unique_ptr<std::string> data_; - - // Total length of the data frame. - size_t data_len_ = 0; - - // Amount of skipped padding (i.e. total length of padding, including Pad - // Length field). - size_t padding_len_ = 0; - - std::unique_ptr<std::string> goaway_description_; - std::unique_ptr<StringPairVector> headers_; - std::unique_ptr<SettingVector> settings_; - std::unique_ptr<RecordingHeadersHandler> headers_handler_; - - std::unique_ptr<SpdyGoAwayIR> goaway_ir_; - std::unique_ptr<SpdyHeadersIR> headers_ir_; - std::unique_ptr<SpdyPushPromiseIR> push_promise_ir_; - std::unique_ptr<SpdySettingsIR> settings_ir_; - - private: - std::unique_ptr<SpdyDeframerVisitorInterface> listener_; -}; - -// static -std::unique_ptr<SpdyTestDeframer> SpdyTestDeframer::CreateConverter( - std::unique_ptr<SpdyDeframerVisitorInterface> listener) { - return std::make_unique<SpdyTestDeframerImpl>(std::move(listener)); -} - -void SpdyTestDeframerImpl::AtDataEnd() { - SPDY_DVLOG(1) << "AtDataEnd"; - CHECK_EQ(data_len_, padding_len_ + data_->size()); - auto ptr = std::make_unique<SpdyDataIR>(stream_id_, std::move(*data_)); - CHECK_EQ(0u, data_->size()); - data_.reset(); - - CHECK_LE(0u, padding_len_); - CHECK_LE(padding_len_, 256u); - if (padding_len_ > 0) { - ptr->set_padding_len(padding_len_); - } - padding_len_ = 0; - - ptr->set_fin(fin_); - listener_->OnData(std::move(ptr)); - frame_type_ = UNSET; - fin_ = false; - data_len_ = 0; -} - -void SpdyTestDeframerImpl::AtGoAwayEnd() { - SPDY_DVLOG(1) << "AtDataEnd"; - CHECK_EQ(frame_type_, GOAWAY); - if (HTTP2_DIE_IF_NULL(goaway_description_)->empty()) { - listener_->OnGoAway(std::move(goaway_ir_)); - } else { - listener_->OnGoAway(std::make_unique<SpdyGoAwayIR>( - goaway_ir_->last_good_stream_id(), goaway_ir_->error_code(), - std::move(*goaway_description_))); - CHECK_EQ(0u, goaway_description_->size()); - } - goaway_description_.reset(); - goaway_ir_.reset(); - frame_type_ = UNSET; -} - -void SpdyTestDeframerImpl::AtHeadersEnd() { - SPDY_DVLOG(1) << "AtDataEnd"; - CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(end_) << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(got_hpack_end_); - - CHECK(headers_ir_ != nullptr); - CHECK(headers_ != nullptr); - CHECK(headers_handler_ != nullptr); - - CHECK_LE(0u, padding_len_); - CHECK_LE(padding_len_, 256u); - if (padding_len_ > 0) { - headers_ir_->set_padding_len(padding_len_); - } - padding_len_ = 0; - - headers_ir_->set_header_block(headers_handler_->decoded_block().Clone()); - headers_handler_.reset(); - listener_->OnHeaders(std::move(headers_ir_), std::move(headers_)); - - frame_type_ = UNSET; - fin_ = false; - end_ = false; - got_hpack_end_ = false; -} - -void SpdyTestDeframerImpl::AtPushPromiseEnd() { - SPDY_DVLOG(1) << "AtDataEnd"; - CHECK(frame_type_ == PUSH_PROMISE || frame_type_ == CONTINUATION) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(end_) << " frame_type_=" << Http2FrameTypeToString(frame_type_); - - CHECK(push_promise_ir_ != nullptr); - CHECK(headers_ != nullptr); - CHECK(headers_handler_ != nullptr); - - CHECK_EQ(headers_ir_.get(), nullptr); - - CHECK_LE(0u, padding_len_); - CHECK_LE(padding_len_, 256u); - if (padding_len_ > 0) { - push_promise_ir_->set_padding_len(padding_len_); - } - padding_len_ = 0; - - push_promise_ir_->set_header_block(headers_handler_->decoded_block().Clone()); - headers_handler_.reset(); - listener_->OnPushPromise(std::move(push_promise_ir_), std::move(headers_)); - - frame_type_ = UNSET; - end_ = false; -} - -bool SpdyTestDeframerImpl::AtFrameEnd() { - bool incomplete_logical_header = false; - // The caller says that the SpdyFrame has reached the end of the frame, - // so if we have any accumulated data, flush it. - switch (frame_type_) { - case DATA: - AtDataEnd(); - break; - - case GOAWAY: - AtGoAwayEnd(); - break; - - case HEADERS: - if (end_) { - AtHeadersEnd(); - } else { - incomplete_logical_header = true; - } - break; - - case PUSH_PROMISE: - if (end_) { - AtPushPromiseEnd(); - } else { - incomplete_logical_header = true; - } - break; - - case CONTINUATION: - if (end_) { - if (headers_ir_) { - AtHeadersEnd(); - } else if (push_promise_ir_) { - AtPushPromiseEnd(); - } else { - SPDY_LOG(FATAL) << "Where is the SpdyFrameIR for the headers!"; - } - } else { - incomplete_logical_header = true; - } - break; - - case UNSET: - // Except for the frame types above, the others don't leave any record - // in the state of this object. Make sure nothing got left by accident. - CHECK_EQ(data_.get(), nullptr); - CHECK_EQ(goaway_description_.get(), nullptr); - CHECK_EQ(goaway_ir_.get(), nullptr); - CHECK_EQ(headers_.get(), nullptr); - CHECK_EQ(headers_handler_.get(), nullptr); - CHECK_EQ(headers_ir_.get(), nullptr); - CHECK_EQ(push_promise_ir_.get(), nullptr); - CHECK_EQ(settings_.get(), nullptr); - CHECK_EQ(settings_ir_.get(), nullptr); - break; - - default: - SPDY_BUG << "Expected UNSET, instead frame_type_==" << frame_type_; - return false; - } - frame_type_ = UNSET; - stream_id_ = 0; - end_ = false; - ack_ = false; - if (!incomplete_logical_header) { - fin_ = false; - } - return true; -} - -// Overridden methods from SpdyFramerVisitorInterface in alpha order... - -void SpdyTestDeframerImpl::OnAltSvc( - SpdyStreamId stream_id, - absl::string_view origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) { - SPDY_DVLOG(1) << "OnAltSvc stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - auto ptr = std::make_unique<SpdyAltSvcIR>(stream_id); - ptr->set_origin(std::string(origin)); - for (auto& altsvc : altsvc_vector) { - ptr->add_altsvc(altsvc); - } - listener_->OnAltSvc(std::move(ptr)); -} - -// A CONTINUATION frame contains a Header Block Fragment, and immediately -// follows another frame that contains a Header Block Fragment (HEADERS, -// PUSH_PROMISE or CONTINUATION). The last such frame has the END flag set. -// SpdyFramer ensures that the behavior is correct before calling the visitor. -void SpdyTestDeframerImpl::OnContinuation(SpdyStreamId stream_id, bool end) { - SPDY_DVLOG(1) << "OnContinuation stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - CHECK_NE(nullptr, headers_.get()); - frame_type_ = CONTINUATION; - - stream_id_ = stream_id; - end_ = end; -} - -// Note that length includes the padding length (0 to 256, when the optional -// padding length field is counted). Padding comes after the payload, both -// for DATA frames and for control frames. -void SpdyTestDeframerImpl::OnDataFrameHeader(SpdyStreamId stream_id, - size_t length, - bool fin) { - SPDY_DVLOG(1) << "OnDataFrameHeader stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - CHECK_EQ(data_.get(), nullptr); - frame_type_ = DATA; - - stream_id_ = stream_id; - fin_ = fin; - data_len_ = length; - data_ = std::make_unique<std::string>(); -} - -// The SpdyFramer will not process any more data at this point. -void SpdyTestDeframerImpl::OnError( - http2::Http2DecoderAdapter::SpdyFramerError error, - std::string /*detailed_error*/) { - SPDY_DVLOG(1) << "SpdyFramer detected an error in the stream: " - << http2::Http2DecoderAdapter::SpdyFramerErrorToString(error) - << " frame_type_: " << Http2FrameTypeToString(frame_type_); - listener_->OnError(error, this); -} - -// Received a GOAWAY frame from the peer. The last stream id it accepted from us -// is |last_accepted_stream_id|. |status| is a protocol defined error code. -// The frame may also contain data. After this OnGoAwayFrameData will be called -// for any non-zero amount of data, and after that it will be called with len==0 -// to indicate the end of the GOAWAY frame. -void SpdyTestDeframerImpl::OnGoAway(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code) { - SPDY_DVLOG(1) << "OnGoAway last_accepted_stream_id: " - << last_accepted_stream_id << " error code: " << error_code; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - frame_type_ = GOAWAY; - goaway_ir_ = - std::make_unique<SpdyGoAwayIR>(last_accepted_stream_id, error_code, ""); - goaway_description_ = std::make_unique<std::string>(); -} - -// If len==0 then we've reached the end of the GOAWAY frame. -bool SpdyTestDeframerImpl::OnGoAwayFrameData(const char* goaway_data, - size_t len) { - SPDY_DVLOG(1) << "OnGoAwayFrameData"; - CHECK_EQ(frame_type_, GOAWAY) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(goaway_description_ != nullptr); - goaway_description_->append(goaway_data, len); - return true; -} - -SpdyHeadersHandlerInterface* SpdyTestDeframerImpl::OnHeaderFrameStart( - SpdyStreamId /*stream_id*/) { - return this; -} - -void SpdyTestDeframerImpl::OnHeaderFrameEnd(SpdyStreamId stream_id) { - SPDY_DVLOG(1) << "OnHeaderFrameEnd stream_id: " << stream_id; -} - -// Received the fixed portion of a HEADERS frame. Called before the variable -// length (including zero length) Header Block Fragment is processed. If fin -// is true then there will be no DATA or trailing HEADERS after this HEADERS -// frame. -// If end is true, then there will be no CONTINUATION frame(s) following this -// frame; else if true then there will be CONTINATION frames(s) immediately -// following this frame, terminated by a CONTINUATION frame with end==true. -void SpdyTestDeframerImpl::OnHeaders(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end) { - SPDY_DVLOG(1) << "OnHeaders stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - frame_type_ = HEADERS; - - stream_id_ = stream_id; - fin_ = fin; - end_ = end; - - headers_ = std::make_unique<StringPairVector>(); - headers_handler_ = std::make_unique<RecordingHeadersHandler>(); - headers_ir_ = std::make_unique<SpdyHeadersIR>(stream_id); - headers_ir_->set_fin(fin); - if (has_priority) { - headers_ir_->set_has_priority(true); - headers_ir_->set_weight(weight); - headers_ir_->set_parent_stream_id(parent_stream_id); - headers_ir_->set_exclusive(exclusive); - } -} - -// The HTTP/2 protocol refers to the payload, |unique_id| here, as 8 octets of -// opaque data that is to be echoed back to the sender, with the ACK bit added. -// It isn't defined as a counter, -// or frame id, as the SpdyPingId naming might imply. -// Responding to a PING is supposed to be at the highest priority. -void SpdyTestDeframerImpl::OnPing(uint64_t unique_id, bool is_ack) { - SPDY_DVLOG(1) << "OnPing unique_id: " << unique_id - << " is_ack: " << (is_ack ? "true" : "false"); - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - auto ptr = std::make_unique<SpdyPingIR>(unique_id); - if (is_ack) { - ptr->set_is_ack(is_ack); - listener_->OnPingAck(std::move(ptr)); - } else { - listener_->OnPing(std::move(ptr)); - } -} - -void SpdyTestDeframerImpl::OnPriority(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive) { - SPDY_DVLOG(1) << "OnPriority stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - - listener_->OnPriority(std::make_unique<SpdyPriorityIR>( - stream_id, parent_stream_id, weight, exclusive)); -} - -void SpdyTestDeframerImpl::OnPushPromise(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end) { - SPDY_DVLOG(1) << "OnPushPromise stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - - frame_type_ = PUSH_PROMISE; - stream_id_ = stream_id; - end_ = end; - - headers_ = std::make_unique<StringPairVector>(); - headers_handler_ = std::make_unique<RecordingHeadersHandler>(); - push_promise_ir_ = - std::make_unique<SpdyPushPromiseIR>(stream_id, promised_stream_id); -} - -// Closes the specified stream. After this the sender may still send PRIORITY -// frames for this stream, which we can ignore. -void SpdyTestDeframerImpl::OnRstStream(SpdyStreamId stream_id, - SpdyErrorCode error_code) { - SPDY_DVLOG(1) << "OnRstStream stream_id: " << stream_id - << " error code: " << error_code; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - - listener_->OnRstStream( - std::make_unique<SpdyRstStreamIR>(stream_id, error_code)); -} - -// Called for an individual setting. There is no negotiation; the sender is -// stating the value that the sender is using. -void SpdyTestDeframerImpl::OnSetting(SpdySettingsId id, uint32_t value) { - SPDY_DVLOG(1) << "OnSetting id: " << id << std::hex << " value: " << value; - CHECK_EQ(frame_type_, SETTINGS) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(settings_ != nullptr); - SpdyKnownSettingsId known_id; - if (ParseSettingsId(id, &known_id)) { - settings_->push_back(std::make_pair(known_id, value)); - settings_ir_->AddSetting(known_id, value); - } -} - -// Called at the start of a SETTINGS frame with setting entries, but not the -// (required) ACK of a SETTINGS frame. There is no stream_id because -// the settings apply to the entire connection, not to an individual stream. -void SpdyTestDeframerImpl::OnSettings() { - SPDY_DVLOG(1) << "OnSettings"; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_EQ(nullptr, settings_ir_.get()); - CHECK_EQ(nullptr, settings_.get()); - frame_type_ = SETTINGS; - ack_ = false; - - settings_ = std::make_unique<SettingVector>(); - settings_ir_ = std::make_unique<SpdySettingsIR>(); -} - -void SpdyTestDeframerImpl::OnSettingsAck() { - SPDY_DVLOG(1) << "OnSettingsAck"; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - auto ptr = std::make_unique<SpdySettingsIR>(); - ptr->set_is_ack(true); - listener_->OnSettingsAck(std::move(ptr)); -} - -void SpdyTestDeframerImpl::OnSettingsEnd() { - SPDY_DVLOG(1) << "OnSettingsEnd"; - CHECK_EQ(frame_type_, SETTINGS) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(!ack_); - CHECK_NE(nullptr, settings_ir_.get()); - CHECK_NE(nullptr, settings_.get()); - listener_->OnSettings(std::move(settings_ir_), std::move(settings_)); - frame_type_ = UNSET; -} - -// Called for a zero length DATA frame with the END_STREAM flag set, or at the -// end a complete HPACK block (and its padding) that started with a HEADERS -// frame with the END_STREAM flag set. Doesn't apply to PUSH_PROMISE frames -// because they don't have END_STREAM flags. -void SpdyTestDeframerImpl::OnStreamEnd(SpdyStreamId stream_id) { - SPDY_DVLOG(1) << "OnStreamEnd stream_id: " << stream_id; - CHECK_EQ(stream_id_, stream_id); - CHECK(frame_type_ == DATA || frame_type_ == HEADERS || - frame_type_ == CONTINUATION) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(fin_); -} - -// The data arg points into the non-padding payload of a DATA frame. -// This must be a DATA frame (i.e. this method will not be -// called for HEADERS or CONTINUATION frames). -// This method may be called multiple times for a single DATA frame, depending -// upon buffer boundaries. -void SpdyTestDeframerImpl::OnStreamFrameData(SpdyStreamId stream_id, - const char* data, - size_t len) { - SPDY_DVLOG(1) << "OnStreamFrameData stream_id: " << stream_id - << " len: " << len; - CHECK_EQ(stream_id_, stream_id); - CHECK_EQ(frame_type_, DATA); - data_->append(data, len); -} - -// Called when receiving the padding length field at the start of the DATA frame -// payload. value will be in the range 0 to 255. -void SpdyTestDeframerImpl::OnStreamPadLength(SpdyStreamId stream_id, - size_t value) { - SPDY_DVLOG(1) << "OnStreamPadding stream_id: " << stream_id - << " value: " << value; - CHECK(frame_type_ == DATA || frame_type_ == HEADERS || - frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_EQ(stream_id_, stream_id); - CHECK_GE(255u, value); - // Count the padding length byte against total padding. - padding_len_ += 1; - CHECK_EQ(1u, padding_len_); -} - -// Called when padding is skipped over at the end of the DATA frame. len will -// be in the range 1 to 255. -void SpdyTestDeframerImpl::OnStreamPadding(SpdyStreamId stream_id, size_t len) { - SPDY_DVLOG(1) << "OnStreamPadding stream_id: " << stream_id - << " len: " << len; - CHECK(frame_type_ == DATA || frame_type_ == HEADERS || - frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_EQ(stream_id_, stream_id); - CHECK_LE(1u, len); - CHECK_GE(255u, len); - padding_len_ += len; - CHECK_LE(padding_len_, 256u) << "len=" << len; -} - -// WINDOW_UPDATE is supposed to be hop-by-hop, according to the spec. -// stream_id is 0 if the update applies to the connection, else stream_id -// will be the id of a stream previously seen, which maybe half or fully -// closed. -void SpdyTestDeframerImpl::OnWindowUpdate(SpdyStreamId stream_id, - int delta_window_size) { - SPDY_DVLOG(1) << "OnWindowUpdate stream_id: " << stream_id - << " delta_window_size: " << delta_window_size; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_NE(0, delta_window_size); - - listener_->OnWindowUpdate( - std::make_unique<SpdyWindowUpdateIR>(stream_id, delta_window_size)); -} - -// Return true to indicate that the stream_id is valid; if not valid then -// SpdyFramer considers the connection corrupted. Requires keeping track -// of the set of currently open streams. For now we'll assume that unknown -// frame types are unsupported. -bool SpdyTestDeframerImpl::OnUnknownFrame(SpdyStreamId stream_id, - uint8_t /*frame_type*/) { - SPDY_DVLOG(1) << "OnAltSvc stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - frame_type_ = UNKNOWN; - - stream_id_ = stream_id; - return false; -} - -// Callbacks defined in SpdyHeadersHandlerInterface. - -void SpdyTestDeframerImpl::OnHeaderBlockStart() { - CHECK(frame_type_ == HEADERS || frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(headers_ != nullptr); - CHECK_EQ(0u, headers_->size()); - got_hpack_end_ = false; -} - -void SpdyTestDeframerImpl::OnHeader(absl::string_view key, - absl::string_view value) { - CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION || - frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(!got_hpack_end_); - HTTP2_DIE_IF_NULL(headers_)->emplace_back(std::string(key), - std::string(value)); - HTTP2_DIE_IF_NULL(headers_handler_)->OnHeader(key, value); -} - -void SpdyTestDeframerImpl::OnHeaderBlockEnd( - size_t /* header_bytes_parsed */, - size_t /* compressed_header_bytes_parsed */) { - CHECK(headers_ != nullptr); - CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION || - frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(end_); - CHECK(!got_hpack_end_); - got_hpack_end_ = true; -} - -class LoggingSpdyDeframerDelegate : public SpdyDeframerVisitorInterface { - public: - explicit LoggingSpdyDeframerDelegate( - std::unique_ptr<SpdyDeframerVisitorInterface> wrapped) - : wrapped_(std::move(wrapped)) { - if (!wrapped_) { - wrapped_ = std::make_unique<SpdyDeframerVisitorInterface>(); - } - } - ~LoggingSpdyDeframerDelegate() override = default; - - void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnAltSvc"; - wrapped_->OnAltSvc(std::move(frame)); - } - void OnData(std::unique_ptr<SpdyDataIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnData"; - wrapped_->OnData(std::move(frame)); - } - void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnGoAway"; - wrapped_->OnGoAway(std::move(frame)); - } - - // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which - // significantly modifies the headers, so the actual header entries (name - // and value strings) are provided in a vector. - void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame, - std::unique_ptr<StringPairVector> headers) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnHeaders"; - wrapped_->OnHeaders(std::move(frame), std::move(headers)); - } - - void OnPing(std::unique_ptr<SpdyPingIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPing"; - wrapped_->OnPing(std::move(frame)); - } - void OnPingAck(std::unique_ptr<SpdyPingIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPingAck"; - wrapped_->OnPingAck(std::move(frame)); - } - - void OnPriority(std::unique_ptr<SpdyPriorityIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPriority"; - wrapped_->OnPriority(std::move(frame)); - } - - // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which - // significantly modifies the headers, so the actual header entries (name - // and value strings) are provided in a vector. - void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame, - std::unique_ptr<StringPairVector> headers) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPushPromise"; - wrapped_->OnPushPromise(std::move(frame), std::move(headers)); - } - - void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnRstStream"; - wrapped_->OnRstStream(std::move(frame)); - } - - // SpdySettingsIR has a map for settings, so loses info about the order of - // settings, and whether the same setting appeared more than once, so the - // the actual settings (parameter and value) are provided in a vector. - void OnSettings(std::unique_ptr<SpdySettingsIR> frame, - std::unique_ptr<SettingVector> settings) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnSettings"; - wrapped_->OnSettings(std::move(frame), std::move(settings)); - } - - // A settings frame with an ACK has no content, but for uniformity passing - // a frame with the ACK flag set. - void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnSettingsAck"; - wrapped_->OnSettingsAck(std::move(frame)); - } - - void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnWindowUpdate"; - wrapped_->OnWindowUpdate(std::move(frame)); - } - - // The SpdyFramer will not process any more data at this point. - void OnError(http2::Http2DecoderAdapter::SpdyFramerError error, - SpdyTestDeframer* deframer) override { - SPDY_DVLOG(1) << "LoggingSpdyDeframerDelegate::OnError"; - wrapped_->OnError(error, deframer); - } - - private: - std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_; -}; - -// static -std::unique_ptr<SpdyDeframerVisitorInterface> -SpdyDeframerVisitorInterface::LogBeforeVisiting( - std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_listener) { - return std::make_unique<LoggingSpdyDeframerDelegate>( - std::move(wrapped_listener)); -} - -CollectedFrame::CollectedFrame() = default; - -CollectedFrame::CollectedFrame(CollectedFrame&& other) - : frame_ir(std::move(other.frame_ir)), - headers(std::move(other.headers)), - settings(std::move(other.settings)), - error_reported(other.error_reported) {} - -CollectedFrame::~CollectedFrame() = default; - -CollectedFrame& CollectedFrame::operator=(CollectedFrame&& other) { - frame_ir = std::move(other.frame_ir); - headers = std::move(other.headers); - settings = std::move(other.settings); - error_reported = other.error_reported; - return *this; -} - -AssertionResult CollectedFrame::VerifyHasHeaders( - const StringPairVector& expected_headers) const { - VERIFY_NE(headers.get(), nullptr); - VERIFY_THAT(*headers, ::testing::ContainerEq(expected_headers)); - return AssertionSuccess(); -} - -AssertionResult CollectedFrame::VerifyHasSettings( - const SettingVector& expected_settings) const { - VERIFY_NE(settings.get(), nullptr); - VERIFY_THAT(*settings, testing::ContainerEq(expected_settings)); - return AssertionSuccess(); -} - -DeframerCallbackCollector::DeframerCallbackCollector( - std::vector<CollectedFrame>* collected_frames) - : collected_frames_(HTTP2_DIE_IF_NULL(collected_frames)) {} - -void DeframerCallbackCollector::OnAltSvc( - std::unique_ptr<SpdyAltSvcIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} -void DeframerCallbackCollector::OnData(std::unique_ptr<SpdyDataIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} -void DeframerCallbackCollector::OnGoAway( - std::unique_ptr<SpdyGoAwayIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -// SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which -// significantly modifies the headers, so the actual header entries (name -// and value strings) are provided in a vector. -void DeframerCallbackCollector::OnHeaders( - std::unique_ptr<SpdyHeadersIR> frame_ir, - std::unique_ptr<StringPairVector> headers) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - cf.headers = std::move(headers); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnPing(std::unique_ptr<SpdyPingIR> frame_ir) { - EXPECT_TRUE(frame_ir && !frame_ir->is_ack()); - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnPingAck( - std::unique_ptr<SpdyPingIR> frame_ir) { - EXPECT_TRUE(frame_ir && frame_ir->is_ack()); - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnPriority( - std::unique_ptr<SpdyPriorityIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -// SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which -// significantly modifies the headers, so the actual header entries (name -// and value strings) are provided in a vector. -void DeframerCallbackCollector::OnPushPromise( - std::unique_ptr<SpdyPushPromiseIR> frame_ir, - std::unique_ptr<StringPairVector> headers) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - cf.headers = std::move(headers); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnRstStream( - std::unique_ptr<SpdyRstStreamIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -// SpdySettingsIR has a map for settings, so loses info about the order of -// settings, and whether the same setting appeared more than once, so the -// the actual settings (parameter and value) are provided in a vector. -void DeframerCallbackCollector::OnSettings( - std::unique_ptr<SpdySettingsIR> frame_ir, - std::unique_ptr<SettingVector> settings) { - EXPECT_TRUE(frame_ir && !frame_ir->is_ack()); - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - cf.settings = std::move(settings); - collected_frames_->push_back(std::move(cf)); -} - -// A settings frame_ir with an ACK has no content, but for uniformity passing -// a frame_ir with the ACK flag set. -void DeframerCallbackCollector::OnSettingsAck( - std::unique_ptr<SpdySettingsIR> frame_ir) { - EXPECT_TRUE(frame_ir && frame_ir->is_ack()); - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnWindowUpdate( - std::unique_ptr<SpdyWindowUpdateIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -// The SpdyFramer will not process any more data at this point. -void DeframerCallbackCollector::OnError( - http2::Http2DecoderAdapter::SpdyFramerError /*error*/, - SpdyTestDeframer* /*deframer*/) { - CollectedFrame cf; - cf.error_reported = true; - collected_frames_->push_back(std::move(cf)); -} - -} // namespace test -} // namespace spdy
diff --git a/spdy/core/spdy_deframer_visitor.h b/spdy/core/spdy_deframer_visitor.h deleted file mode 100644 index f17df98..0000000 --- a/spdy/core/spdy_deframer_visitor.h +++ /dev/null
@@ -1,247 +0,0 @@ -// Copyright 2016 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. - -#ifndef QUICHE_SPDY_CORE_SPDY_DEFRAMER_VISITOR_H_ -#define QUICHE_SPDY_CORE_SPDY_DEFRAMER_VISITOR_H_ - -// Supports testing by converting callbacks to SpdyFramerVisitorInterface into -// callbacks to SpdyDeframerVisitorInterface, whose arguments are generally -// SpdyFrameIR instances. This enables a test client or test backend to operate -// at a level between the low-level callbacks of SpdyFramerVisitorInterface and -// the much higher level of entire messages (i.e. headers, body, trailers). -// Where possible the converter (SpdyTestDeframer) tries to preserve information -// that might be useful to tests (e.g. the order of headers or the amount of -// padding); the design also aims to allow tests to be concise, ideally -// supporting gMock style EXPECT_CALL(visitor, OnHeaders(...matchers...)) -// without too much boilerplate. -// -// Only supports HTTP/2 for the moment. -// -// Example of usage: -// -// SpdyFramer framer(HTTP2); -// -// // Need to call SpdyTestDeframer::AtFrameEnd() after processing each -// // frame, so tell SpdyFramer to stop after each. -// framer.set_process_single_input_frame(true); -// -// // Need the new OnHeader callbacks. -// framer.set_use_new_methods_for_test(true); -// -// // Create your visitor, a subclass of SpdyDeframerVisitorInterface. -// // For example, using DeframerCallbackCollector to collect frames: -// std::vector<CollectedFrame> collected_frames; -// auto your_visitor = std::make_unique<DeframerCallbackCollector>( -// &collected_frames); -// -// // Transfer ownership of your visitor to the converter, which ensures that -// // your visitor stays alive while the converter needs to call it. -// auto the_deframer = SpdyTestDeframer::CreateConverter( -// std::move(your_visitor)); -// -// // Tell the framer to notify SpdyTestDeframer of the decoded frame -// // details. -// framer.set_visitor(the_deframer.get()); -// -// // Process frames. -// absl::string_view input = ... -// while (!input.empty() && !framer.HasError()) { -// size_t consumed = framer.ProcessInput(input.data(), input.size()); -// input.remove_prefix(consumed); -// if (framer.state() == SpdyFramer::SPDY_READY_FOR_FRAME) { -// the_deframer->AtFrameEnd(); -// } -// } -// -// // Make sure that the correct frames were received. For example: -// ASSERT_EQ(collected_frames.size(), 3); -// -// SpdyDataIR expected1(7 /*stream_id*/, "Data Payload"); -// expected1.set_padding_len(17); -// EXPECT_TRUE(collected_frames[0].VerifyEquals(expected1)); -// -// // Repeat for the other frames. -// -// Note that you could also seed the subclass of SpdyDeframerVisitorInterface -// with the expected frames, which it would pop-off the list as its expectations -// are met. - -#include <cstdint> -#include <memory> -#include <string> -#include <type_traits> -#include <utility> -#include <vector> - -#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" -#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" -#include "net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h" -#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" -#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h" - -namespace spdy { -namespace test { - -// Non-lossy representation of a SETTINGS frame payload. -typedef std::vector<std::pair<SpdyKnownSettingsId, uint32_t>> SettingVector; - -// StringPairVector is used to record information lost by SpdyHeaderBlock, in -// particular the order of each header entry, though it doesn't expose the -// inner details of the HPACK block, such as the type of encoding selected -// for each header entry, nor dynamic table size changes. -typedef std::pair<std::string, std::string> StringPair; -typedef std::vector<StringPair> StringPairVector; - -// Forward decl. -class SpdyTestDeframer; - -// Note that this only roughly captures the frames, as padding bytes are lost, -// continuation frames are combined with their leading HEADERS or PUSH_PROMISE, -// the details of the HPACK encoding are lost, leaving -// only the list of header entries (name and value strings). If really helpful, -// we could add a SpdyRawDeframerVisitorInterface that gets the HPACK bytes, -// and receives continuation frames. For more info we'd need to improve -// SpdyFramerVisitorInterface. -class SpdyDeframerVisitorInterface { - public: - virtual ~SpdyDeframerVisitorInterface() {} - - // Wrap a visitor in another SpdyDeframerVisitorInterface that will - // DVLOG each call, and will then forward the calls to the wrapped visitor - // (if provided; nullptr is OK). Takes ownership of the wrapped visitor. - static std::unique_ptr<SpdyDeframerVisitorInterface> LogBeforeVisiting( - std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_visitor); - - virtual void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> /*frame*/) {} - virtual void OnData(std::unique_ptr<SpdyDataIR> /*frame*/) {} - virtual void OnGoAway(std::unique_ptr<SpdyGoAwayIR> /*frame*/) {} - - // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which - // significantly modifies the headers, so the actual header entries (name - // and value strings) are provided in a vector. - virtual void OnHeaders(std::unique_ptr<SpdyHeadersIR> /*frame*/, - std::unique_ptr<StringPairVector> /*headers*/) {} - - virtual void OnPing(std::unique_ptr<SpdyPingIR> /*frame*/) {} - virtual void OnPingAck(std::unique_ptr<SpdyPingIR> /*frame*/); - virtual void OnPriority(std::unique_ptr<SpdyPriorityIR> /*frame*/) {} - - // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which - // significantly modifies the headers, so the actual header entries (name - // and value strings) are provided in a vector. - virtual void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> /*frame*/, - std::unique_ptr<StringPairVector> /*headers*/) {} - - virtual void OnRstStream(std::unique_ptr<SpdyRstStreamIR> /*frame*/) {} - - // SpdySettingsIR has a map for settings, so loses info about the order of - // settings, and whether the same setting appeared more than once, so the - // the actual settings (parameter and value) are provided in a vector. - virtual void OnSettings(std::unique_ptr<SpdySettingsIR> /*frame*/, - std::unique_ptr<SettingVector> /*settings*/) {} - - // A settings frame with an ACK has no content, but for uniformity passing - // a frame with the ACK flag set. - virtual void OnSettingsAck(std::unique_ptr<SpdySettingsIR> /*frame*/); - - virtual void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> /*frame*/) {} - - // The SpdyFramer will not process any more data at this point. - virtual void OnError(http2::Http2DecoderAdapter::SpdyFramerError /*error*/, - SpdyTestDeframer* /*deframer*/) {} -}; - -class SpdyTestDeframer : public SpdyFramerVisitorInterface { - public: - ~SpdyTestDeframer() override {} - - // Creates a SpdyFramerVisitorInterface that builds SpdyFrameIR concrete - // instances based on the callbacks it receives; when an entire frame is - // decoded/reconstructed it calls the passed in SpdyDeframerVisitorInterface. - // Transfers ownership of visitor to the new SpdyTestDeframer, which ensures - // that it continues to exist while the SpdyTestDeframer exists. - static std::unique_ptr<SpdyTestDeframer> CreateConverter( - std::unique_ptr<SpdyDeframerVisitorInterface> visitor); - - // Call to notify the deframer that the SpdyFramer has returned after reaching - // the end of decoding a frame. This is used to flush info about some frame - // types where we don't get a clear end signal; others are flushed (i.e. the - // appropriate call to the SpdyDeframerVisitorInterface method is invoked) - // as they're decoded by SpdyFramer and it calls the deframer. See the - // example in the comments at the top of this file. - virtual bool AtFrameEnd() = 0; - - protected: - SpdyTestDeframer() {} - SpdyTestDeframer(const SpdyTestDeframer&) = delete; - SpdyTestDeframer& operator=(const SpdyTestDeframer&) = delete; -}; - -// CollectedFrame holds the result of one call to SpdyDeframerVisitorInterface, -// as recorded by DeframerCallbackCollector. -struct CollectedFrame { - CollectedFrame(); - CollectedFrame(CollectedFrame&& other); - ~CollectedFrame(); - CollectedFrame& operator=(CollectedFrame&& other); - - // Compare a SpdyFrameIR sub-class instance, expected_ir, against the - // collected SpdyFrameIR. - template <class T, - typename X = - typename std::enable_if<std::is_base_of<SpdyFrameIR, T>::value>> - ::testing::AssertionResult VerifyHasFrame(const T& expected_ir) const { - return VerifySpdyFrameIREquals(expected_ir, frame_ir.get()); - } - - // Compare the collected headers against a StringPairVector. Ignores - // this->frame_ir. - ::testing::AssertionResult VerifyHasHeaders( - const StringPairVector& expected_headers) const; - - // Compare the collected settings (parameter and value pairs) against - // expected_settings. Ignores this->frame_ir. - ::testing::AssertionResult VerifyHasSettings( - const SettingVector& expected_settings) const; - - std::unique_ptr<SpdyFrameIR> frame_ir; - std::unique_ptr<StringPairVector> headers; - std::unique_ptr<SettingVector> settings; - bool error_reported = false; -}; - -// Creates a CollectedFrame instance for each callback, storing it in the -// vector provided to the constructor. -class DeframerCallbackCollector : public SpdyDeframerVisitorInterface { - public: - explicit DeframerCallbackCollector( - std::vector<CollectedFrame>* collected_frames); - ~DeframerCallbackCollector() override {} - - void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame_ir) override; - void OnData(std::unique_ptr<SpdyDataIR> frame_ir) override; - void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame_ir) override; - void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame_ir, - std::unique_ptr<StringPairVector> headers) override; - void OnPing(std::unique_ptr<SpdyPingIR> frame_ir) override; - void OnPingAck(std::unique_ptr<SpdyPingIR> frame_ir) override; - void OnPriority(std::unique_ptr<SpdyPriorityIR> frame_ir) override; - void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame_ir, - std::unique_ptr<StringPairVector> headers) override; - void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame_ir) override; - void OnSettings(std::unique_ptr<SpdySettingsIR> frame_ir, - std::unique_ptr<SettingVector> settings) override; - void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame_ir) override; - void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame_ir) override; - void OnError(http2::Http2DecoderAdapter::SpdyFramerError error, - SpdyTestDeframer* deframer) override; - - private: - std::vector<CollectedFrame>* collected_frames_; -}; - -} // namespace test -} // namespace spdy - -#endif // QUICHE_SPDY_CORE_SPDY_DEFRAMER_VISITOR_H_
diff --git a/spdy/core/spdy_deframer_visitor_test.cc b/spdy/core/spdy_deframer_visitor_test.cc deleted file mode 100644 index b90d0b0..0000000 --- a/spdy/core/spdy_deframer_visitor_test.cc +++ /dev/null
@@ -1,246 +0,0 @@ -// Copyright 2016 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/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h" - -#include <stdlib.h> - -#include <algorithm> -#include <limits> - -#include "net/third_party/quiche/src/http2/test_tools/http2_random.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_test.h" -#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.h" -#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" -#include "net/third_party/quiche/src/spdy/core/spdy_frame_reader.h" -#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" -#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" -#include "net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h" -#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" -#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h" - -namespace spdy { -namespace test { -namespace { - -class SpdyDeframerVisitorTest : public QuicheTest { - protected: - SpdyDeframerVisitorTest() : encoder_(SpdyFramer::ENABLE_COMPRESSION) { - decoder_.set_process_single_input_frame(true); - auto collector = - std::make_unique<DeframerCallbackCollector>(&collected_frames_); - auto log_and_collect = - SpdyDeframerVisitorInterface::LogBeforeVisiting(std::move(collector)); - deframer_ = SpdyTestDeframer::CreateConverter(std::move(log_and_collect)); - decoder_.set_visitor(deframer_.get()); - } - - bool DeframeInput(const char* input, size_t size) { - size_t input_remaining = size; - while (input_remaining > 0 && - decoder_.spdy_framer_error() == - http2::Http2DecoderAdapter::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 = - (random_.Uniform(std::min(input_remaining, kMaxReadSize))) + 1; - size_t bytes_processed = decoder_.ProcessInput(input, bytes_read); - input_remaining -= bytes_processed; - input += bytes_processed; - if (decoder_.state() == - http2::Http2DecoderAdapter::SPDY_READY_FOR_FRAME) { - deframer_->AtFrameEnd(); - } - } - return (input_remaining == 0 && - decoder_.spdy_framer_error() == - http2::Http2DecoderAdapter::SPDY_NO_ERROR); - } - - SpdyFramer encoder_; - http2::Http2DecoderAdapter decoder_; - std::vector<CollectedFrame> collected_frames_; - std::unique_ptr<SpdyTestDeframer> deframer_; - - private: - http2::test::Http2Random random_; -}; - -TEST_F(SpdyDeframerVisitorTest, DataFrame) { - const char kFrameData[] = { - 0x00, 0x00, 0x0d, // Length = 13. - 0x00, // DATA - 0x08, // PADDED - 0x00, 0x00, 0x00, 0x01, // Stream 1 - 0x07, // Pad length field. - 'h', 'e', 'l', 'l', // Data - 'o', // More Data - 0x00, 0x00, 0x00, 0x00, // Padding - 0x00, 0x00, 0x00 // More Padding - }; - - EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); - ASSERT_EQ(1u, collected_frames_.size()); - const CollectedFrame& cf0 = collected_frames_[0]; - ASSERT_NE(cf0.frame_ir, nullptr); - - SpdyDataIR expected_ir(/* stream_id = */ 1, "hello"); - expected_ir.set_padding_len(8); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); -} - -TEST_F(SpdyDeframerVisitorTest, HeaderFrameWithContinuation) { - const char kFrameData[] = { - 0x00, 0x00, 0x05, // Payload Length: 5 - 0x01, // Type: HEADERS - 0x09, // Flags: PADDED | END_STREAM - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x04, // Padding Length: 4 - 0x00, 0x00, 0x00, 0x00, // Padding - /* Second Frame */ - 0x00, 0x00, 0x12, // Payload Length: 18 - 0x09, // Type: CONTINUATION - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, // Unindexed, literal name & value - 0x03, 0x62, 0x61, 0x72, // Name len and name (3, "bar") - 0x03, 0x66, 0x6f, 0x6f, // Value len and value (3, "foo") - 0x00, // Unindexed, literal name & value - 0x03, 0x66, 0x6f, 0x6f, // Name len and name (3, "foo") - 0x03, 0x62, 0x61, 0x72, // Value len and value (3, "bar") - }; - - EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); - ASSERT_EQ(1u, collected_frames_.size()); - const CollectedFrame& cf0 = collected_frames_[0]; - - StringPairVector headers; - headers.push_back({"bar", "foo"}); - headers.push_back({"foo", "bar"}); - - EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); - - SpdyHeadersIR expected_ir(/* stream_id = */ 1); - // Yet again SpdyFramerVisitorInterface is lossy: it doesn't call OnPadding - // for HEADERS, just for DATA. Sigh. - // expected_ir.set_padding_len(5); - expected_ir.set_fin(true); - for (const auto& nv : headers) { - expected_ir.SetHeader(nv.first, nv.second); - } - - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - // Confirm that mismatches are also detected. - headers.push_back({"baz", "bing"}); - EXPECT_FALSE(cf0.VerifyHasHeaders(headers)); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - headers.pop_back(); - EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - expected_ir.SetHeader("baz", "bing"); - EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); - EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); -} - -TEST_F(SpdyDeframerVisitorTest, PriorityFrame) { - const char kFrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x02, // Type: PRIORITY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x65, // Stream: 101 - '\x80', 0x00, 0x00, 0x01, // Parent: 1 (Exclusive) - 0x10, // Weight: 17 - }; - - EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); - ASSERT_EQ(1u, collected_frames_.size()); - const CollectedFrame& cf0 = collected_frames_[0]; - - SpdyPriorityIR expected_ir(/* stream_id = */ 101, - /* parent_stream_id = */ 1, /* weight = */ 17, - /* exclusive = */ true); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - // Confirm that mismatches are also detected. - EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 1, 16, true))); - EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 50, 17, true))); - EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(201, 1, 17, true))); - EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 1, 17, false))); -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_RstStreamFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, SettingsFrame) { - // Settings frame with two entries for the same parameter but with different - // values. The last one will be in the decoded SpdySettingsIR, but the vector - // of settings will have both, in the same order. - const char kFrameData[] = { - 0x00, 0x00, 0x0c, // Length - 0x04, // Type (SETTINGS) - 0x00, // Flags - 0x00, 0x00, 0x00, 0x00, // Stream id (must be zero) - 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE) - 0x0a, 0x0b, 0x0c, 0x0d, // Setting value - 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE) - 0x00, 0x00, 0x00, '\xff', // Setting value - }; - - EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); - ASSERT_EQ(1u, collected_frames_.size()); - const CollectedFrame& cf0 = collected_frames_[0]; - ASSERT_NE(cf0.frame_ir, nullptr); - - SpdySettingsIR expected_ir; - expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 255); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - SettingVector expected_settings; - expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 0x0a0b0c0d}); - expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 255}); - - EXPECT_TRUE(cf0.VerifyHasSettings(expected_settings)); - - // Confirm that mismatches are also detected. - expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 65536}); - EXPECT_FALSE(cf0.VerifyHasSettings(expected_settings)); - - expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 65536); - EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); - - SpdySettingsIR unexpected_ir; - unexpected_ir.set_is_ack(true); - EXPECT_FALSE(cf0.VerifyHasFrame(unexpected_ir)); -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_PushPromiseFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_PingFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_GoAwayFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_WindowUpdateFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_AltSvcFrame) { - // TODO(jamessynge): Please implement. -} - -} // namespace -} // namespace test -} // namespace spdy