summaryrefslogtreecommitdiffstats
path: root/net/spdy/spdy_framer.cc
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-04 00:01:57 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-04 00:01:57 +0000
commit8ac2a02fd8f0e4355d70ae6c51d2c1c51f92b64a (patch)
treeab3f7ed18f31dedd18e9ea86cb77e400923c325b /net/spdy/spdy_framer.cc
parent03101106c90fb094efa760200521bcc6dbf7586e (diff)
downloadchromium_src-8ac2a02fd8f0e4355d70ae6c51d2c1c51f92b64a.zip
chromium_src-8ac2a02fd8f0e4355d70ae6c51d2c1c51f92b64a.tar.gz
chromium_src-8ac2a02fd8f0e4355d70ae6c51d2c1c51f92b64a.tar.bz2
Merge spdy_framer changes from server.
R=willchan TEST=network unit tests Review URL: http://codereview.chromium.org/8437098 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108585 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy/spdy_framer.cc')
-rw-r--r--net/spdy/spdy_framer.cc1522
1 files changed, 755 insertions, 767 deletions
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index 963ae43..29a1565 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -20,75 +20,25 @@
#include "third_party/zlib/zlib.h"
#endif
-namespace {
-
-// 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.
-const int kCompressorLevel = 9;
-const int kCompressorWindowSizeInBits = 11;
-const int kCompressorMemLevel = 1;
-
-// Adler ID for the SPDY header compressor dictionary.
-uLong dictionary_id = 0;
-
-} // namespace
-
namespace spdy {
-// This is just a hacked dictionary to use for shrinking HTTP-like headers.
-// TODO(mbelshe): Use a scientific methodology for computing the dictionary.
-const char SpdyFramer::kDictionary[] =
- "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
- "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
- "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
- "-agent10010120020120220320420520630030130230330430530630740040140240340440"
- "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
- "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
- "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
- "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
- "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
- "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
- "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
- "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
- ".1statusversionurl";
-const int SpdyFramer::kDictionarySize = arraysize(kDictionary);
-
-// 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 = 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.
-size_t SpdyFramer::kControlFrameBufferMaxSize = 64 * 1024;
-
-const SpdyStreamId SpdyFramer::kInvalidStream = -1;
-const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
-
-#ifdef DEBUG_SPDY_STATE_CHANGES
-#define CHANGE_STATE(newstate) \
-{ \
- do { \
- LOG(INFO) << "Changing state from: " \
- << StateToString(state_) \
- << " to " << StateToString(newstate) << "\n"; \
- state_ = newstate; \
- } while (false); \
+// Compute the id of our dictionary so that we know we're using the
+// right one when asked for it.
+uLong CalculateDictionaryId() {
+ uLong initial_value = adler32(0L, Z_NULL, 0);
+ return adler32(initial_value,
+ reinterpret_cast<const Bytef*>(SpdyFramer::kDictionary),
+ SpdyFramer::kDictionarySize);
}
-#else
-#define CHANGE_STATE(newstate) (state_ = newstate)
-#endif
+
+// Adler ID for the SPDY header compressor dictionary.
+const uLong kDictionaryId = CalculateDictionaryId();
int DecompressHeaderBlockInZStream(z_stream* decompressor) {
int rv = inflate(decompressor, Z_SYNC_FLUSH);
if (rv == Z_NEED_DICT) {
// Need to try again with the right dictionary.
- if (decompressor->adler == dictionary_id) {
+ if (decompressor->adler == kDictionaryId) {
rv = inflateSetDictionary(decompressor,
(const Bytef*)SpdyFramer::kDictionary,
SpdyFramer::kDictionarySize);
@@ -136,6 +86,37 @@ FlagsAndLength CreateFlagsAndLength(SpdyControlFlags flags, size_t length) {
return flags_length;
}
+// By default is compression on or off.
+bool SpdyFramer::compression_default_ = true;
+
+// 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 = 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.
+size_t SpdyFramer::kControlFrameBufferMaxSize = 64 * 1024;
+
+int SpdyFramer::spdy_version_ = kSpdyProtocolVersion;
+
+const SpdyStreamId SpdyFramer::kInvalidStream = -1;
+const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
+
+#ifdef DEBUG_SPDY_STATE_CHANGES
+#define CHANGE_STATE(newstate) \
+{ \
+ do { \
+ LOG(INFO) << "Changing state from: " \
+ << StateToString(state_) \
+ << " to " << StateToString(newstate) << "\n"; \
+ state_ = newstate; \
+ } while (false); \
+}
+#else
+#define CHANGE_STATE(newstate) (state_ = newstate)
+#endif
+
SpdyFramer::SpdyFramer()
: state_(SPDY_RESET),
error_code_(SPDY_NO_ERROR),
@@ -147,7 +128,8 @@ SpdyFramer::SpdyFramer()
current_frame_capacity_(0),
validate_control_frame_sizes_(true),
enable_compression_(compression_default_),
- visitor_(NULL) {
+ visitor_(NULL),
+ display_protocol_("SPDY") {
}
SpdyFramer::~SpdyFramer() {
@@ -161,6 +143,81 @@ SpdyFramer::~SpdyFramer() {
delete [] current_frame_buffer_;
}
+void SpdyFramer::Reset() {
+ state_ = SPDY_RESET;
+ error_code_ = SPDY_NO_ERROR;
+ remaining_data_ = 0;
+ remaining_control_payload_ = 0;
+ remaining_control_header_ = 0;
+ current_frame_len_ = 0;
+ // TODO(hkhalil): Remove once initial_size == kControlFrameBufferInitialSize.
+ size_t initial_size = kControlFrameBufferInitialSize;
+ if (!enable_compression_) {
+ initial_size = kUncompressedControlFrameBufferInitialSize;
+ }
+ if (current_frame_capacity_ != initial_size) {
+ delete [] current_frame_buffer_;
+ current_frame_buffer_ = 0;
+ current_frame_capacity_ = 0;
+ ExpandControlFrameBuffer(initial_size);
+ }
+}
+
+const char* SpdyFramer::StateToString(int state) {
+ switch (state) {
+ case SPDY_ERROR:
+ return "ERROR";
+ case SPDY_DONE:
+ return "DONE";
+ case SPDY_AUTO_RESET:
+ return "AUTO_RESET";
+ case SPDY_RESET:
+ return "RESET";
+ case SPDY_READING_COMMON_HEADER:
+ return "READING_COMMON_HEADER";
+ case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
+ return "INTERPRET_CONTROL_FRAME_COMMON_HEADER";
+ case SPDY_CONTROL_FRAME_PAYLOAD:
+ return "CONTROL_FRAME_PAYLOAD";
+ case SPDY_IGNORE_REMAINING_PAYLOAD:
+ return "IGNORE_REMAINING_PAYLOAD";
+ case SPDY_FORWARD_STREAM_FRAME:
+ return "FORWARD_STREAM_FRAME";
+ case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK:
+ return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK";
+ case SPDY_CONTROL_FRAME_HEADER_BLOCK:
+ return "SPDY_CONTROL_FRAME_HEADER_BLOCK";
+ }
+ return "UNKNOWN_STATE";
+}
+
+void SpdyFramer::set_error(SpdyError error) {
+ DCHECK(visitor_);
+ error_code_ = error;
+ CHANGE_STATE(SPDY_ERROR);
+ visitor_->OnError(this);
+}
+
+const char* SpdyFramer::ErrorCodeToString(int error_code) {
+ switch (error_code) {
+ case SPDY_NO_ERROR:
+ return "NO_ERROR";
+ case SPDY_INVALID_CONTROL_FRAME:
+ return "INVALID_CONTROL_FRAME";
+ case SPDY_CONTROL_PAYLOAD_TOO_LARGE:
+ return "CONTROL_PAYLOAD_TOO_LARGE";
+ case SPDY_ZLIB_INIT_FAILURE:
+ return "ZLIB_INIT_FAILURE";
+ case SPDY_UNSUPPORTED_VERSION:
+ return "UNSUPPORTED_VERSION";
+ case SPDY_DECOMPRESS_FAILURE:
+ return "DECOMPRESS_FAILURE";
+ case SPDY_COMPRESS_FAILURE:
+ return "COMPRESS_FAILURE";
+ }
+ return "UNKNOWN_ERROR";
+}
+
const char* SpdyFramer::StatusCodeToString(int status_code) {
switch (status_code) {
case INVALID:
@@ -289,84 +346,142 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
return original_len - len;
}
-void SpdyFramer::Reset() {
- state_ = SPDY_RESET;
- error_code_ = SPDY_NO_ERROR;
- remaining_data_ = 0;
- remaining_control_payload_ = 0;
- remaining_control_header_ = 0;
- current_frame_len_ = 0;
- if (current_frame_capacity_ != kControlFrameBufferInitialSize) {
- delete [] current_frame_buffer_;
- current_frame_buffer_ = 0;
- current_frame_capacity_ = 0;
- ExpandControlFrameBuffer(kControlFrameBufferInitialSize);
- }
+size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
+ // This should only be called when we're in the SPDY_READING_COMMON_HEADER
+ // state.
+ DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER);
+
+ size_t original_len = len;
+ SpdyFrame current_frame(current_frame_buffer_, false);
+
+ do {
+ if (current_frame_len_ < SpdyFrame::size()) {
+ size_t bytes_desired = SpdyFrame::size() - current_frame_len_;
+ UpdateCurrentFrameBuffer(&data, &len, bytes_desired);
+ // Check for an empty data frame.
+ if (current_frame_len_ == SpdyFrame::size() &&
+ !current_frame.is_control_frame() &&
+ current_frame.length() == 0) {
+ if (current_frame.flags() & CONTROL_FLAG_FIN) {
+ SpdyDataFrame data_frame(current_frame_buffer_, false);
+ visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0);
+ }
+ CHANGE_STATE(SPDY_AUTO_RESET);
+ }
+ break;
+ }
+ remaining_data_ = current_frame.length();
+
+ // This is just a sanity check for help debugging early frame errors.
+ if (remaining_data_ > 1000000u) {
+ LOG(WARNING) <<
+ "Unexpectedly large frame. Spdy session is likely corrupt.";
+ }
+
+ // if we're here, then we have the common header all received.
+ if (!current_frame.is_control_frame())
+ CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
+ else
+ CHANGE_STATE(SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER);
+ } while (false);
+
+ return original_len - len;
}
-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 && type != HEADERS)
- return false;
+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);
- // Find the header data within the control frame.
- scoped_ptr<SpdyFrame> decompressed_frame(DecompressFrame(*frame));
- if (!decompressed_frame.get())
- return false;
+ // We check version before we check validity: version can never be 'invalid',
+ // it can only be unsupported.
+ if (current_control_frame.version() != spdy_version_) {
+ set_error(SPDY_UNSUPPORTED_VERSION);
+ return;
+ }
- const char *header_data = NULL;
- int header_length = 0;
+ // 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;
+ }
- switch (type) {
- case SYN_STREAM:
- {
- SpdySynStreamControlFrame syn_frame(decompressed_frame->data(), false);
- header_data = syn_frame.header_block();
- header_length = syn_frame.header_block_len();
- }
- break;
- case SYN_REPLY:
- {
- SpdySynReplyControlFrame syn_frame(decompressed_frame->data(), false);
- header_data = syn_frame.header_block();
- 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;
+ if (current_control_frame.type() == NOOP) {
+ DLOG(INFO) << "NOOP control frame found. Ignoring.";
+ CHANGE_STATE(SPDY_AUTO_RESET);
+ return;
}
- SpdyFrameBuilder builder(header_data, header_length);
- void* iter = NULL;
- uint16 num_headers;
- if (builder.ReadUInt16(&iter, &num_headers)) {
- int index;
- for (index = 0; index < num_headers; ++index) {
- std::string name;
- std::string value;
- if (!builder.ReadString(&iter, &name))
+ if (validate_control_frame_sizes_) {
+ // Do some sanity checking on the control frame sizes.
+ switch (current_control_frame.type()) {
+ case SYN_STREAM:
+ if (current_control_frame.length() <
+ SpdySynStreamControlFrame::size() - SpdyControlFrame::size())
+ set_error(SPDY_INVALID_CONTROL_FRAME);
break;
- if (!builder.ReadString(&iter, &value))
+ case SYN_REPLY:
+ if (current_control_frame.length() <
+ SpdySynReplyControlFrame::size() - SpdyControlFrame::size())
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ break;
+ case RST_STREAM:
+ if (current_control_frame.length() !=
+ 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 GOAWAY:
+ if (current_control_frame.length() !=
+ SpdyGoAwayControlFrame::size() - SpdyFrame::size())
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ break;
+ case HEADERS:
+ if (current_control_frame.length() <
+ SpdyHeadersControlFrame::size() - SpdyControlFrame::size())
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ break;
+ case WINDOW_UPDATE:
+ if (current_control_frame.length() !=
+ SpdyWindowUpdateControlFrame::size() - SpdyControlFrame::size())
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ break;
+ case PING:
+ if (current_control_frame.length() !=
+ SpdyPingControlFrame::size() - SpdyControlFrame::size())
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ break;
+ default:
+ LOG(WARNING) << "Valid " << display_protocol_
+ << " control frame with unhandled type: "
+ << current_control_frame.type();
+ DCHECK(false);
+ set_error(SPDY_INVALID_CONTROL_FRAME);
break;
- if (!name.size() || !value.size())
- return false;
- if (block->find(name) == block->end()) {
- (*block)[name] = value;
- } else {
- return false;
- }
}
- return index == num_headers &&
- iter == header_data + header_length;
}
- return false;
+
+ // We only support version 1 of this protocol.
+ if (current_control_frame.version() != spdy_version_) {
+ set_error(SPDY_UNSUPPORTED_VERSION);
+ return;
+ }
+
+ remaining_control_payload_ = current_control_frame.length();
+ if (remaining_control_payload_ > kControlFrameBufferMaxSize) {
+ set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
+ return;
+ }
+
+ ExpandControlFrameBuffer(remaining_control_payload_);
+ CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD);
}
size_t SpdyFramer::UpdateCurrentFrameBuffer(const char** data, size_t* len,
@@ -419,7 +534,7 @@ size_t SpdyFramer::NewProcessControlFrameHeaderBlock(const char* data,
DCHECK_GT(process_bytes, 0u);
if (enable_compression_) {
- processed_successfully = IncrementallyDecompressControlFrameHeaderData(
+ processed_successfully = NewIncrementallyDecompressControlFrameHeaderData(
&control_frame, data, process_bytes);
} else {
processed_successfully = IncrementallyDeliverControlFrameHeaderData(
@@ -503,6 +618,107 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
return original_data_len - data_len;
}
+size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
+ size_t original_len = len;
+ do {
+ if (remaining_control_payload_) {
+ size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
+ remaining_control_payload_);
+ remaining_control_payload_ -= bytes_read;
+ remaining_data_ -= bytes_read;
+ if (remaining_control_payload_)
+ break;
+ }
+ SpdyControlFrame control_frame(current_frame_buffer_, false);
+ visitor_->OnControl(&control_frame);
+
+ // If this is a FIN, tell the caller.
+ if (control_frame.type() == SYN_REPLY &&
+ control_frame.flags() & CONTROL_FLAG_FIN) {
+ visitor_->OnStreamFrameData(reinterpret_cast<SpdySynReplyControlFrame*>(
+ &control_frame)->stream_id(),
+ NULL, 0);
+ }
+
+ CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD);
+ } while (false);
+ return original_len - len;
+}
+
+size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
+ size_t original_len = len;
+
+ SpdyDataFrame current_data_frame(current_frame_buffer_, false);
+ if (remaining_data_) {
+ size_t amount_to_forward = std::min(remaining_data_, len);
+ if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) {
+ if (current_data_frame.flags() & DATA_FLAG_COMPRESSED) {
+ z_stream* decompressor =
+ GetStreamDecompressor(current_data_frame.stream_id());
+ if (!decompressor)
+ return 0;
+
+ size_t decompressed_max_size = amount_to_forward * 100;
+ 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;
+ decompressor->next_out =
+ reinterpret_cast<Bytef*>(decompressed.get());
+ decompressor->avail_out = decompressed_max_size;
+
+ int rv = inflate(decompressor, Z_SYNC_FLUSH);
+ if (rv != Z_OK) {
+ LOG(WARNING) << "inflate failure: " << rv;
+ set_error(SPDY_DECOMPRESS_FAILURE);
+ return 0;
+ }
+ size_t decompressed_size = decompressed_max_size -
+ decompressor->avail_out;
+
+ // Only inform the visitor if there is data.
+ if (decompressed_size)
+ visitor_->OnStreamFrameData(current_data_frame.stream_id(),
+ decompressed.get(),
+ decompressed_size);
+ amount_to_forward -= decompressor->avail_in;
+ } else {
+ // The data frame was not compressed.
+ // Only inform the visitor if there is data.
+ if (amount_to_forward)
+ visitor_->OnStreamFrameData(current_data_frame.stream_id(),
+ data, amount_to_forward);
+ }
+ }
+ data += amount_to_forward;
+ len -= amount_to_forward;
+ remaining_data_ -= amount_to_forward;
+
+ // If the FIN flag is set, and there is no more data in this data
+ // frame, inform the visitor of EOF via a 0-length data frame.
+ if (!remaining_data_ &&
+ current_data_frame.flags() & DATA_FLAG_FIN) {
+ visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0);
+ CleanupDecompressorForStream(current_data_frame.stream_id());
+ }
+ } else {
+ CHANGE_STATE(SPDY_AUTO_RESET);
+ }
+ return original_len - len;
+}
+
+void SpdyFramer::ExpandControlFrameBuffer(size_t size) {
+ size_t alloc_size = size + SpdyFrame::size();
+ DCHECK_LE(alloc_size, kControlFrameBufferMaxSize);
+ if (alloc_size <= current_frame_capacity_)
+ return;
+ 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;
+}
+
/* static */
bool SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data,
size_t header_length,
@@ -529,39 +745,115 @@ bool SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data,
return false;
}
+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 && type != HEADERS)
+ return false;
+
+ // Find the header data within the control frame.
+ scoped_ptr<SpdyFrame> decompressed_frame(DecompressFrame(*frame));
+ if (!decompressed_frame.get())
+ return false;
+
+ const char *header_data = NULL;
+ int header_length = 0;
+
+ switch (type) {
+ case SYN_STREAM:
+ {
+ SpdySynStreamControlFrame syn_frame(decompressed_frame->data(), false);
+ header_data = syn_frame.header_block();
+ header_length = syn_frame.header_block_len();
+ }
+ break;
+ case SYN_REPLY:
+ {
+ SpdySynReplyControlFrame syn_frame(decompressed_frame->data(), false);
+ header_data = syn_frame.header_block();
+ 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;
+ for (index = 0; index < num_headers; ++index) {
+ std::string name;
+ std::string value;
+ if (!builder.ReadString(&iter, &name))
+ break;
+ if (!builder.ReadString(&iter, &value))
+ break;
+ if (!name.size() || !value.size())
+ return false;
+ if (block->find(name) == block->end()) {
+ (*block)[name] = value;
+ } else {
+ return false;
+ }
+ }
+ return index == num_headers &&
+ iter == header_data + header_length;
+ }
+ return false;
+}
+
+/* static */
+bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame,
+ SpdySettings* settings) {
+ DCHECK_EQ(frame->type(), SETTINGS);
+ DCHECK(settings);
+
+ SpdyFrameBuilder parser(frame->header_block(), frame->header_block_len());
+ void* iter = NULL;
+ for (size_t index = 0; index < frame->num_entries(); ++index) {
+ uint32 id;
+ uint32 value;
+ if (!parser.ReadUInt32(&iter, &id))
+ return false;
+ if (!parser.ReadUInt32(&iter, &value))
+ return false;
+ settings->insert(settings->end(), std::make_pair(id, value));
+ }
+ return true;
+}
+
SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
SpdyStreamId stream_id, SpdyStreamId associated_stream_id, int priority,
SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) {
- SpdyFrameBuilder frame;
-
DCHECK_GT(stream_id, static_cast<SpdyStreamId>(0));
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask);
+ // Find our length.
+ size_t expected_frame_size = SpdySynStreamControlFrame::size() +
+ GetSerializedLength(headers);
+
+ // Create our FlagsAndLength.
+ FlagsAndLength flags_length = CreateFlagsAndLength(
+ flags,
+ expected_frame_size - SpdyFrame::size());
+
+ SpdyFrameBuilder frame(expected_frame_size);
frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(SYN_STREAM);
- frame.WriteUInt32(0); // Placeholder for the length and flags
+ frame.WriteBytes(&flags_length, sizeof(flags_length));
frame.WriteUInt32(stream_id);
frame.WriteUInt32(associated_stream_id);
frame.WriteUInt16(ntohs(priority) << 6); // Priority.
-
- frame.WriteUInt16(headers->size()); // Number of headers.
- SpdyHeaderBlock::const_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);
- }
-
- // 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));
+ WriteHeaderBlock(&frame, headers);
scoped_ptr<SpdySynStreamControlFrame> syn_frame(
reinterpret_cast<SpdySynStreamControlFrame*>(frame.take()));
@@ -577,31 +869,22 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id,
DCHECK_GT(stream_id, 0u);
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
- SpdyFrameBuilder frame;
+ // Find our length.
+ size_t expected_frame_size = SpdySynReplyControlFrame::size() +
+ GetSerializedLength(headers);
+ // Create our FlagsAndLength.
+ FlagsAndLength flags_length = CreateFlagsAndLength(
+ flags,
+ expected_frame_size - SpdyFrame::size());
+
+ SpdyFrameBuilder frame(expected_frame_size);
frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(SYN_REPLY);
- frame.WriteUInt32(0); // Placeholder for the length and flags.
+ frame.WriteBytes(&flags_length, sizeof(flags_length));
frame.WriteUInt32(stream_id);
frame.WriteUInt16(0); // Unused
-
- frame.WriteUInt16(headers->size()); // Number of headers.
- SpdyHeaderBlock::const_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);
- }
-
- // 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));
+ WriteHeaderBlock(&frame, headers);
scoped_ptr<SpdySynReplyControlFrame> reply_frame(
reinterpret_cast<SpdySynReplyControlFrame*>(frame.take()));
@@ -620,7 +903,7 @@ SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id,
DCHECK_NE(status, INVALID);
DCHECK_LT(status, NUM_STATUS_CODES);
- SpdyFrameBuilder frame;
+ SpdyFrameBuilder frame(SpdyRstStreamControlFrame::size());
frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(RST_STREAM);
frame.WriteUInt32(8);
@@ -632,7 +915,7 @@ SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id,
/* static */
SpdySettingsControlFrame* SpdyFramer::CreateSettings(
const SpdySettings& values) {
- SpdyFrameBuilder frame;
+ SpdyFrameBuilder frame(SpdySettingsControlFrame::size() + 8 * values.size());
frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(SETTINGS);
size_t settings_size = SpdySettingsControlFrame::size() - SpdyFrame::size() +
@@ -650,7 +933,7 @@ SpdySettingsControlFrame* SpdyFramer::CreateSettings(
/* static */
SpdyNoOpControlFrame* SpdyFramer::CreateNopFrame() {
- SpdyFrameBuilder frame;
+ SpdyFrameBuilder frame(SpdyNoOpControlFrame::size());
frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(NOOP);
frame.WriteUInt32(0);
@@ -659,8 +942,8 @@ SpdyNoOpControlFrame* SpdyFramer::CreateNopFrame() {
/* static */
SpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) {
- SpdyFrameBuilder frame;
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ SpdyFrameBuilder frame(SpdyPingControlFrame::size());
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(PING);
size_t ping_size = SpdyPingControlFrame::size() - SpdyFrame::size();
frame.WriteUInt32(ping_size);
@@ -673,7 +956,7 @@ SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway(
SpdyStreamId last_accepted_stream_id) {
DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask);
- SpdyFrameBuilder frame;
+ SpdyFrameBuilder frame(SpdyGoAwayControlFrame::size());
frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(GOAWAY);
size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::size();
@@ -688,30 +971,23 @@ SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(SpdyStreamId stream_id,
DCHECK_GT(stream_id, 0u);
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
- SpdyFrameBuilder frame;
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ // Find our length.
+ size_t expected_frame_size = SpdyHeadersControlFrame::size() +
+ GetSerializedLength(headers);
+
+ // Create our FlagsAndLength.
+ FlagsAndLength flags_length = CreateFlagsAndLength(
+ flags,
+ expected_frame_size - SpdyFrame::size());
+
+ SpdyFrameBuilder frame(expected_frame_size);
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(HEADERS);
- frame.WriteUInt32(0); // Placeholder for the length and flags.
+ frame.WriteBytes(&flags_length, sizeof(flags_length));
frame.WriteUInt32(stream_id);
frame.WriteUInt16(0); // Unused
-
- frame.WriteUInt16(headers->size()); // Number of headers.
- SpdyHeaderBlock::const_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);
- }
-
- // 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));
+ WriteHeaderBlock(&frame, headers);
+ DCHECK_EQ(static_cast<size_t>(frame.length()), expected_frame_size);
scoped_ptr<SpdyHeadersControlFrame> headers_frame(
reinterpret_cast<SpdyHeadersControlFrame*>(frame.take()));
@@ -731,7 +1007,7 @@ SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
DCHECK_GT(delta_window_size, 0u);
DCHECK_LE(delta_window_size, spdy::kSpdyStreamMaximumWindowSize);
- SpdyFrameBuilder frame;
+ SpdyFrameBuilder frame(SpdyWindowUpdateControlFrame::size());
frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(WINDOW_UPDATE);
size_t window_update_size = SpdyWindowUpdateControlFrame::size() -
@@ -742,33 +1018,13 @@ SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take());
}
-/* static */
-bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame,
- SpdySettings* settings) {
- DCHECK_EQ(frame->type(), SETTINGS);
- DCHECK(settings);
-
- SpdyFrameBuilder parser(frame->header_block(), frame->header_block_len());
- void* iter = NULL;
- for (size_t index = 0; index < frame->num_entries(); ++index) {
- uint32 id;
- uint32 value;
- if (!parser.ReadUInt32(&iter, &id))
- return false;
- if (!parser.ReadUInt32(&iter, &value))
- return false;
- settings->insert(settings->end(), std::make_pair(id, value));
- }
- return true;
-}
-
SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
const char* data,
uint32 len, SpdyDataFlags flags) {
- SpdyFrameBuilder frame;
-
DCHECK_GT(stream_id, 0u);
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
+
+ SpdyFrameBuilder frame(SpdyDataFrame::size() + len);
frame.WriteUInt32(stream_id);
DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask));
@@ -794,6 +1050,31 @@ SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
return rv;
}
+// 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.
+static const int kCompressorLevel = 9;
+static const int kCompressorWindowSizeInBits = 11;
+static const int kCompressorMemLevel = 1;
+
+// This is just a hacked dictionary to use for shrinking HTTP-like headers.
+// TODO(mbelshe): Use a scientific methodology for computing the dictionary.
+const char SpdyFramer::kDictionary[] =
+ "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
+ "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
+ "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
+ "-agent10010120020120220320420520630030130230330430530630740040140240340440"
+ "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
+ "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
+ "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
+ "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
+ "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
+ "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
+ "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
+ "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
+ ".1statusversionurl";
+const int SpdyFramer::kDictionarySize = arraysize(kDictionary);
+
SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) {
if (frame.is_control_frame()) {
return CompressControlFrame(
@@ -810,13 +1091,6 @@ SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) {
return DecompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
}
-SpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) {
- int size = SpdyFrame::size() + frame.length();
- SpdyFrame* new_frame = new SpdyFrame(size);
- memcpy(new_frame->data(), frame.data(), size);
- return new_frame;
-}
-
bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const {
// The important frames to compress are those which contain large
// amounts of compressible data - namely the headers in the SYN_STREAM
@@ -835,280 +1109,6 @@ bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const {
return (data_frame.flags() & DATA_FLAG_COMPRESSED) != 0;
}
-const char* SpdyFramer::StateToString(int state) {
- switch (state) {
- case SPDY_ERROR:
- return "ERROR";
- case SPDY_DONE:
- return "DONE";
- case SPDY_AUTO_RESET:
- return "AUTO_RESET";
- case SPDY_RESET:
- return "RESET";
- case SPDY_READING_COMMON_HEADER:
- return "READING_COMMON_HEADER";
- case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
- return "INTERPRET_CONTROL_FRAME_COMMON_HEADER";
- case SPDY_CONTROL_FRAME_PAYLOAD:
- return "CONTROL_FRAME_PAYLOAD";
- case SPDY_IGNORE_REMAINING_PAYLOAD:
- return "IGNORE_REMAINING_PAYLOAD";
- case SPDY_FORWARD_STREAM_FRAME:
- return "FORWARD_STREAM_FRAME";
- case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK:
- return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK";
- case SPDY_CONTROL_FRAME_HEADER_BLOCK:
- return "SPDY_CONTROL_FRAME_HEADER_BLOCK";
- }
- return "UNKNOWN_STATE";
-}
-
-const char* SpdyFramer::ErrorCodeToString(int error_code) {
- switch (error_code) {
- case SPDY_NO_ERROR:
- return "NO_ERROR";
- case SPDY_INVALID_CONTROL_FRAME:
- return "INVALID_CONTROL_FRAME";
- case SPDY_CONTROL_PAYLOAD_TOO_LARGE:
- return "CONTROL_PAYLOAD_TOO_LARGE";
- case SPDY_ZLIB_INIT_FAILURE:
- return "ZLIB_INIT_FAILURE";
- case SPDY_UNSUPPORTED_VERSION:
- return "UNSUPPORTED_VERSION";
- case SPDY_DECOMPRESS_FAILURE:
- return "DECOMPRESS_FAILURE";
- case SPDY_COMPRESS_FAILURE:
- return "COMPRESS_FAILURE";
- }
- return "UNKNOWN_ERROR";
-}
-
-void SpdyFramer::set_enable_compression(bool value) {
- enable_compression_ = value;
-}
-
-void SpdyFramer::set_enable_compression_default(bool value) {
- compression_default_ = value;
-}
-
-size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
- // This should only be called when we're in the SPDY_READING_COMMON_HEADER
- // state.
- DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER);
-
- size_t original_len = len;
- SpdyFrame current_frame(current_frame_buffer_, false);
-
- do {
- if (current_frame_len_ < SpdyFrame::size()) {
- size_t bytes_desired = SpdyFrame::size() - current_frame_len_;
- UpdateCurrentFrameBuffer(&data, &len, bytes_desired);
- // Check for an empty data frame.
- if (current_frame_len_ == SpdyFrame::size() &&
- !current_frame.is_control_frame() &&
- current_frame.length() == 0) {
- if (current_frame.flags() & CONTROL_FLAG_FIN) {
- SpdyDataFrame data_frame(current_frame_buffer_, false);
- visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0);
- }
- CHANGE_STATE(SPDY_AUTO_RESET);
- }
- break;
- }
- remaining_data_ = current_frame.length();
-
- // This is just a sanity check for help debugging early frame errors.
- if (remaining_data_ > 1000000u) {
- LOG(WARNING) <<
- "Unexpectedly large frame. Spdy session is likely corrupt.";
- }
-
- // if we're here, then we have the common header all received.
- if (!current_frame.is_control_frame())
- CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
- else
- CHANGE_STATE(SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER);
- } while (false);
-
- return original_len - len;
-}
-
-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() != spdy_version_) {
- 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:
- if (current_control_frame.length() <
- SpdySynStreamControlFrame::size() - SpdyControlFrame::size())
- set_error(SPDY_INVALID_CONTROL_FRAME);
- break;
- case SYN_REPLY:
- if (current_control_frame.length() <
- SpdySynReplyControlFrame::size() - SpdyControlFrame::size())
- set_error(SPDY_INVALID_CONTROL_FRAME);
- break;
- case RST_STREAM:
- if (current_control_frame.length() !=
- 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;
- // TODO(hkhalil): Remove NOOP.
- case NOOP:
- // NOOP. Swallow it.
- DLOG(INFO) << "Attempted frame size validation for NOOP. Resetting.";
- CHANGE_STATE(SPDY_AUTO_RESET);
- return;
- case GOAWAY:
- if (current_control_frame.length() !=
- SpdyGoAwayControlFrame::size() - SpdyFrame::size())
- set_error(SPDY_INVALID_CONTROL_FRAME);
- break;
- case HEADERS:
- if (current_control_frame.length() <
- SpdyHeadersControlFrame::size() - SpdyControlFrame::size())
- set_error(SPDY_INVALID_CONTROL_FRAME);
- break;
- case WINDOW_UPDATE:
- if (current_control_frame.length() !=
- SpdyWindowUpdateControlFrame::size() - SpdyControlFrame::size())
- set_error(SPDY_INVALID_CONTROL_FRAME);
- break;
- case PING:
- if (current_control_frame.length() !=
- SpdyPingControlFrame::size() - SpdyControlFrame::size())
- set_error(SPDY_INVALID_CONTROL_FRAME);
- break;
- default:
- LOG(WARNING) << "Valid spdy control frame with unhandled type: "
- << current_control_frame.type();
- DCHECK(false);
- set_error(SPDY_INVALID_CONTROL_FRAME);
- break;
- }
-
- remaining_control_payload_ = current_control_frame.length();
- if (remaining_control_payload_ > kControlFrameBufferMaxSize) {
- set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
- return;
- }
-
- ExpandControlFrameBuffer(remaining_control_payload_);
- CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD);
-}
-
-size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
- size_t original_len = len;
- do {
- if (remaining_control_payload_) {
- size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
- remaining_control_payload_);
- remaining_control_payload_ -= bytes_read;
- remaining_data_ -= bytes_read;
- if (remaining_control_payload_)
- break;
- }
- SpdyControlFrame control_frame(current_frame_buffer_, false);
- visitor_->OnControl(&control_frame);
-
- // If this is a FIN, tell the caller.
- if (control_frame.type() == SYN_REPLY &&
- control_frame.flags() & CONTROL_FLAG_FIN) {
- visitor_->OnStreamFrameData(reinterpret_cast<SpdySynReplyControlFrame*>(
- &control_frame)->stream_id(),
- NULL, 0);
- }
-
- CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD);
- } while (false);
- return original_len - len;
-}
-
-size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
- size_t original_len = len;
-
- SpdyDataFrame current_data_frame(current_frame_buffer_, false);
- if (remaining_data_) {
- size_t amount_to_forward = std::min(remaining_data_, len);
- if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) {
- if (current_data_frame.flags() & DATA_FLAG_COMPRESSED) {
- z_stream* decompressor =
- GetStreamDecompressor(current_data_frame.stream_id());
- if (!decompressor)
- return 0;
-
- size_t decompressed_max_size = amount_to_forward * 100;
- 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;
- decompressor->next_out =
- reinterpret_cast<Bytef*>(decompressed.get());
- decompressor->avail_out = decompressed_max_size;
-
- int rv = inflate(decompressor, Z_SYNC_FLUSH);
- if (rv != Z_OK) {
- LOG(WARNING) << "inflate failure: " << rv;
- set_error(SPDY_DECOMPRESS_FAILURE);
- return 0;
- }
- size_t decompressed_size = decompressed_max_size -
- decompressor->avail_out;
-
- // Only inform the visitor if there is data.
- if (decompressed_size)
- visitor_->OnStreamFrameData(current_data_frame.stream_id(),
- decompressed.get(),
- decompressed_size);
- amount_to_forward -= decompressor->avail_in;
- } else {
- // The data frame was not compressed.
- // Only inform the visitor if there is data.
- if (amount_to_forward)
- visitor_->OnStreamFrameData(current_data_frame.stream_id(),
- data, amount_to_forward);
- }
- }
- data += amount_to_forward;
- len -= amount_to_forward;
- remaining_data_ -= amount_to_forward;
-
- // If the FIN flag is set, and there is no more data in this data
- // frame, inform the visitor of EOF via a 0-length data frame.
- if (!remaining_data_ &&
- current_data_frame.flags() & DATA_FLAG_FIN) {
- visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0);
- CleanupDecompressorForStream(current_data_frame.stream_id());
- }
- } else {
- CHANGE_STATE(SPDY_AUTO_RESET);
- }
- return original_len - len;
-}
-
z_stream* SpdyFramer::GetHeaderCompressor() {
if (header_compressor_.get())
return header_compressor_.get(); // Already initialized.
@@ -1141,15 +1141,6 @@ z_stream* SpdyFramer::GetHeaderDecompressor() {
header_decompressor_.reset(new z_stream);
memset(header_decompressor_.get(), 0, sizeof(z_stream));
- // Compute the id of our dictionary so that we know we're using the
- // right one when asked for it.
- if (dictionary_id == 0) {
- dictionary_id = adler32(0L, Z_NULL, 0);
- dictionary_id = adler32(dictionary_id,
- reinterpret_cast<const Bytef*>(kDictionary),
- kDictionarySize);
- }
-
int success = inflateInit(header_decompressor_.get());
if (success != Z_OK) {
LOG(WARNING) << "inflateInit failure: " << success;
@@ -1196,6 +1187,58 @@ z_stream* SpdyFramer::GetStreamDecompressor(SpdyStreamId stream_id) {
return stream_decompressors_[stream_id] = decompressor.release();
}
+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);
+ switch (control_frame.type()) {
+ case SYN_STREAM:
+ {
+ const SpdySynStreamControlFrame& syn_frame =
+ reinterpret_cast<const SpdySynStreamControlFrame&>(frame);
+ frame_size = SpdySynStreamControlFrame::size();
+ *payload_length = syn_frame.header_block_len();
+ *header_length = frame_size;
+ *payload = frame.data() + *header_length;
+ }
+ break;
+ case SYN_REPLY:
+ {
+ const SpdySynReplyControlFrame& syn_frame =
+ reinterpret_cast<const SpdySynReplyControlFrame&>(frame);
+ frame_size = SpdySynReplyControlFrame::size();
+ *payload_length = syn_frame.header_block_len();
+ *header_length = frame_size;
+ *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!
+ }
+ } else {
+ frame_size = SpdyFrame::size();
+ *header_length = frame_size;
+ *payload_length = frame.length();
+ *payload = frame.data() + SpdyFrame::size();
+ }
+ return true;
+}
+
SpdyControlFrame* SpdyFramer::CompressControlFrame(
const SpdyControlFrame& frame) {
z_stream* compressor = GetHeaderCompressor();
@@ -1222,194 +1265,6 @@ SpdyControlFrame* SpdyFramer::DecompressControlFrame(
DecompressFrameWithZStream(frame, decompressor));
}
-// Incrementally decompress the control frame's header block, feeding the
-// result to the visitor in chunks. Continue this until the visitor
-// indicates that it cannot process any more data, or (more commonly) we
-// run out of data to deliver.
-bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
- const SpdyControlFrame* control_frame) {
- z_stream* decomp = GetHeaderDecompressor();
- int payload_length;
- int header_length;
- const char* payload;
- bool read_successfully = true;
- bool more = true;
- char buffer[kHeaderDataChunkMaxSize];
-
- if (!GetFrameBoundaries(
- *control_frame, &payload_length, &header_length, &payload)) {
- DLOG(ERROR) << "Control frame of type "
- << SpdyFramer::ControlTypeToString(control_frame->type())
- <<" doesn't have headers";
- return false;
- }
- decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
- decomp->avail_in = payload_length;
- const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
- DCHECK_LT(0u, stream_id);
- while (more && read_successfully) {
- decomp->next_out = reinterpret_cast<Bytef*>(buffer);
- decomp->avail_out = arraysize(buffer);
- int rv = DecompressHeaderBlockInZStream(decomp);
- if (rv != Z_OK) {
- set_error(SPDY_DECOMPRESS_FAILURE);
- DLOG(WARNING) << "inflate failure: " << rv;
- more = read_successfully = false;
- } else {
- DCHECK_GT(arraysize(buffer), decomp->avail_out);
- size_t len = arraysize(buffer) - decomp->avail_out;
- read_successfully = visitor_->OnControlFrameHeaderData(stream_id, buffer,
- len);
- if (!read_successfully) {
- // Assume that the problem was the header block was too large for the
- // visitor.
- set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
- }
- more = decomp->avail_in > 0;
- }
- }
- return read_successfully;
-}
-
-// Incrementally decompress the control frame's header block, feeding the
-// result to the visitor in chunks. Continue this until the visitor
-// indicates that it cannot process any more data, or (more commonly) we
-// run out of data to deliver.
-bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
- const SpdyControlFrame* control_frame,
- const char* data,
- size_t len) {
- // Get a decompressor or set error.
- z_stream* decomp = GetHeaderDecompressor();
- if (decomp == NULL) {
- LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers.";
- set_error(SPDY_DECOMPRESS_FAILURE);
- return false;
- }
-
- bool processed_successfully = true;
- char buffer[kHeaderDataChunkMaxSize];
-
- decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
- decomp->avail_in = len;
- const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
- DCHECK_LT(0u, stream_id);
- while (decomp->avail_in > 0 && processed_successfully) {
- decomp->next_out = reinterpret_cast<Bytef*>(buffer);
- decomp->avail_out = arraysize(buffer);
- int rv = DecompressHeaderBlockInZStream(decomp);
- if (rv != Z_OK) {
- set_error(SPDY_DECOMPRESS_FAILURE);
- DLOG(WARNING) << "inflate failure: " << rv;
- processed_successfully = false;
- } else {
- size_t decompressed_len = arraysize(buffer) - decomp->avail_out;
- if (decompressed_len > 0) {
- processed_successfully = visitor_->OnControlFrameHeaderData(
- stream_id, buffer, decompressed_len);
- }
- if (!processed_successfully) {
- // Assume that the problem was the header block was too large for the
- // visitor.
- set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
- }
- }
- }
- return processed_successfully;
-}
-
-bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData(
- const SpdyControlFrame* control_frame, const char* data, size_t len) {
- bool read_successfully = true;
- const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
- DCHECK_LT(0u, stream_id);
- while (read_successfully && len > 0) {
- size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize);
- read_successfully = visitor_->OnControlFrameHeaderData(stream_id, data,
- bytes_to_deliver);
- data += bytes_to_deliver;
- len -= bytes_to_deliver;
- if (!read_successfully) {
- // Assume that the problem was the header block was too large for the
- // visitor.
- set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
- }
- }
- return read_successfully;
-}
-
-size_t SpdyFramer::GetMinimumControlFrameSize(SpdyControlType type) {
- switch (type) {
- case SYN_STREAM:
- return SpdySynStreamControlFrame::size();
- case SYN_REPLY:
- return SpdySynReplyControlFrame::size();
- case RST_STREAM:
- return SpdyRstStreamControlFrame::size();
- case SETTINGS:
- return SpdySettingsControlFrame::size();
- case NOOP:
- return SpdyNoOpControlFrame::size();
- case PING:
- return SpdyPingControlFrame::size();
- case GOAWAY:
- return SpdyGoAwayControlFrame::size();
- case HEADERS:
- return SpdyHeadersControlFrame::size();
- case WINDOW_UPDATE:
- return SpdyWindowUpdateControlFrame::size();
- case NUM_CONTROL_FRAME_TYPES:
- break;
- }
- LOG(ERROR) << "Unknown SPDY control frame type " << type;
- return 0x7FFFFFFF; // Max signed 32bit int
-}
-
-/* static */
-SpdyStreamId SpdyFramer::GetControlFrameStreamId(
- const SpdyControlFrame* control_frame) {
- SpdyStreamId stream_id = kInvalidStream;
- if (control_frame != NULL) {
- switch (control_frame->type()) {
- case SYN_STREAM:
- stream_id = reinterpret_cast<const SpdySynStreamControlFrame*>(
- control_frame)->stream_id();
- break;
- case SYN_REPLY:
- stream_id = reinterpret_cast<const SpdySynReplyControlFrame*>(
- control_frame)->stream_id();
- break;
- case HEADERS:
- stream_id = reinterpret_cast<const SpdyHeadersControlFrame*>(
- control_frame)->stream_id();
- break;
- case RST_STREAM:
- stream_id = reinterpret_cast<const SpdyRstStreamControlFrame*>(
- control_frame)->stream_id();
- break;
- case WINDOW_UPDATE:
- stream_id = reinterpret_cast<const SpdyWindowUpdateControlFrame*>(
- control_frame)->stream_id();
- break;
- // All of the following types are not part of a particular stream.
- // They all fall through to the invalid control frame type case.
- // (The default case isn't used so that the compile will break if a new
- // control frame type is added but not included here.)
- case SETTINGS:
- case NOOP:
- case PING:
- case GOAWAY:
- case NUM_CONTROL_FRAME_TYPES: // makes compiler happy
- break;
- }
- }
- return stream_id;
-}
-
-void SpdyFramer::set_validate_control_frame_sizes(bool value) {
- validate_control_frame_sizes_ = value;
-}
-
SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) {
z_stream* decompressor = GetStreamDecompressor(frame.stream_id());
if (!decompressor)
@@ -1523,9 +1378,10 @@ SpdyFrame* SpdyFramer::DecompressFrameWithZStream(const SpdyFrame& frame,
int rv = inflate(decompressor, Z_SYNC_FLUSH);
if (rv == Z_NEED_DICT) {
// Need to try again with the right dictionary.
- if (decompressor->adler == dictionary_id) {
- rv = inflateSetDictionary(decompressor, (const Bytef*)kDictionary,
- kDictionarySize);
+ if (decompressor->adler == kDictionaryId) {
+ rv = inflateSetDictionary(decompressor,
+ (const Bytef*)SpdyFramer::kDictionary,
+ SpdyFramer::kDictionarySize);
if (rv == Z_OK)
rv = inflate(decompressor, Z_SYNC_FLUSH);
}
@@ -1558,6 +1414,122 @@ SpdyFrame* SpdyFramer::DecompressFrameWithZStream(const SpdyFrame& frame,
return new_frame.release();
}
+// Incrementally decompress the control frame's header block, feeding the
+// result to the visitor in chunks. Continue this until the visitor
+// indicates that it cannot process any more data, or (more commonly) we
+// run out of data to deliver.
+bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
+ const SpdyControlFrame* control_frame) {
+ z_stream* decomp = GetHeaderDecompressor();
+ int payload_length;
+ int header_length;
+ const char* payload;
+ bool read_successfully = true;
+ bool more = true;
+ char buffer[kHeaderDataChunkMaxSize];
+
+ if (!GetFrameBoundaries(
+ *control_frame, &payload_length, &header_length, &payload)) {
+ DLOG(ERROR) << "Control frame of type "
+ << SpdyFramer::ControlTypeToString(control_frame->type())
+ <<" doesn't have headers";
+ return false;
+ }
+ decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
+ decomp->avail_in = payload_length;
+ const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
+ DCHECK_LT(0u, stream_id);
+ while (more && read_successfully) {
+ decomp->next_out = reinterpret_cast<Bytef*>(buffer);
+ decomp->avail_out = arraysize(buffer);
+ int rv = DecompressHeaderBlockInZStream(decomp);
+ if (rv != Z_OK) {
+ set_error(SPDY_DECOMPRESS_FAILURE);
+ DLOG(WARNING) << "inflate failure: " << rv;
+ more = read_successfully = false;
+ } else {
+ DCHECK_GT(arraysize(buffer), decomp->avail_out);
+ size_t len = arraysize(buffer) - decomp->avail_out;
+ read_successfully = visitor_->OnControlFrameHeaderData(stream_id, buffer,
+ len);
+ if (!read_successfully) {
+ // Assume that the problem was the header block was too large for the
+ // visitor.
+ set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
+ }
+ more = decomp->avail_in > 0;
+ }
+ }
+ return read_successfully;
+}
+
+// Incrementally decompress the control frame's header block, feeding the
+// result to the visitor in chunks. Continue this until the visitor
+// indicates that it cannot process any more data, or (more commonly) we
+// run out of data to deliver.
+bool SpdyFramer::NewIncrementallyDecompressControlFrameHeaderData(
+ const SpdyControlFrame* control_frame,
+ const char* data,
+ size_t len) {
+ // Get a decompressor or set error.
+ z_stream* decomp = GetHeaderDecompressor();
+ if (decomp == NULL) {
+ LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers.";
+ set_error(SPDY_DECOMPRESS_FAILURE);
+ return false;
+ }
+
+ bool processed_successfully = true;
+ char buffer[kHeaderDataChunkMaxSize];
+
+ decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
+ decomp->avail_in = len;
+ const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
+ DCHECK_LT(0u, stream_id);
+ while (decomp->avail_in > 0 && processed_successfully) {
+ decomp->next_out = reinterpret_cast<Bytef*>(buffer);
+ decomp->avail_out = arraysize(buffer);
+ int rv = DecompressHeaderBlockInZStream(decomp);
+ if (rv != Z_OK) {
+ set_error(SPDY_DECOMPRESS_FAILURE);
+ DLOG(WARNING) << "inflate failure: " << rv;
+ processed_successfully = false;
+ } else {
+ size_t decompressed_len = arraysize(buffer) - decomp->avail_out;
+ if (decompressed_len > 0) {
+ processed_successfully = visitor_->OnControlFrameHeaderData(
+ stream_id, buffer, decompressed_len);
+ }
+ if (!processed_successfully) {
+ // Assume that the problem was the header block was too large for the
+ // visitor.
+ set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
+ }
+ }
+ }
+ return processed_successfully;
+}
+
+bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData(
+ const SpdyControlFrame* control_frame, const char* data, size_t len) {
+ bool read_successfully = true;
+ const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
+ DCHECK_LT(0u, stream_id);
+ while (read_successfully && len > 0) {
+ size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize);
+ read_successfully = visitor_->OnControlFrameHeaderData(stream_id, data,
+ bytes_to_deliver);
+ data += bytes_to_deliver;
+ len -= bytes_to_deliver;
+ if (!read_successfully) {
+ // Assume that the problem was the header block was too large for the
+ // visitor.
+ set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
+ }
+ }
+ return read_successfully;
+}
+
void SpdyFramer::CleanupCompressorForStream(SpdyStreamId id) {
CompressorMap::iterator it = stream_compressors_.find(id);
if (it != stream_compressors_.end()) {
@@ -1600,6 +1572,81 @@ void SpdyFramer::CleanupStreamCompressorsAndDecompressors() {
stream_decompressors_.clear();
}
+SpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) {
+ int size = SpdyFrame::size() + frame.length();
+ SpdyFrame* new_frame = new SpdyFrame(size);
+ memcpy(new_frame->data(), frame.data(), size);
+ return new_frame;
+}
+
+size_t SpdyFramer::GetMinimumControlFrameSize(SpdyControlType type) {
+ switch (type) {
+ case SYN_STREAM:
+ return SpdySynStreamControlFrame::size();
+ case SYN_REPLY:
+ return SpdySynReplyControlFrame::size();
+ case RST_STREAM:
+ return SpdyRstStreamControlFrame::size();
+ case SETTINGS:
+ return SpdySettingsControlFrame::size();
+ case NOOP:
+ return SpdyNoOpControlFrame::size();
+ case PING:
+ return SpdyPingControlFrame::size();
+ case GOAWAY:
+ return SpdyGoAwayControlFrame::size();
+ case HEADERS:
+ return SpdyHeadersControlFrame::size();
+ case WINDOW_UPDATE:
+ return SpdyWindowUpdateControlFrame::size();
+ case NUM_CONTROL_FRAME_TYPES:
+ break;
+ }
+ LOG(ERROR) << "Unknown control frame type " << type;
+ return 0x7FFFFFFF; // Max signed 32bit int
+}
+
+/* static */
+SpdyStreamId SpdyFramer::GetControlFrameStreamId(
+ const SpdyControlFrame* control_frame) {
+ SpdyStreamId stream_id = kInvalidStream;
+ if (control_frame != NULL) {
+ switch (control_frame->type()) {
+ case SYN_STREAM:
+ stream_id = reinterpret_cast<const SpdySynStreamControlFrame*>(
+ control_frame)->stream_id();
+ break;
+ case SYN_REPLY:
+ stream_id = reinterpret_cast<const SpdySynReplyControlFrame*>(
+ control_frame)->stream_id();
+ break;
+ case HEADERS:
+ stream_id = reinterpret_cast<const SpdyHeadersControlFrame*>(
+ control_frame)->stream_id();
+ break;
+ case RST_STREAM:
+ stream_id = reinterpret_cast<const SpdyRstStreamControlFrame*>(
+ control_frame)->stream_id();
+ break;
+ case WINDOW_UPDATE:
+ stream_id = reinterpret_cast<const SpdyWindowUpdateControlFrame*>(
+ control_frame)->stream_id();
+ break;
+ // All of the following types are not part of a particular stream.
+ // They all fall through to the invalid control frame type case.
+ // (The default case isn't used so that the compile will break if a new
+ // control frame type is added but not included here.)
+ case SETTINGS:
+ case NOOP:
+ case PING:
+ case GOAWAY:
+ case NUM_CONTROL_FRAME_TYPES: // makes compiler happy
+ break;
+ }
+ }
+ return stream_id;
+}
+
size_t SpdyFramer::BytesSafeToRead() const {
switch (state_) {
case SPDY_ERROR:
@@ -1626,75 +1673,16 @@ size_t SpdyFramer::BytesSafeToRead() const {
return 0;
}
-void SpdyFramer::set_error(SpdyError error) {
- DCHECK(visitor_);
- error_code_ = error;
- CHANGE_STATE(SPDY_ERROR);
- visitor_->OnError(this);
+void SpdyFramer::set_enable_compression(bool value) {
+ enable_compression_ = value;
}
-void SpdyFramer::ExpandControlFrameBuffer(size_t size) {
- size_t alloc_size = size + SpdyFrame::size();
- DCHECK_LE(alloc_size, kControlFrameBufferMaxSize);
- if (alloc_size <= current_frame_capacity_)
- return;
- 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;
+void SpdyFramer::set_enable_compression_default(bool value) {
+ compression_default_ = value;
}
-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);
- switch (control_frame.type()) {
- case SYN_STREAM:
- {
- const SpdySynStreamControlFrame& syn_frame =
- reinterpret_cast<const SpdySynStreamControlFrame&>(frame);
- frame_size = SpdySynStreamControlFrame::size();
- *payload_length = syn_frame.header_block_len();
- *header_length = frame_size;
- *payload = frame.data() + *header_length;
- }
- break;
- case SYN_REPLY:
- {
- const SpdySynReplyControlFrame& syn_frame =
- reinterpret_cast<const SpdySynReplyControlFrame&>(frame);
- frame_size = SpdySynReplyControlFrame::size();
- *payload_length = syn_frame.header_block_len();
- *header_length = frame_size;
- *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!
- }
- } else {
- frame_size = SpdyFrame::size();
- *header_length = frame_size;
- *payload_length = frame.length();
- *payload = frame.data() + SpdyFrame::size();
- }
- return true;
+void SpdyFramer::set_validate_control_frame_sizes(bool value) {
+ validate_control_frame_sizes_ = value;
}
} // namespace spdy