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

Unified Diff: net/spdy/spdy_framer.h

Issue 9618002: SPDY - integration of spdy/3 code. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 9 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_frame_reader_test.cc ('k') | net/spdy/spdy_framer.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_framer.h
===================================================================
--- net/spdy/spdy_framer.h (revision 126086)
+++ net/spdy/spdy_framer.h (working copy)
@@ -37,19 +37,51 @@
namespace spdy {
class SpdyFramer;
-class SpdyFramerTest;
+class SpdyFrameBuilder;
+class SpdyFramerSpdy2Test;
+class SpdyFramerSpdy3Test;
-namespace test {
+namespace test_spdy2 {
+
class TestSpdyVisitor;
-void FramerSetEnableCompressionHelper(SpdyFramer* framer, bool compress);
-} // namespace test
+} // namespace test_spdy2
+
+namespace test_spdy3 {
+
+class TestSpdyVisitor;
+
+} // namespace test_spdy3
+
// A datastructure for holding a set of headers from either a
// SYN_STREAM or SYN_REPLY frame.
typedef std::map<std::string, std::string> SpdyHeaderBlock;
+// A datastructure for holding the ID and flag fields for SETTINGS.
+// Conveniently handles converstion to/from wire format.
+class NET_EXPORT_PRIVATE SettingsFlagsAndId {
+ public:
+ static SettingsFlagsAndId FromWireFormat(int version, uint32 wire);
+
+ SettingsFlagsAndId() : flags_(0), id_(0) {}
+
+ // TODO(hkhalil): restrict to enums instead of free-form ints.
+ SettingsFlagsAndId(uint8 flags, uint32 id);
+
+ uint32 GetWireFormat(int version) const;
+
+ uint32 id() const { return id_; }
+ uint8 flags() const { return flags_; }
+
+ private:
+ static void ConvertFlagsAndIdForSpdy2(uint32* val);
+
+ uint8 flags_;
+ uint32 id_;
+};
+
// A datastructure for holding a set of ID/value pairs for a SETTINGS frame.
-typedef std::pair<spdy::SettingsFlagsAndId, uint32> SpdySetting;
+typedef std::pair<SettingsFlagsAndId, uint32> SpdySetting;
typedef std::list<SpdySetting> SpdySettings;
// A datastrcture for holding the contents of a CREDENTIAL frame.
@@ -62,6 +94,27 @@
std::string proof;
};
+// Scratch space necessary for processing SETTINGS frames.
+struct NET_EXPORT_PRIVATE SpdySettingsScratch {
+ SpdySettingsScratch() { Reset(); }
+
+ void Reset() {
+ setting_buf_len = 0;
+ last_setting_id = 0;
+ }
+
+ // Buffer contains up to one complete key/value pair.
+ char setting_buf[8];
+
+ // The amount of the buffer that is filled with valid data.
+ size_t setting_buf_len;
+
+ // The ID of the last setting that was processed in the current SETTINGS
+ // frame. Used for detecting out-of-order or duplicate keys within a settings
+ // frame. Set to 0 before first key/value pair is processed.
+ uint32 last_setting_id;
+};
+
// SpdyFramerVisitorInterface is a set of callbacks for the SpdyFramer.
// Implement this interface to receive event callbacks as frames are
// decoded from the framer.
@@ -113,13 +166,13 @@
// Called when a chunk of payload data for a credential frame is available.
// This is called after OnControl() is called with the credential frame
// associated with the payload being delivered here.
- // |frame_data| A buffer containing the header data chunk received.
+ // |header_data| A buffer containing the header data chunk received.
// |len| The length of the header data buffer. A length of zero indicates
// that the header data block has been completely sent.
// When this function returns true the visitor indicates that it accepted
// all of the data. Returning false indicates that that an unrecoverable
// error has occurred, such as bad header data or resource exhaustion.
- virtual bool OnCredentialFrameData(const char* frame_data,
+ virtual bool OnCredentialFrameData(const char* header_data,
size_t len) = 0;
// Called when a data frame header is received. The frame's data
@@ -136,6 +189,10 @@
virtual void OnStreamFrameData(SpdyStreamId stream_id,
const char* data,
size_t len) = 0;
+
+ // Called when a complete setting within a SETTINGS frame has been parsed and
+ // validated.
+ virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) = 0;
};
class NET_EXPORT_PRIVATE SpdyFramer {
@@ -155,6 +212,7 @@
SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK,
SPDY_CONTROL_FRAME_HEADER_BLOCK,
SPDY_CREDENTIAL_FRAME_PAYLOAD,
+ SPDY_SETTINGS_FRAME_PAYLOAD,
};
// SPDY error codes.
@@ -179,8 +237,8 @@
// purposes.)
static const size_t kHeaderDataChunkMaxSize;
- // Create a new Framer.
- SpdyFramer();
+ // Create a new Framer, provided a SPDY version.
+ explicit SpdyFramer(int version);
virtual ~SpdyFramer();
// Set callbacks to be called from the framer. A visitor must be set, or
@@ -209,31 +267,26 @@
}
bool HasError() { return state_ == SPDY_ERROR; }
- // Further parsing utilities.
- // Given a control frame, parse out a SpdyHeaderBlock. Only
- // valid for SYN_STREAM and SYN_REPLY frames.
- // Returns true if successfully parsed, false otherwise.
- bool ParseHeaderBlock(const SpdyFrame* frame, SpdyHeaderBlock* block);
-
// Given a buffer containing a decompressed header block in SPDY
// serialized format, parse out a SpdyHeaderBlock, putting the results
// in the given header block.
// Returns true if successfully parsed, false otherwise.
- static bool ParseHeaderBlockInBuffer(const char* header_data,
- size_t header_length,
- SpdyHeaderBlock* block);
+ bool ParseHeaderBlockInBuffer(const char* header_data,
+ size_t header_length,
+ SpdyHeaderBlock* block);
// Create a SpdySynStreamControlFrame.
// |stream_id| is the id for this stream.
// |associated_stream_id| is the associated stream id for this stream.
- // |priority| is the priority (0-3) for this stream.
+ // |priority| is the priority (GetHighestPriority()-GetLowestPriority) for
+ // this stream.
// |flags| is the flags to use with the data.
// To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
// |compressed| specifies whether the frame should be compressed.
// |headers| is the header block to include in the frame.
SpdySynStreamControlFrame* CreateSynStream(SpdyStreamId stream_id,
SpdyStreamId associated_stream_id,
- int priority,
+ SpdyPriority priority,
SpdyControlFlags flags,
bool compressed,
const SpdyHeaderBlock* headers);
@@ -249,26 +302,23 @@
bool compressed,
const SpdyHeaderBlock* headers);
- static SpdyRstStreamControlFrame* CreateRstStream(SpdyStreamId stream_id,
- SpdyStatusCodes status);
+ SpdyRstStreamControlFrame* CreateRstStream(SpdyStreamId stream_id,
+ SpdyStatusCodes status) const;
// Creates an instance of SpdySettingsControlFrame. The SETTINGS frame is
// used to communicate name/value pairs relevant to the communication channel.
- // TODO(mbelshe): add the name/value pairs!!
- static SpdySettingsControlFrame* CreateSettings(const SpdySettings& values);
+ SpdySettingsControlFrame* CreateSettings(const SpdySettings& values) const;
- static SpdyNoOpControlFrame* CreateNopFrame();
-
// Creates an instance of SpdyPingControlFrame. The unique_id is used to
// identify the ping request/response.
- static SpdyPingControlFrame* CreatePingFrame(uint32 unique_id);
+ SpdyPingControlFrame* CreatePingFrame(uint32 unique_id) const;
// Creates an instance of SpdyGoAwayControlFrame. The GOAWAY frame is used
// prior to the shutting down of the TCP connection, and includes the
// stream_id of the last stream the sender of the frame is willing to process
// to completion.
- static SpdyGoAwayControlFrame* CreateGoAway(
- SpdyStreamId last_accepted_stream_id);
+ SpdyGoAwayControlFrame* CreateGoAway(
+ SpdyStreamId last_accepted_stream_id) const;
// Creates an instance of SpdyHeadersControlFrame. The HEADERS frame is used
// for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The
@@ -280,15 +330,15 @@
// Creates an instance of SpdyWindowUpdateControlFrame. The WINDOW_UPDATE
// frame is used to implement per stream flow control in SPDY.
- static SpdyWindowUpdateControlFrame* CreateWindowUpdate(
+ SpdyWindowUpdateControlFrame* CreateWindowUpdate(
SpdyStreamId stream_id,
- uint32 delta_window_size);
+ uint32 delta_window_size) const;
// Creates an instance of SpdyCredentialControlFrame. The CREDENTIAL
// frame is used to send a client certificate to the server when
// request more than one origin are sent over the same SPDY session.
- static SpdyCredentialControlFrame* CreateCredentialFrame(
- const SpdyCredential& credential);
+ SpdyCredentialControlFrame* CreateCredentialFrame(
+ const SpdyCredential& credential) const;
// Given a SpdySettingsControlFrame, extract the settings.
// Returns true on successful parse, false otherwise.
@@ -330,13 +380,6 @@
// On failure, returns NULL.
SpdyFrame* CompressFrame(const SpdyFrame& frame);
- // Decompresses a SpdyFrame.
- // On success, returns a new SpdyFrame with the payload decompressed.
- // Compression state is maintained as part of the SpdyFramer.
- // Returned frame must be freed with "delete".
- // On failure, returns NULL.
- SpdyFrame* DecompressFrame(const SpdyFrame& frame);
-
// Create a copy of a frame.
// Returned frame must be freed with "delete".
SpdyFrame* DuplicateFrame(const SpdyFrame& frame);
@@ -373,18 +416,44 @@
static const char* StatusCodeToString(int status_code);
static const char* ControlTypeToString(SpdyControlType type);
- static void set_protocol_version(int version) { spdy_version_= version; }
- static int protocol_version() { return spdy_version_; }
+ // TODO(hkhalil): Remove SpdyFramer::set_protocol_version()
+ void set_protocol_version(int version) { spdy_version_= version; }
+ int protocol_version() const { return spdy_version_; }
- // Export the compression dictionary
- static const char kDictionary[];
- static const int kDictionarySize;
+ bool probable_http_response() { return probable_http_response_; }
+ SpdyPriority GetLowestPriority() const { return spdy_version_ < 3 ? 3 : 7; }
+ SpdyPriority GetHighestPriority() const { return 0; }
+
protected:
- FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, HeaderCompression);
- FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ExpandBuffer_HeapSmash);
- FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, HugeHeaderBlock);
- FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, UnclosedStreamDataCompressors);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test, BasicCompression);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test, ControlFrameSizesAreValidated);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test, HeaderCompression);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test, DecompressUncompressedFrame);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test, ExpandBuffer_HeapSmash);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test, HugeHeaderBlock);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test, UnclosedStreamDataCompressors);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test,
+ UnclosedStreamDataCompressorsOneByteAtATime);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test,
+ UncompressLargerThanFrameBufferInitialSize);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test, ReadLargeSettingsFrame);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy2Test,
+ ReadLargeSettingsFrameInSmallChunks);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test, BasicCompression);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test, ControlFrameSizesAreValidated);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test, HeaderCompression);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test, DecompressUncompressedFrame);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test, ExpandBuffer_HeapSmash);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test, HugeHeaderBlock);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test, UnclosedStreamDataCompressors);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test,
+ UnclosedStreamDataCompressorsOneByteAtATime);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test,
+ UncompressLargerThanFrameBufferInitialSize);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test, ReadLargeSettingsFrame);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerSpdy3Test,
+ ReadLargeSettingsFrameInSmallChunks);
friend class net::HttpNetworkLayer; // This is temporary for the server.
friend class net::HttpNetworkTransactionTest;
friend class net::HttpProxyClientSocketPoolTest;
@@ -395,45 +464,37 @@
friend class net::SpdyStreamTest;
friend class net::SpdyWebSocketStreamTest;
friend class net::WebSocketJobTest;
- friend class test::TestSpdyVisitor;
- friend void test::FramerSetEnableCompressionHelper(SpdyFramer* framer,
- bool compress);
+ friend class test_spdy2::TestSpdyVisitor;
+ friend class test_spdy3::TestSpdyVisitor;
private:
typedef std::map<SpdyStreamId, z_stream*> CompressorMap;
- // Internal breakout from ProcessInput. Returns the number of bytes
+ // Internal breakouts from ProcessInput. Each returns the number of bytes
// consumed from the data.
size_t ProcessCommonHeader(const char* data, size_t len);
- void ProcessControlFrameHeader();
size_t ProcessControlFramePayload(const char* data, size_t len);
size_t ProcessCredentialFramePayload(const char* data, size_t len);
size_t ProcessControlFrameBeforeHeaderBlock(const char* data, size_t len);
size_t ProcessControlFrameHeaderBlock(const char* data, size_t len);
+ size_t ProcessSettingsFramePayload(const char* data, size_t len);
size_t ProcessDataFramePayload(const char* data, size_t len);
+ // Helpers for above internal breakouts from ProcessInput.
+ void ProcessControlFrameHeader();
+ bool ProcessSetting(const char* data); // Always passed exactly 8 bytes.
+
// Get (and lazily initialize) the ZLib state.
z_stream* GetHeaderCompressor();
z_stream* GetHeaderDecompressor();
- z_stream* GetStreamCompressor(SpdyStreamId id);
z_stream* GetStreamDecompressor(SpdyStreamId id);
// Compression helpers
SpdyControlFrame* CompressControlFrame(const SpdyControlFrame& frame);
- SpdyDataFrame* CompressDataFrame(const SpdyDataFrame& frame);
- SpdyControlFrame* DecompressControlFrame(const SpdyControlFrame& frame);
- SpdyDataFrame* DecompressDataFrame(const SpdyDataFrame& frame);
- SpdyFrame* CompressFrameWithZStream(const SpdyFrame& frame,
- z_stream* compressor);
- SpdyFrame* DecompressFrameWithZStream(const SpdyFrame& frame,
- z_stream* decompressor);
void CleanupCompressorForStream(SpdyStreamId id);
void CleanupDecompressorForStream(SpdyStreamId id);
void CleanupStreamCompressorsAndDecompressors();
- // Not used (yet)
- size_t BytesSafeToRead() const;
-
// Deliver the given control frame's compressed headers block to the visitor
// in decompressed form, in chunks. Returns true if the visitor has
// accepted all of the chunks.
@@ -458,6 +519,13 @@
size_t UpdateCurrentFrameBuffer(const char** data, size_t* len,
size_t max_bytes);
+ // Retrieve serialized length of SpdyHeaderBlock.
+ size_t GetSerializedLength(const SpdyHeaderBlock* headers) const;
+
+ // Serializes a SpdyHeaderBlock.
+ void WriteHeaderBlock(SpdyFrameBuilder* frame,
+ const SpdyHeaderBlock* headers) const;
+
// Set the error code and moves the framer into the error state.
void set_error(SpdyError error);
@@ -486,19 +554,14 @@
// Since this is only used for control frame headers, the maximum control
// frame header size (18B) is sufficient; all remaining control frame data is
// streamed to the visitor.
- // In addition to the maximum control frame header size, we account for any
- // LOAS checksumming (16B) that may occur in the VTL case.
// TODO(hkhalil): Remove post code-yellow once streamed inflate is properly
// implemented.
- static const size_t kUncompressedControlFrameBufferInitialSize = 18 + 16;
+ static size_t kUncompressedControlFrameBufferInitialSize;
// The maximum size of the control frame buffer that we support.
// TODO(mbelshe): We should make this stream-based so there are no limits.
static size_t kControlFrameBufferMaxSize;
- // The size of the buffer into which compressed frames are inflated.
- static const size_t kDecompressionBufferSize = 8 * 1024;
-
SpdyState state_;
SpdyError error_code_;
size_t remaining_data_;
@@ -516,6 +579,11 @@
size_t current_frame_len_; // Number of bytes read into the current_frame_.
size_t current_frame_capacity_;
+ // Scratch space for handling SETTINGS frames.
+ // TODO(hkhalil): Unify memory for this scratch space with
+ // current_frame_buffer_.
+ SpdySettingsScratch settings_scratch_;
+
bool validate_control_frame_sizes_;
bool enable_compression_; // Controls all compression
// SPDY header compressors.
@@ -530,8 +598,24 @@
std::string display_protocol_;
+ int spdy_version_;
+
+ // Tracks if we've ever gotten far enough in framing to see a control frame of
+ // type SYN_STREAM or SYN_REPLY.
+ //
+ // If we ever get something which looks like a data frame before we've had a
+ // SYN, we explicitly check to see if it looks like we got an HTTP response to
+ // a SPDY request. This boolean lets us do that.
+ bool syn_frame_processed_;
+
+ // If we ever get a data frame before a SYN frame, we check to see if it
+ // starts with HTTP. If it does, we likely have an HTTP response. This
+ // isn't guaranteed though: we could have gotten a settings frame and then
+ // corrupt data that just looks like HTTP, but deterministic checking requires
+ // a lot more state.
+ bool probable_http_response_;
+
static bool compression_default_;
- static int spdy_version_;
};
} // namespace spdy
« no previous file with comments | « net/spdy/spdy_frame_reader_test.cc ('k') | net/spdy/spdy_framer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698