diff options
author | mbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-09 18:35:40 +0000 |
---|---|---|
committer | mbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-09 18:35:40 +0000 |
commit | 592ca909efa35c0000b349285b059700ae543ee4 (patch) | |
tree | 76e6308199862df45804c70e99b23edafcdc85d1 /net/spdy | |
parent | 75a2c3b76edcaba820e96e5e202a7cf5c2f5f088 (diff) | |
download | chromium_src-592ca909efa35c0000b349285b059700ae543ee4.zip chromium_src-592ca909efa35c0000b349285b059700ae543ee4.tar.gz chromium_src-592ca909efa35c0000b349285b059700ae543ee4.tar.bz2 |
Merge deltas from server team common SPDY files.
Fixes one memory leak and one mismatched scoped_ptr/array usage.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/591003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38478 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy')
-rw-r--r-- | net/spdy/spdy_framer.cc | 71 | ||||
-rw-r--r-- | net/spdy/spdy_framer.h | 15 | ||||
-rw-r--r-- | net/spdy/spdy_protocol.h | 81 |
3 files changed, 126 insertions, 41 deletions
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index 0a5c014..0996970 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "net/spdy/spdy_framer.h" + #include "base/scoped_ptr.h" #include "base/stats_counters.h" -#include "net/spdy/spdy_framer.h" #include "net/spdy/spdy_frame_builder.h" #include "net/spdy/spdy_bitmasks.h" @@ -133,8 +134,6 @@ const char* SpdyFramer::ErrorCodeToString(int error_code) { switch (error_code) { case SPDY_NO_ERROR: return "NO_ERROR"; - case SPDY_UNKNOWN_CONTROL_TYPE: - return "UNKNOWN_CONTROL_TYPE"; case SPDY_INVALID_CONTROL_FRAME: return "INVALID_CONTROL_FRAME"; case SPDY_CONTROL_PAYLOAD_TOO_LARGE: @@ -145,8 +144,10 @@ const char* SpdyFramer::ErrorCodeToString(int error_code) { return "UNSUPPORTED_VERSION"; case SPDY_DECOMPRESS_FAILURE: return "DECOMPRESS_FAILURE"; + case SPDY_COMPRESS_FAILURE: + return "COMPRESS_FAILURE"; } - return "UNKNOWN_STATE"; + return "UNKNOWN_ERROR"; } size_t SpdyFramer::ProcessInput(const char* data, size_t len) { @@ -228,7 +229,7 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) { SpdyDataFrame data_frame(current_frame_buffer_, false); visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0); } - CHANGE_STATE(SPDY_RESET); + CHANGE_STATE(SPDY_AUTO_RESET); } break; } @@ -254,6 +255,23 @@ void SpdyFramer::ProcessControlFrameHeader() { DCHECK_EQ(SPDY_NO_ERROR, error_code_); DCHECK_LE(SpdyFrame::size(), current_frame_len_); SpdyControlFrame current_control_frame(current_frame_buffer_, false); + + // We check version before we check validity: version can never be 'invalid', + // it can only be unsupported. + if (current_control_frame.version() != kSpdyProtocolVersion) { + set_error(SPDY_UNSUPPORTED_VERSION); + return; + } + + // Next up, check to see if we have valid data. This should be after version + // checking (otherwise if the the type were out of bounds due to a version + // upgrade we would misclassify the error) and before checking the type + // (type can definitely be out of bounds) + if (!current_control_frame.AppearsToBeAValidControlFrame()) { + set_error(SPDY_INVALID_CONTROL_FRAME); + return; + } + // Do some sanity checking on the control frame sizes. switch (current_control_frame.type()) { case SYN_STREAM: @@ -276,20 +294,25 @@ void SpdyFramer::ProcessControlFrameHeader() { CHANGE_STATE(SPDY_AUTO_RESET); return; default: - set_error(SPDY_UNKNOWN_CONTROL_TYPE); + LOG(WARNING) << "Valid spdy control frame with unknown type: " + << current_control_frame.type() + << ". This should never happen"; + DCHECK(false); + set_error(SPDY_INVALID_CONTROL_FRAME); break; } // We only support version 1 of this protocol. - if (current_control_frame.version() != kSpdyProtocolVersion) + if (current_control_frame.version() != kSpdyProtocolVersion) { set_error(SPDY_UNSUPPORTED_VERSION); + return; + } remaining_control_payload_ = current_control_frame.length(); - if (remaining_control_payload_ > kControlFrameBufferMaxSize) + if (remaining_control_payload_ > kControlFrameBufferMaxSize) { set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); - - if (error_code_) return; + } ExpandControlFrameBuffer(remaining_control_payload_); CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD); @@ -336,7 +359,7 @@ size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) { return NULL; size_t decompressed_max_size = amount_to_forward * 100; - scoped_ptr<char> decompressed(new char[decompressed_max_size]); + scoped_array<char> decompressed(new char[decompressed_max_size]); decompressor_->next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data)); decompressor_->avail_in = amount_to_forward; @@ -389,6 +412,7 @@ void SpdyFramer::ExpandControlFrameBuffer(size_t size) { int alloc_size = size + SpdyFrame::size(); char* new_buffer = new char[alloc_size]; memcpy(new_buffer, current_frame_buffer_, current_frame_len_); + delete [] current_frame_buffer_; current_frame_capacity_ = alloc_size; current_frame_buffer_ = new_buffer; } @@ -495,7 +519,7 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id, frame.WriteString(it->second); } - // Write the length + // Write the length and flags. size_t length = frame.length() - SpdyFrame::size(); DCHECK(length < static_cast<size_t>(kLengthMask)); FlagsAndLength flags_length; @@ -543,7 +567,7 @@ SpdyControlFrame* SpdyFramer::CreateNopFrame() { static const int kCompressorLevel = Z_DEFAULT_COMPRESSION; // This is just a hacked dictionary to use for shrinking HTTP-like headers. // TODO(mbelshe): Use a scientific methodology for computing the dictionary. -static const char dictionary[] = +const char SpdyFramer::kDictionary[] = "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" @@ -557,6 +581,8 @@ static const char dictionary[] = "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" ".1statusversionurl"; +const int SpdyFramer::kDictionarySize = arraysize(kDictionary); + static uLong dictionary_id = 0; bool SpdyFramer::InitializeCompressor() { @@ -569,8 +595,8 @@ bool SpdyFramer::InitializeCompressor() { int success = deflateInit(compressor_.get(), kCompressorLevel); if (success == Z_OK) success = deflateSetDictionary(compressor_.get(), - reinterpret_cast<const Bytef*>(dictionary), - sizeof(dictionary)); + reinterpret_cast<const Bytef*>(kDictionary), + kDictionarySize); if (success != Z_OK) compressor_.reset(NULL); return success == Z_OK; @@ -588,8 +614,8 @@ bool SpdyFramer::InitializeDecompressor() { if (dictionary_id == 0) { dictionary_id = adler32(0L, Z_NULL, 0); dictionary_id = adler32(dictionary_id, - reinterpret_cast<const Bytef*>(dictionary), - sizeof(dictionary)); + reinterpret_cast<const Bytef*>(kDictionary), + kDictionarySize); } int success = inflateInit(decompressor_.get()); @@ -602,6 +628,7 @@ bool SpdyFramer::GetFrameBoundaries(const SpdyFrame* frame, int* payload_length, int* header_length, const char** payload) const { + size_t frame_size; if (frame->is_control_frame()) { const SpdyControlFrame* control_frame = reinterpret_cast<const SpdyControlFrame*>(frame); @@ -611,8 +638,9 @@ bool SpdyFramer::GetFrameBoundaries(const SpdyFrame* frame, { const SpdySynStreamControlFrame *syn_frame = reinterpret_cast<const SpdySynStreamControlFrame*>(frame); + frame_size = SpdySynStreamControlFrame::size(); *payload_length = syn_frame->header_block_len(); - *header_length = syn_frame->size(); + *header_length = frame_size; *payload = frame->data() + *header_length; } break; @@ -621,7 +649,8 @@ bool SpdyFramer::GetFrameBoundaries(const SpdyFrame* frame, return false; // We can't compress this frame! } } else { - *header_length = SpdyFrame::size(); + frame_size = SpdyFrame::size(); + *header_length = frame_size; *payload_length = frame->length(); *payload = frame->data() + SpdyFrame::size(); } @@ -727,8 +756,8 @@ SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame* frame) { if (rv == Z_NEED_DICT) { // Need to try again with the right dictionary. if (decompressor_->adler == dictionary_id) { - rv = inflateSetDictionary(decompressor_.get(), (const Bytef*)dictionary, - sizeof(dictionary)); + rv = inflateSetDictionary(decompressor_.get(), (const Bytef*)kDictionary, + kDictionarySize); if (rv == Z_OK) rv = inflate(decompressor_.get(), Z_SYNC_FLUSH); } diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h index c431f67..8b129ea 100644 --- a/net/spdy/spdy_framer.h +++ b/net/spdy/spdy_framer.h @@ -59,7 +59,7 @@ class SpdyFramerVisitorInterface { // |len| The length of the data buffer. // When the other side has finished sending data on this stream, // this method will be called with a zero-length buffer. - virtual void OnStreamFrameData(spdy::SpdyStreamId stream_id, + virtual void OnStreamFrameData(SpdyStreamId stream_id, const char* data, size_t len) = 0; }; @@ -84,12 +84,14 @@ class SpdyFramer { // SPDY error codes. enum SpdyError { SPDY_NO_ERROR, - SPDY_UNKNOWN_CONTROL_TYPE, // Control frame is an unknown type. SPDY_INVALID_CONTROL_FRAME, // Control frame is mal-formatted. SPDY_CONTROL_PAYLOAD_TOO_LARGE, // Control frame payload was too large. SPDY_ZLIB_INIT_FAILURE, // The Zlib library could not initialize. SPDY_UNSUPPORTED_VERSION, // Control frame has unsupported version. SPDY_DECOMPRESS_FAILURE, // There was an error decompressing. + SPDY_COMPRESS_FAILURE, // There was an error compressing. + + LAST_ERROR, // Must be the last entry in the enum. }; // Create a new Framer. @@ -181,24 +183,29 @@ class SpdyFramer { // Compresses a SpdyFrame. // On success, returns a new SpdyFrame with the payload compressed. // Compression state is maintained as part of the SpdyFramer. - // Returned frame must be freed with free(). + // Returned frame must be freed with "delete". // 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 free(). + // 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); // For debugging. static const char* StateToString(int state); static const char* ErrorCodeToString(int error_code); + // Export the compression dictionary + static const char kDictionary[]; + static const int kDictionarySize; + protected: FRIEND_TEST(SpdyFramerTest, HeaderBlockBarfsOnOutOfOrderHeaders); friend class net::SpdyNetworkTransactionTest; diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h index 988d08d..f82ed11 100644 --- a/net/spdy/spdy_protocol.h +++ b/net/spdy/spdy_protocol.h @@ -15,7 +15,7 @@ #include "base/basictypes.h" #include "base/logging.h" -#include "spdy_bitmasks.h" // cross-google3 directory naming. +#include "net/spdy/spdy_bitmasks.h" // Data Frame Format // +----------------------------------+ @@ -93,7 +93,8 @@ enum SpdyControlType { SYN_STREAM = 1, SYN_REPLY, FIN_STREAM, - NOOP + NOOP, + NUM_CONTROL_FRAME_TYPES }; // Flags on data packets @@ -109,10 +110,21 @@ enum SpdyControlFlags { CONTROL_FLAG_FIN = 1 }; -// A Spdy stream id is a 31 bit entity. +// Status codes, as used in control frames (primarily FIN_STREAM). +enum SpdyStatusCodes { + INVALID = 0, + PROTOCOL_ERROR = 1, + INVALID_STREAM = 2, + REFUSED_STREAM = 3 +}; + +// A SPDY stream id is a 31 bit entity. typedef uint32 SpdyStreamId; -// Spdy Priorities. (there are only 2 bits) +// A SPDY priority is a number between 0 and 4. +typedef uint8 SpdyPriority; + +// SPDY Priorities. (there are only 2 bits) #define SPDY_PRIORITY_LOWEST 3 #define SPDY_PRIORITY_HIGHEST 0 @@ -130,7 +142,7 @@ union FlagsAndLength { uint32 length_; // 24 bits }; -// The basic Spdy Frame structure. +// The basic SPDY Frame structure. struct SpdyFrameBlock { union { struct { @@ -146,12 +158,15 @@ struct SpdyFrameBlock { // A Control Frame structure. struct SpdyControlFrameBlock : SpdyFrameBlock { + // Note: technically, this probably should be moved to the + // various control frame subclasses. Not all control + // frames will always have stream_ids. SpdyStreamId stream_id_; }; // A SYN_STREAM Control Frame structure. struct SpdySynStreamControlFrameBlock : SpdyControlFrameBlock { - uint8 priority_; + SpdyPriority priority_; uint8 unused_; }; @@ -168,7 +183,7 @@ struct SpdyFinStreamControlFrameBlock : SpdyControlFrameBlock { #pragma pack(pop) // ------------------------------------------------------------------------- -// Wrapper classes for various Spdy frames. +// Wrapper classes for various SPDY frames. // All Spdy Frame types derive from this SpdyFrame class. class SpdyFrame { @@ -225,7 +240,6 @@ class SpdyFrame { } // Returns the size of the SpdyFrameBlock structure. - // Note: this is not the size of the SpdyFrame class. // Every SpdyFrame* class has a static size() method for accessing // the size of the data structure which will be sent over the wire. // Note: this is not the same as sizeof(SpdyFrame). @@ -275,21 +289,42 @@ class SpdyControlFrame : public SpdyFrame { : SpdyFrame(data, owns_buffer) {} virtual ~SpdyControlFrame() {} + // Callers can use this method to check if the frame appears to be a valid + // frame. Does not guarantee that there are no errors. + bool AppearsToBeAValidControlFrame() const { + // Right now we only check if the frame has an out-of-bounds type. + uint16 type = ntohs(block()->control_.type_); + return (type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES); + } + uint16 version() const { const int kVersionMask = 0x7fff; return ntohs(block()->control_.version_) & kVersionMask; } + + void set_version(uint16 version) { + const uint16 kControlBit = 0x80; + DCHECK_EQ(0, version & kControlBit); + mutable_block()->control_.version_ = kControlBit | htons(version); + } + SpdyControlType type() const { uint16 type = ntohs(block()->control_.type_); - DCHECK(type >= SYN_STREAM && type <= NOOP); + DCHECK(type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES); return static_cast<SpdyControlType>(type); } + + void set_type(SpdyControlType type) { + DCHECK(type >= SYN_STREAM && type < NUM_CONTROL_FRAME_TYPES); + mutable_block()->control_.type_ = htons(type); + } + SpdyStreamId stream_id() const { return ntohl(block()->stream_id_) & kStreamIdMask; } void set_stream_id(SpdyStreamId id) { - block()->stream_id_ = htonl(id & kStreamIdMask); + mutable_block()->stream_id_ = htonl(id & kStreamIdMask); } // Returns the size of the SpdyControlFrameBlock structure. @@ -297,7 +332,10 @@ class SpdyControlFrame : public SpdyFrame { static size_t size() { return sizeof(SpdyControlFrameBlock); } private: - struct SpdyControlFrameBlock* block() const { + const struct SpdyControlFrameBlock* block() const { + return static_cast<SpdyControlFrameBlock*>(frame_); + } + struct SpdyControlFrameBlock* mutable_block() { return static_cast<SpdyControlFrameBlock*>(frame_); } DISALLOW_COPY_AND_ASSIGN(SpdyControlFrame); @@ -311,7 +349,9 @@ class SpdySynStreamControlFrame : public SpdyControlFrame { : SpdyControlFrame(data, owns_buffer) {} virtual ~SpdySynStreamControlFrame() {} - uint8 priority() const { return (block()->priority_ & kPriorityMask) >> 6; } + SpdyPriority priority() const { + return (block()->priority_ & kPriorityMask) >> 6; + } // The number of bytes in the header block beyond the frame header length. int header_block_len() const { @@ -327,7 +367,10 @@ class SpdySynStreamControlFrame : public SpdyControlFrame { static size_t size() { return sizeof(SpdySynStreamControlFrameBlock); } private: - struct SpdySynStreamControlFrameBlock* block() const { + const struct SpdySynStreamControlFrameBlock* block() const { + return static_cast<SpdySynStreamControlFrameBlock*>(frame_); + } + struct SpdySynStreamControlFrameBlock* mutable_block() { return static_cast<SpdySynStreamControlFrameBlock*>(frame_); } DISALLOW_COPY_AND_ASSIGN(SpdySynStreamControlFrame); @@ -354,7 +397,10 @@ class SpdySynReplyControlFrame : public SpdyControlFrame { static size_t size() { return sizeof(SpdySynReplyControlFrameBlock); } private: - struct SpdySynReplyControlFrameBlock* block() const { + const struct SpdySynReplyControlFrameBlock* block() const { + return static_cast<SpdySynReplyControlFrameBlock*>(frame_); + } + struct SpdySynReplyControlFrameBlock* mutable_block() { return static_cast<SpdySynReplyControlFrameBlock*>(frame_); } DISALLOW_COPY_AND_ASSIGN(SpdySynReplyControlFrame); @@ -369,14 +415,17 @@ class SpdyFinStreamControlFrame : public SpdyControlFrame { virtual ~SpdyFinStreamControlFrame() {} uint32 status() const { return ntohl(block()->status_); } - void set_status(uint32 status) { block()->status_ = htonl(status); } + void set_status(uint32 status) { mutable_block()->status_ = htonl(status); } // Returns the size of the SpdyFinStreamControlFrameBlock structure. // Note: this is not the size of the SpdyFinStreamControlFrame class. static size_t size() { return sizeof(SpdyFinStreamControlFrameBlock); } private: - struct SpdyFinStreamControlFrameBlock* block() const { + const struct SpdyFinStreamControlFrameBlock* block() const { + return static_cast<SpdyFinStreamControlFrameBlock*>(frame_); + } + struct SpdyFinStreamControlFrameBlock* mutable_block() { return static_cast<SpdyFinStreamControlFrameBlock*>(frame_); } DISALLOW_COPY_AND_ASSIGN(SpdyFinStreamControlFrame); |