summaryrefslogtreecommitdiffstats
path: root/net/spdy
diff options
context:
space:
mode:
authormbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-09 18:35:40 +0000
committermbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-09 18:35:40 +0000
commit592ca909efa35c0000b349285b059700ae543ee4 (patch)
tree76e6308199862df45804c70e99b23edafcdc85d1 /net/spdy
parent75a2c3b76edcaba820e96e5e202a7cf5c2f5f088 (diff)
downloadchromium_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.cc71
-rw-r--r--net/spdy/spdy_framer.h15
-rw-r--r--net/spdy/spdy_protocol.h81
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);