| // Copyright 2012 The Chromium Authors |
| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/memory/raw_ptr.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/quiche/spdy/core/http2_frame_decoder_adapter.h" |
| #include "net/third_party/quiche/src/quiche/spdy/core/http2_header_block.h" |
| #include "net/third_party/quiche/src/quiche/spdy/core/spdy_alt_svc_wire_format.h" |
| #include "net/third_party/quiche/src/quiche/spdy/core/spdy_framer.h" |
| #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h" |
| |
| namespace net { |
| |
| class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface { |
| public: |
| BufferedSpdyFramerVisitorInterface() = default; |
| |
| BufferedSpdyFramerVisitorInterface( |
| const BufferedSpdyFramerVisitorInterface&) = delete; |
| BufferedSpdyFramerVisitorInterface& operator=( |
| const BufferedSpdyFramerVisitorInterface&) = delete; |
| |
| // 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() = default; |
| }; |
| |
| class NET_EXPORT_PRIVATE BufferedSpdyFramer |
| : public spdy::SpdyFramerVisitorInterface { |
| public: |
| using TimeFunc = base::TimeTicks (*)(); |
| |
| BufferedSpdyFramer(uint32_t max_header_list_size, |
| const NetLogWithSource& net_log, |
| TimeFunc time_func = base::TimeTicks::Now); |
| BufferedSpdyFramer() = delete; |
| |
| BufferedSpdyFramer(const BufferedSpdyFramer&) = delete; |
| BufferedSpdyFramer& operator=(const 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, |
| size_t payload_length, |
| 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, |
| size_t payload_length, |
| 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; |
| void OnUnknownFrameStart(spdy::SpdyStreamId stream_id, |
| size_t length, |
| uint8_t type, |
| uint8_t flags) override {} |
| void OnUnknownFramePayload(spdy::SpdyStreamId stream_id, |
| absl::string_view payload) override {} |
| |
| // spdy::SpdyFramer methods. |
| size_t ProcessInput(const char* data, size_t len); |
| void UpdateHeaderDecoderTableSize(uint32_t value); |
| http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error() const; |
| http2::Http2DecoderAdapter::SpdyState state() const; |
| bool MessageFullyRead(); |
| bool HasError(); |
| std::unique_ptr<spdy::SpdySerializedFrame> CreateRstStream( |
| spdy::SpdyStreamId stream_id, |
| spdy::SpdyErrorCode error_code) const; |
| std::unique_ptr<spdy::SpdySerializedFrame> CreateSettings( |
| const spdy::SettingsMap& values) const; |
| std::unique_ptr<spdy::SpdySerializedFrame> CreatePingFrame( |
| spdy::SpdyPingId unique_id, |
| bool is_ack) const; |
| std::unique_ptr<spdy::SpdySerializedFrame> CreateWindowUpdate( |
| spdy::SpdyStreamId stream_id, |
| uint32_t delta_window_size) const; |
| std::unique_ptr<spdy::SpdySerializedFrame> CreateDataFrame( |
| spdy::SpdyStreamId stream_id, |
| const char* data, |
| uint32_t len, |
| spdy::SpdyDataFlags flags); |
| std::unique_ptr<spdy::SpdySerializedFrame> 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_; |
| raw_ptr<BufferedSpdyFramerVisitorInterface> visitor_ = nullptr; |
| |
| 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<ControlFrameFields> 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<GoAwayFields> goaway_fields_; |
| |
| std::unique_ptr<HeaderCoalescer> coalescer_; |
| |
| const uint32_t max_header_list_size_; |
| NetLogWithSource net_log_; |
| TimeFunc time_func_; |
| }; |
| |
| } // namespace net |
| |
| #endif // NET_SPDY_BUFFERED_SPDY_FRAMER_H_ |