// 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. #ifndef NET_SPDY_BUFFERED_SPDY_FRAMER_H_ #define NET_SPDY_BUFFERED_SPDY_FRAMER_H_ #include #include #include #include #include "base/macros.h" #include "base/strings/string_piece.h" #include "base/time/time.h" #include "net/base/net_export.h" #include "net/log/net_log_source.h" #include "net/spdy/header_coalescer.h" #include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" #include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" #include "net/third_party/quiche/src/spdy/core/spdy_framer.h" #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace net { class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface { public: BufferedSpdyFramerVisitorInterface() {} // Called if an error is detected in the spdy::SpdySerializedFrame protocol. virtual void OnError( http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error) = 0; // Called if an error is detected in a HTTP2 stream. virtual void OnStreamError(spdy::SpdyStreamId stream_id, const std::string& description) = 0; // Called after all the header data for HEADERS control frame is received. virtual void OnHeaders(spdy::SpdyStreamId stream_id, bool has_priority, int weight, spdy::SpdyStreamId parent_stream_id, bool exclusive, bool fin, spdy::Http2HeaderBlock headers, base::TimeTicks recv_first_byte_time) = 0; // Called when a data frame header is received. virtual void OnDataFrameHeader(spdy::SpdyStreamId stream_id, size_t length, bool fin) = 0; // Called when data is received. // |stream_id| The stream receiving data. // |data| A buffer containing the data received. // |len| The length of the data buffer (at most 2^16 - 1 - 8). virtual void OnStreamFrameData(spdy::SpdyStreamId stream_id, const char* data, size_t len) = 0; // Called when the other side has finished sending data on this stream. // |stream_id| The stream that was receivin data. virtual void OnStreamEnd(spdy::SpdyStreamId stream_id) = 0; // Called when padding is received (padding length field or padding octets). // |stream_id| The stream receiving data. // |len| The number of padding octets. virtual void OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) = 0; // Called when a SETTINGS frame is received. virtual void OnSettings() = 0; // Called when an individual setting within a SETTINGS frame has been parsed. // Note that |id| may or may not be a SETTINGS ID defined in the HTTP/2 spec. virtual void OnSetting(spdy::SpdySettingsId id, uint32_t value) = 0; // Called when a SETTINGS frame is received with the ACK flag set. virtual void OnSettingsAck() = 0; // Called at the completion of parsing SETTINGS id and value tuples. virtual void OnSettingsEnd() = 0; // Called when a PING frame has been parsed. virtual void OnPing(spdy::SpdyPingId unique_id, bool is_ack) = 0; // Called when a RST_STREAM frame has been parsed. virtual void OnRstStream(spdy::SpdyStreamId stream_id, spdy::SpdyErrorCode error_code) = 0; // Called when a GOAWAY frame has been parsed. virtual void OnGoAway(spdy::SpdyStreamId last_accepted_stream_id, spdy::SpdyErrorCode error_code, base::StringPiece debug_data) = 0; // Called when a WINDOW_UPDATE frame has been parsed. virtual void OnWindowUpdate(spdy::SpdyStreamId stream_id, int delta_window_size) = 0; // Called when a PUSH_PROMISE frame has been parsed. virtual void OnPushPromise(spdy::SpdyStreamId stream_id, spdy::SpdyStreamId promised_stream_id, spdy::Http2HeaderBlock headers) = 0; // Called when an ALTSVC frame has been parsed. virtual void OnAltSvc( spdy::SpdyStreamId stream_id, base::StringPiece origin, const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) = 0; // Called when a frame type we don't recognize is received. // Return true if this appears to be a valid extension frame, false otherwise. // We distinguish between extension frames and nonsense by checking // whether the stream id is valid. virtual bool OnUnknownFrame(spdy::SpdyStreamId stream_id, uint8_t frame_type) = 0; protected: virtual ~BufferedSpdyFramerVisitorInterface() {} private: DISALLOW_COPY_AND_ASSIGN(BufferedSpdyFramerVisitorInterface); }; class NET_EXPORT_PRIVATE BufferedSpdyFramer : public spdy::SpdyFramerVisitorInterface { public: using TimeFunc = base::TimeTicks (*)(void); BufferedSpdyFramer(uint32_t max_header_list_size, const NetLogWithSource& net_log, TimeFunc time_func = base::TimeTicks::Now); BufferedSpdyFramer() = delete; ~BufferedSpdyFramer() override; // Sets callbacks to be called from the buffered spdy framer. A visitor must // be set, or else the framer will likely crash. It is acceptable for the // visitor to do nothing. If this is called multiple times, only the last // visitor will be used. void set_visitor(BufferedSpdyFramerVisitorInterface* visitor); // Set debug callbacks to be called from the framer. The debug visitor is // completely optional and need not be set in order for normal operation. // If this is called multiple times, only the last visitor will be used. void set_debug_visitor(spdy::SpdyFramerDebugVisitorInterface* debug_visitor); // spdy::SpdyFramerVisitorInterface void OnError(http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error, std::string detailed_error) override; void OnHeaders(spdy::SpdyStreamId stream_id, bool has_priority, int weight, spdy::SpdyStreamId parent_stream_id, bool exclusive, bool fin, bool end) override; void OnStreamFrameData(spdy::SpdyStreamId stream_id, const char* data, size_t len) override; void OnStreamEnd(spdy::SpdyStreamId stream_id) override; void OnStreamPadLength(spdy::SpdyStreamId stream_id, size_t value) override; void OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) override; spdy::SpdyHeadersHandlerInterface* OnHeaderFrameStart( spdy::SpdyStreamId stream_id) override; void OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) override; void OnSettings() override; void OnSetting(spdy::SpdySettingsId id, uint32_t value) override; void OnSettingsAck() override; void OnSettingsEnd() override; void OnPing(spdy::SpdyPingId unique_id, bool is_ack) override; void OnRstStream(spdy::SpdyStreamId stream_id, spdy::SpdyErrorCode error_code) override; void OnGoAway(spdy::SpdyStreamId last_accepted_stream_id, spdy::SpdyErrorCode error_code) override; bool OnGoAwayFrameData(const char* goaway_data, size_t len) override; void OnWindowUpdate(spdy::SpdyStreamId stream_id, int delta_window_size) override; void OnPushPromise(spdy::SpdyStreamId stream_id, spdy::SpdyStreamId promised_stream_id, bool end) override; void OnAltSvc(spdy::SpdyStreamId stream_id, absl::string_view origin, const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) override; void OnDataFrameHeader(spdy::SpdyStreamId stream_id, size_t length, bool fin) override; void OnContinuation(spdy::SpdyStreamId stream_id, bool end) override; void OnPriority(spdy::SpdyStreamId stream_id, spdy::SpdyStreamId parent_stream_id, int weight, bool exclusive) override {} void OnPriorityUpdate(spdy::SpdyStreamId prioritized_stream_id, absl::string_view priority_field_value) override {} bool OnUnknownFrame(spdy::SpdyStreamId stream_id, uint8_t frame_type) override; // spdy::SpdyFramer methods. size_t ProcessInput(const char* data, size_t len); void UpdateHeaderDecoderTableSize(uint32_t value); void Reset(); http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error() const; http2::Http2DecoderAdapter::SpdyState state() const; bool MessageFullyRead(); bool HasError(); std::unique_ptr CreateRstStream( spdy::SpdyStreamId stream_id, spdy::SpdyErrorCode error_code) const; std::unique_ptr CreateSettings( const spdy::SettingsMap& values) const; std::unique_ptr CreatePingFrame( spdy::SpdyPingId unique_id, bool is_ack) const; std::unique_ptr CreateWindowUpdate( spdy::SpdyStreamId stream_id, uint32_t delta_window_size) const; std::unique_ptr CreateDataFrame( spdy::SpdyStreamId stream_id, const char* data, uint32_t len, spdy::SpdyDataFlags flags); std::unique_ptr CreatePriority( spdy::SpdyStreamId stream_id, spdy::SpdyStreamId dependency_id, int weight, bool exclusive) const; // Serialize a frame of unknown type. spdy::SpdySerializedFrame SerializeFrame(const spdy::SpdyFrameIR& frame) { return spdy_framer_.SerializeFrame(frame); } int frames_received() const { return frames_received_; } // Updates the maximum size of the header encoder compression table. void UpdateHeaderEncoderTableSize(uint32_t value); // Returns the maximum size of the header encoder compression table. uint32_t header_encoder_table_size() const; private: spdy::SpdyFramer spdy_framer_; http2::Http2DecoderAdapter deframer_; BufferedSpdyFramerVisitorInterface* visitor_; int frames_received_ = 0; // Collection of fields from control frames that we need to // buffer up from the spdy framer. struct ControlFrameFields { ControlFrameFields(); spdy::SpdyFrameType type; spdy::SpdyStreamId stream_id = 0U; spdy::SpdyStreamId associated_stream_id = 0U; spdy::SpdyStreamId promised_stream_id = 0U; bool has_priority = false; spdy::SpdyPriority priority = 0U; int weight = 0; spdy::SpdyStreamId parent_stream_id = 0U; bool exclusive = false; bool fin = false; bool unidirectional = false; base::TimeTicks recv_first_byte_time; }; std::unique_ptr control_frame_fields_; // Collection of fields of a GOAWAY frame that this class needs to buffer. struct GoAwayFields { spdy::SpdyStreamId last_accepted_stream_id; spdy::SpdyErrorCode error_code; std::string debug_data; }; std::unique_ptr goaway_fields_; std::unique_ptr coalescer_; const uint32_t max_header_list_size_; NetLogWithSource net_log_; TimeFunc time_func_; DISALLOW_COPY_AND_ASSIGN(BufferedSpdyFramer); }; } // namespace net #endif // NET_SPDY_BUFFERED_SPDY_FRAMER_H_