diff options
author | mbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-03 22:04:03 +0000 |
---|---|---|
committer | mbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-03 22:04:03 +0000 |
commit | d083585002893abaa6172c361aa04306a0e4d396 (patch) | |
tree | 75ff77ddf51d68d450ee0e7d56192409e44bcf97 /net/spdy/spdy_framer.cc | |
parent | 95c97199c4406036b216d74e4ba3a5c57c0081a2 (diff) | |
download | chromium_src-d083585002893abaa6172c361aa04306a0e4d396.zip chromium_src-d083585002893abaa6172c361aa04306a0e4d396.tar.gz chromium_src-d083585002893abaa6172c361aa04306a0e4d396.tar.bz2 |
Update server push to allow use of HEADERS frame.
- Sync'd server changes for SPDY protocol and framer.
- Adds HEADERS support & smaller header frame support.
- Changes field name from "path" to "url" for pushed streams.
- Changes existing semantics in SpdyStream and SpdyHttpStream
with how the OnResponseReceived callback works and with how
headers are parsed to reflect multi-frame arrival of headers.
Other changes:
- Reworked the StaticSocketDataProvider interface slightly so that we
can share code between tests using DelayedSocketData or
DeterministicSocketData
- Tidy up net_log for pushed streams with associated-stream id logging
and format fixes for SPDY_STREAM.
BUG=none
TEST=spdy_framer_test,spdy_network_transaction_unittest(s)
Review URL: http://codereview.chromium.org/5248001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68221 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy/spdy_framer.cc')
-rw-r--r-- | net/spdy/spdy_framer.cc | 202 |
1 files changed, 136 insertions, 66 deletions
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index ea58559..ed21610 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(rtenhove) clean up frame buffer size calculations so that we aren't +// constantly adding and subtracting header sizes; this is ugly and error- +// prone. + #include "net/spdy/spdy_framer.h" #include "base/metrics/stats_counters.h" @@ -17,23 +21,26 @@ namespace spdy { -// The initial size of the control frame buffer; this is used internally -// as we parse through control frames. -static const size_t kControlFrameBufferInitialSize = 32 * 1024; -// 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 const size_t kControlFrameBufferMaxSize = 64 * 1024; - // By default is compression on or off. bool SpdyFramer::compression_default_ = true; int SpdyFramer::spdy_version_ = kSpdyProtocolVersion; +// The initial size of the control frame buffer; this is used internally +// as we parse through control frames. (It is exposed here for unit test +// purposes.) +size_t SpdyFramer::kControlFrameBufferInitialSize = 8 * 1024; + +// The maximum size of the control frame buffer that we support. +// TODO(mbelshe): We should make this stream-based so there are no limits. +size_t SpdyFramer::kControlFrameBufferMaxSize = 16 * 1024; + #ifdef DEBUG_SPDY_STATE_CHANGES #define CHANGE_STATE(newstate) \ { \ do { \ - VLOG(1) << "Changing state from: " << StateToString(state_) \ - << " to " << StateToString(newstate); \ + LOG(INFO) << "Changing state from: " \ + << StateToString(state_) \ + << " to " << StateToString(newstate) << "\n"; \ state_ = newstate; \ } while (false); \ } @@ -72,7 +79,7 @@ void SpdyFramer::Reset() { current_frame_len_ = 0; if (current_frame_capacity_ != kControlFrameBufferInitialSize) { delete [] current_frame_buffer_; - current_frame_buffer_ = NULL; + current_frame_buffer_ = 0; current_frame_capacity_ = 0; ExpandControlFrameBuffer(kControlFrameBufferInitialSize); } @@ -289,6 +296,11 @@ void SpdyFramer::ProcessControlFrameHeader() { SpdyRstStreamControlFrame::size() - SpdyFrame::size()) set_error(SPDY_INVALID_CONTROL_FRAME); break; + case SETTINGS: + if (current_control_frame.length() < + SpdySettingsControlFrame::size() - SpdyControlFrame::size()) + set_error(SPDY_INVALID_CONTROL_FRAME); + break; case NOOP: // NOOP. Swallow it. CHANGE_STATE(SPDY_AUTO_RESET); @@ -298,14 +310,14 @@ void SpdyFramer::ProcessControlFrameHeader() { SpdyGoAwayControlFrame::size() - SpdyFrame::size()) set_error(SPDY_INVALID_CONTROL_FRAME); break; - case SETTINGS: + case HEADERS: if (current_control_frame.length() < - SpdySettingsControlFrame::size() - SpdyControlFrame::size()) + SpdyHeadersControlFrame::size() - SpdyControlFrame::size()) set_error(SPDY_INVALID_CONTROL_FRAME); break; case WINDOW_UPDATE: if (current_control_frame.length() != - SpdyWindowUpdateControlFrame::size() - SpdyFrame::size()) + SpdyWindowUpdateControlFrame::size() - SpdyControlFrame::size()) set_error(SPDY_INVALID_CONTROL_FRAME); break; default: @@ -435,7 +447,7 @@ bool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame, SpdyHeaderBlock* block) { SpdyControlFrame control_frame(frame->data(), false); uint32 type = control_frame.type(); - if (type != SYN_STREAM && type != SYN_REPLY) + if (type != SYN_STREAM && type != SYN_REPLY && type != HEADERS) return false; // Find the header data within the control frame. @@ -461,14 +473,21 @@ bool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame, header_length = syn_frame.header_block_len(); } break; + case HEADERS: + { + SpdyHeadersControlFrame header_frame(decompressed_frame->data(), false); + header_data = header_frame.header_block(); + header_length = header_frame.header_block_len(); + } + break; } SpdyFrameBuilder builder(header_data, header_length); void* iter = NULL; uint16 num_headers; if (builder.ReadUInt16(&iter, &num_headers)) { - int index = 0; - for ( ; index < num_headers; ++index) { + int index; + for (index = 0; index < num_headers; ++index) { std::string name; std::string value; if (!builder.ReadString(&iter, &name)) @@ -551,55 +570,60 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( return reinterpret_cast<SpdySynStreamControlFrame*>(syn_frame.release()); } -/* static */ -SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id, - SpdyStatusCodes status) { +SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id, + SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) { DCHECK_GT(stream_id, 0u); DCHECK_EQ(0u, stream_id & ~kStreamIdMask); - DCHECK_NE(status, INVALID); - DCHECK_LT(status, NUM_STATUS_CODES); SpdyFrameBuilder frame; + frame.WriteUInt16(kControlFlagMask | spdy_version_); - frame.WriteUInt16(RST_STREAM); - frame.WriteUInt32(8); + frame.WriteUInt16(SYN_REPLY); + frame.WriteUInt32(0); // Placeholder for the length and flags. frame.WriteUInt32(stream_id); - frame.WriteUInt32(status); - return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take()); -} + frame.WriteUInt16(0); // Unused -/* static */ -SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway( - SpdyStreamId last_accepted_stream_id) { - DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask); + frame.WriteUInt16(headers->size()); // Number of headers. + SpdyHeaderBlock::iterator it; + for (it = headers->begin(); it != headers->end(); ++it) { + bool wrote_header; + wrote_header = frame.WriteString(it->first); + wrote_header &= frame.WriteString(it->second); + DCHECK(wrote_header); + } - SpdyFrameBuilder frame; - frame.WriteUInt16(kControlFlagMask | spdy_version_); - frame.WriteUInt16(GOAWAY); - size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::size(); - frame.WriteUInt32(go_away_size); - frame.WriteUInt32(last_accepted_stream_id); - return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take()); + // Write the length and flags. + size_t length = frame.length() - SpdyFrame::size(); + DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask)); + FlagsAndLength flags_length; + flags_length.length_ = htonl(static_cast<uint32>(length)); + DCHECK_EQ(0, flags & ~kControlFlagsMask); + flags_length.flags_[0] = flags; + frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length)); + + scoped_ptr<SpdyFrame> reply_frame(frame.take()); + if (compressed) { + return reinterpret_cast<SpdySynReplyControlFrame*>( + CompressFrame(*reply_frame.get())); + } + return reinterpret_cast<SpdySynReplyControlFrame*>(reply_frame.release()); } /* static */ -SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate( - SpdyStreamId stream_id, - uint32 delta_window_size) { +SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id, + SpdyStatusCodes status) { DCHECK_GT(stream_id, 0u); DCHECK_EQ(0u, stream_id & ~kStreamIdMask); - DCHECK_GT(delta_window_size, 0u); - DCHECK_LT(delta_window_size, 0x80000000u); // 2^31 + DCHECK_NE(status, INVALID); + DCHECK_LT(status, NUM_STATUS_CODES); SpdyFrameBuilder frame; frame.WriteUInt16(kControlFlagMask | spdy_version_); - frame.WriteUInt16(WINDOW_UPDATE); - size_t window_update_size = SpdyWindowUpdateControlFrame::size() - - SpdyFrame::size(); - frame.WriteUInt32(window_update_size); + frame.WriteUInt16(RST_STREAM); + frame.WriteUInt32(8); frame.WriteUInt32(stream_id); - frame.WriteUInt32(delta_window_size); - return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take()); + frame.WriteUInt32(status); + return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take()); } /* static */ @@ -621,15 +645,38 @@ SpdySettingsControlFrame* SpdyFramer::CreateSettings( return reinterpret_cast<SpdySettingsControlFrame*>(frame.take()); } -SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id, +/* static */ +SpdyControlFrame* SpdyFramer::CreateNopFrame() { + SpdyFrameBuilder frame; + frame.WriteUInt16(kControlFlagMask | spdy_version_); + frame.WriteUInt16(NOOP); + frame.WriteUInt32(0); + return reinterpret_cast<SpdyControlFrame*>(frame.take()); +} + +/* static */ +SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway( + SpdyStreamId last_accepted_stream_id) { + DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask); + + SpdyFrameBuilder frame; + frame.WriteUInt16(kControlFlagMask | spdy_version_); + frame.WriteUInt16(GOAWAY); + size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::size(); + frame.WriteUInt32(go_away_size); + frame.WriteUInt32(last_accepted_stream_id); + return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take()); +} + +SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(SpdyStreamId stream_id, SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) { + // Basically the same as CreateSynReply(). DCHECK_GT(stream_id, 0u); DCHECK_EQ(0u, stream_id & ~kStreamIdMask); SpdyFrameBuilder frame; - - frame.WriteUInt16(kControlFlagMask | spdy_version_); - frame.WriteUInt16(SYN_REPLY); + frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion); + frame.WriteUInt16(HEADERS); frame.WriteUInt32(0); // Placeholder for the length and flags. frame.WriteUInt32(stream_id); frame.WriteUInt16(0); // Unused @@ -652,12 +699,32 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id, flags_length.flags_[0] = flags; frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length)); - scoped_ptr<SpdyFrame> reply_frame(frame.take()); + scoped_ptr<SpdyFrame> headers_frame(frame.take()); if (compressed) { - return reinterpret_cast<SpdySynReplyControlFrame*>( - CompressFrame(*reply_frame.get())); + return reinterpret_cast<SpdyHeadersControlFrame*>( + CompressFrame(*headers_frame.get())); } - return reinterpret_cast<SpdySynReplyControlFrame*>(reply_frame.release()); + return reinterpret_cast<SpdyHeadersControlFrame*>(headers_frame.release()); +} + +/* static */ +SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate( + SpdyStreamId stream_id, + uint32 delta_window_size) { + DCHECK_GT(stream_id, 0u); + DCHECK_EQ(0u, stream_id & ~kStreamIdMask); + DCHECK_GT(delta_window_size, 0u); + DCHECK_LE(delta_window_size, spdy::kSpdyStreamMaximumWindowSize); + + SpdyFrameBuilder frame; + frame.WriteUInt16(kControlFlagMask | spdy_version_); + frame.WriteUInt16(WINDOW_UPDATE); + size_t window_update_size = SpdyWindowUpdateControlFrame::size() - + SpdyFrame::size(); + frame.WriteUInt32(window_update_size); + frame.WriteUInt32(stream_id); + frame.WriteUInt32(delta_window_size); + return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take()); } SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id, @@ -692,15 +759,6 @@ SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id, return rv; } -/* static */ -SpdyControlFrame* SpdyFramer::CreateNopFrame() { - SpdyFrameBuilder frame; - frame.WriteUInt16(kControlFlagMask | spdy_version_); - frame.WriteUInt16(NOOP); - frame.WriteUInt32(0); - return reinterpret_cast<SpdyControlFrame*>(frame.take()); -} - // The following compression setting are based on Brian Olson's analysis. See // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac792 // for more details. @@ -844,6 +902,16 @@ bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame, *payload = frame.data() + *header_length; } break; + case HEADERS: + { + const SpdyHeadersControlFrame& headers_frame = + reinterpret_cast<const SpdyHeadersControlFrame&>(frame); + frame_size = SpdyHeadersControlFrame::size(); + *payload_length = headers_frame.header_block_len(); + *header_length = frame_size; + *payload = frame.data() + *header_length; + } + break; default: // TODO(mbelshe): set an error? return false; // We can't compress this frame! @@ -985,8 +1053,10 @@ SpdyFrame* SpdyFramer::DecompressFrameWithZStream(const SpdyFrame& frame, // Create an output frame. Assume it does not need to be longer than // the input data. - int decompressed_max_size = kControlFrameBufferInitialSize; + size_t decompressed_max_size = kControlFrameBufferInitialSize; int new_frame_size = header_length + decompressed_max_size; + if (frame.length() > decompressed_max_size) + return NULL; scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size)); memcpy(new_frame->data(), frame.data(), frame.length() + SpdyFrame::size()); |