| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "net/base/net_export.h" |
| #include "net/socket/next_proto.h" |
| #include "net/spdy/spdy_framer.h" |
| #include "net/spdy/spdy_header_block.h" |
| #include "net/spdy/spdy_protocol.h" |
| |
| namespace net { |
| |
| // Returns the SPDY major version corresponding to the given NextProto |
| // value, which must represent a SPDY-like protocol. |
| NET_EXPORT_PRIVATE SpdyMajorVersion NextProtoToSpdyMajorVersion( |
| NextProto next_proto); |
| |
| class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface { |
| public: |
| BufferedSpdyFramerVisitorInterface() {} |
| |
| // Called if an error is detected in the SpdyFrame protocol. |
| virtual void OnError(SpdyFramer::SpdyError error_code) = 0; |
| |
| // Called if an error is detected in a SPDY stream. |
| virtual void OnStreamError(SpdyStreamId stream_id, |
| const std::string& description) = 0; |
| |
| // Called after all the header data for SYN_STREAM control frame is received. |
| virtual void OnSynStream(SpdyStreamId stream_id, |
| SpdyStreamId associated_stream_id, |
| SpdyPriority priority, |
| bool fin, |
| bool unidirectional, |
| const SpdyHeaderBlock& headers) = 0; |
| |
| // Called after all the header data for SYN_REPLY control frame is received. |
| virtual void OnSynReply(SpdyStreamId stream_id, |
| bool fin, |
| const SpdyHeaderBlock& headers) = 0; |
| |
| // Called after all the header data for HEADERS control frame is received. |
| virtual void OnHeaders(SpdyStreamId stream_id, |
| bool has_priority, |
| SpdyPriority priority, |
| SpdyStreamId parent_stream_id, |
| bool exclusive, |
| bool fin, |
| const SpdyHeaderBlock& headers) = 0; |
| |
| // Called when a data frame header is received. |
| virtual void OnDataFrameHeader(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^24 - 1 for SPDY/3, |
| // but 2^16 - 1 - 8 for SPDY/4). |
| // When the other side has finished sending data on this stream, |
| // this method will be called with a zero-length buffer. |
| virtual void OnStreamFrameData(SpdyStreamId stream_id, |
| const char* data, |
| size_t len, |
| bool fin) = 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(SpdyStreamId stream_id, size_t len) = 0; |
| |
| // Called just before processing the payload of a frame containing header |
| // data. Should return an implementation of SpdyHeadersHandlerInterface that |
| // will receive headers for stream |stream_id|. The caller will not take |
| // ownership of the headers handler. The same instance should be returned |
| // for all header frames comprising a logical header block (i.e. until |
| // OnHeaderFrameEnd() is called with end_headers == true). |
| virtual SpdyHeadersHandlerInterface* OnHeaderFrameStart( |
| SpdyStreamId stream_id) = 0; |
| |
| // Called after processing the payload of a frame containing header data. |
| // |end_headers| is true if there will not be any subsequent CONTINUATION |
| // frames. |
| virtual void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) = 0; |
| |
| // Called when a SETTINGS frame is received. |
| // |clear_persisted| True if the respective flag is set on the SETTINGS frame. |
| virtual void OnSettings(bool clear_persisted) = 0; |
| |
| // Called when an individual setting within a SETTINGS frame has been parsed |
| // and validated. |
| virtual void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) = 0; |
| |
| // Called when a SETTINGS frame is received with the ACK flag set. |
| virtual void OnSettingsAck() {} |
| |
| // Called at the completion of parsing SETTINGS id and value tuples. |
| virtual void OnSettingsEnd() {} |
| |
| // Called when a PING frame has been parsed. |
| virtual void OnPing(SpdyPingId unique_id, bool is_ack) = 0; |
| |
| // Called when a RST_STREAM frame has been parsed. |
| virtual void OnRstStream(SpdyStreamId stream_id, |
| SpdyRstStreamStatus status) = 0; |
| |
| // Called when a GOAWAY frame has been parsed. |
| virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, |
| SpdyGoAwayStatus status, |
| base::StringPiece debug_data) = 0; |
| |
| // Called when a WINDOW_UPDATE frame has been parsed. |
| virtual void OnWindowUpdate(SpdyStreamId stream_id, |
| int delta_window_size) = 0; |
| |
| // Called when a PUSH_PROMISE frame has been parsed. |
| virtual void OnPushPromise(SpdyStreamId stream_id, |
| SpdyStreamId promised_stream_id, |
| const SpdyHeaderBlock& headers) = 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(SpdyStreamId stream_id, int frame_type) = 0; |
| |
| protected: |
| virtual ~BufferedSpdyFramerVisitorInterface() {} |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(BufferedSpdyFramerVisitorInterface); |
| }; |
| |
| class NET_EXPORT_PRIVATE BufferedSpdyFramer |
| : public SpdyFramerVisitorInterface { |
| public: |
| BufferedSpdyFramer(SpdyMajorVersion version, |
| bool enable_compression); |
| ~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(SpdyFramerDebugVisitorInterface* debug_visitor); |
| |
| // SpdyFramerVisitorInterface |
| void OnError(SpdyFramer* spdy_framer) override; |
| void OnSynStream(SpdyStreamId stream_id, |
| SpdyStreamId associated_stream_id, |
| SpdyPriority priority, |
| bool fin, |
| bool unidirectional) override; |
| void OnSynReply(SpdyStreamId stream_id, bool fin) override; |
| void OnHeaders(SpdyStreamId stream_id, |
| bool has_priority, |
| SpdyPriority priority, |
| SpdyStreamId parent_stream_id, |
| bool exclusive, |
| bool fin, |
| bool end) override; |
| bool OnControlFrameHeaderData(SpdyStreamId stream_id, |
| const char* header_data, |
| size_t len) override; |
| void OnStreamFrameData(SpdyStreamId stream_id, |
| const char* data, |
| size_t len, |
| bool fin) override; |
| void OnStreamPadding(SpdyStreamId stream_id, size_t len) override; |
| SpdyHeadersHandlerInterface* OnHeaderFrameStart( |
| SpdyStreamId stream_id) override; |
| void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override; |
| void OnSettings(bool clear_persisted) override; |
| void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override; |
| void OnSettingsAck() override; |
| void OnSettingsEnd() override; |
| void OnPing(SpdyPingId unique_id, bool is_ack) override; |
| void OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) override; |
| void OnGoAway(SpdyStreamId last_accepted_stream_id, |
| SpdyGoAwayStatus status) override; |
| bool OnGoAwayFrameData(const char* goaway_data, size_t len) override; |
| void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override; |
| void OnPushPromise(SpdyStreamId stream_id, |
| SpdyStreamId promised_stream_id, |
| bool end) override; |
| void OnDataFrameHeader(SpdyStreamId stream_id, |
| size_t length, |
| bool fin) override; |
| void OnContinuation(SpdyStreamId stream_id, bool end) override; |
| bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override; |
| |
| // SpdyFramer methods. |
| size_t ProcessInput(const char* data, size_t len); |
| SpdyMajorVersion protocol_version(); |
| void Reset(); |
| SpdyFramer::SpdyError error_code() const; |
| SpdyFramer::SpdyState state() const; |
| bool MessageFullyRead(); |
| bool HasError(); |
| SpdyFrame* CreateSynStream(SpdyStreamId stream_id, |
| SpdyStreamId associated_stream_id, |
| SpdyPriority priority, |
| SpdyControlFlags flags, |
| const SpdyHeaderBlock* headers); |
| SpdyFrame* CreateSynReply(SpdyStreamId stream_id, |
| SpdyControlFlags flags, |
| const SpdyHeaderBlock* headers); |
| SpdyFrame* CreateRstStream(SpdyStreamId stream_id, |
| SpdyRstStreamStatus status) const; |
| SpdyFrame* CreateSettings(const SettingsMap& values) const; |
| SpdyFrame* CreatePingFrame(SpdyPingId unique_id, bool is_ack) const; |
| SpdyFrame* CreateGoAway(SpdyStreamId last_accepted_stream_id, |
| SpdyGoAwayStatus status, |
| base::StringPiece debug_data) const; |
| SpdyFrame* CreateHeaders(SpdyStreamId stream_id, |
| SpdyControlFlags flags, |
| SpdyPriority priority, |
| const SpdyHeaderBlock* headers); |
| SpdyFrame* CreateWindowUpdate(SpdyStreamId stream_id, |
| uint32_t delta_window_size) const; |
| SpdyFrame* CreateDataFrame(SpdyStreamId stream_id, |
| const char* data, |
| uint32_t len, |
| SpdyDataFlags flags); |
| SpdyFrame* CreatePushPromise(SpdyStreamId stream_id, |
| SpdyStreamId promised_stream_id, |
| const SpdyHeaderBlock* headers); |
| |
| // Serialize a frame of unknown type. |
| SpdySerializedFrame* SerializeFrame(const SpdyFrameIR& frame) { |
| return spdy_framer_.SerializeFrame(frame); |
| } |
| |
| SpdyPriority GetHighestPriority() const; |
| |
| size_t GetDataFrameMinimumSize() const { |
| return spdy_framer_.GetDataFrameMinimumSize(); |
| } |
| |
| size_t GetControlFrameHeaderSize() const { |
| return spdy_framer_.GetControlFrameHeaderSize(); |
| } |
| |
| size_t GetSynStreamMinimumSize() const { |
| return spdy_framer_.GetSynStreamMinimumSize(); |
| } |
| |
| size_t GetFrameMinimumSize() const { |
| return spdy_framer_.GetFrameMinimumSize(); |
| } |
| |
| size_t GetFrameMaximumSize() const { |
| return spdy_framer_.GetFrameMaximumSize(); |
| } |
| |
| size_t GetDataFrameMaximumPayload() const { |
| return spdy_framer_.GetDataFrameMaximumPayload(); |
| } |
| |
| int frames_received() const { return frames_received_; } |
| |
| private: |
| void InitHeaderStreaming(SpdyStreamId stream_id); |
| |
| SpdyFramer spdy_framer_; |
| BufferedSpdyFramerVisitorInterface* visitor_; |
| |
| // Header block streaming state: |
| std::string header_buffer_; |
| bool header_buffer_valid_; |
| SpdyStreamId header_stream_id_; |
| int frames_received_; |
| |
| // Collection of fields from control frames that we need to |
| // buffer up from the spdy framer. |
| struct ControlFrameFields { |
| SpdyFrameType type; |
| SpdyStreamId stream_id; |
| SpdyStreamId associated_stream_id; |
| SpdyStreamId promised_stream_id; |
| bool has_priority; |
| SpdyPriority priority; |
| SpdyStreamId parent_stream_id; |
| bool exclusive; |
| bool fin; |
| bool unidirectional; |
| }; |
| scoped_ptr<ControlFrameFields> control_frame_fields_; |
| |
| // Collection of fields of a GOAWAY frame that this class needs to buffer. |
| struct GoAwayFields { |
| SpdyStreamId last_accepted_stream_id; |
| SpdyGoAwayStatus status; |
| std::string debug_data; |
| }; |
| scoped_ptr<GoAwayFields> goaway_fields_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BufferedSpdyFramer); |
| }; |
| |
| } // namespace net |
| |
| #endif // NET_SPDY_BUFFERED_SPDY_FRAMER_H_ |