| Index: net/spdy/spdy_framer.cc
|
| diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
|
| index ed21610524b481a5b96615471de335133553d70f..9a3203b0ee6b6b36cdb9495293c65e39fcd64be8 100644
|
| --- a/net/spdy/spdy_framer.cc
|
| +++ b/net/spdy/spdy_framer.cc
|
| @@ -19,8 +19,39 @@
|
| #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;
|
| +
|
| +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;
|
| @@ -71,92 +102,6 @@ SpdyFramer::~SpdyFramer() {
|
| delete [] current_frame_buffer_;
|
| }
|
|
|
| -void SpdyFramer::Reset() {
|
| - state_ = SPDY_RESET;
|
| - error_code_ = SPDY_NO_ERROR;
|
| - remaining_payload_ = 0;
|
| - remaining_control_payload_ = 0;
|
| - current_frame_len_ = 0;
|
| - if (current_frame_capacity_ != kControlFrameBufferInitialSize) {
|
| - delete [] current_frame_buffer_;
|
| - current_frame_buffer_ = 0;
|
| - current_frame_capacity_ = 0;
|
| - ExpandControlFrameBuffer(kControlFrameBufferInitialSize);
|
| - }
|
| -}
|
| -
|
| -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";
|
| - }
|
| - return "UNKNOWN_STATE";
|
| -}
|
| -
|
| -size_t SpdyFramer::BytesSafeToRead() const {
|
| - switch (state_) {
|
| - case SPDY_ERROR:
|
| - case SPDY_DONE:
|
| - case SPDY_AUTO_RESET:
|
| - case SPDY_RESET:
|
| - return 0;
|
| - case SPDY_READING_COMMON_HEADER:
|
| - DCHECK_LT(current_frame_len_, SpdyFrame::size());
|
| - return SpdyFrame::size() - current_frame_len_;
|
| - case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
|
| - return 0;
|
| - case SPDY_CONTROL_FRAME_PAYLOAD:
|
| - case SPDY_IGNORE_REMAINING_PAYLOAD:
|
| - case SPDY_FORWARD_STREAM_FRAME:
|
| - return remaining_payload_;
|
| - }
|
| - // We should never get to here.
|
| - return 0;
|
| -}
|
| -
|
| -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";
|
| -}
|
| -
|
| size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
|
| DCHECK(visitor_);
|
| DCHECK(data);
|
| @@ -211,274 +156,56 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
|
| return original_len - len;
|
| }
|
|
|
| -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_;
|
| - size_t bytes_to_append = std::min(bytes_desired, len);
|
| - char* header_buffer = current_frame_buffer_;
|
| - memcpy(&header_buffer[current_frame_len_], data, bytes_to_append);
|
| - current_frame_len_ += bytes_to_append;
|
| - data += bytes_to_append;
|
| - len -= bytes_to_append;
|
| - // 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_payload_ = current_frame.length();
|
| -
|
| - // This is just a sanity check for help debugging early frame errors.
|
| - if (remaining_payload_ > 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::Reset() {
|
| + state_ = SPDY_RESET;
|
| + error_code_ = SPDY_NO_ERROR;
|
| + remaining_payload_ = 0;
|
| + remaining_control_payload_ = 0;
|
| + current_frame_len_ = 0;
|
| + if (current_frame_capacity_ != kControlFrameBufferInitialSize) {
|
| + delete [] current_frame_buffer_;
|
| + current_frame_buffer_ = 0;
|
| + current_frame_capacity_ = 0;
|
| + ExpandControlFrameBuffer(kControlFrameBufferInitialSize);
|
| + }
|
| }
|
|
|
| -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);
|
| +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;
|
|
|
| - // 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;
|
| - }
|
| + // Find the header data within the control frame.
|
| + scoped_ptr<SpdyFrame> decompressed_frame(DecompressFrame(*frame));
|
| + if (!decompressed_frame.get())
|
| + return false;
|
|
|
| - // 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;
|
| - }
|
| + const char *header_data = NULL;
|
| + int header_length = 0;
|
|
|
| - // Do some sanity checking on the control frame sizes.
|
| - switch (current_control_frame.type()) {
|
| + switch (type) {
|
| case SYN_STREAM:
|
| - if (current_control_frame.length() <
|
| - SpdySynStreamControlFrame::size() - SpdyControlFrame::size())
|
| - set_error(SPDY_INVALID_CONTROL_FRAME);
|
| + {
|
| + SpdySynStreamControlFrame syn_frame(decompressed_frame->data(), false);
|
| + header_data = syn_frame.header_block();
|
| + header_length = syn_frame.header_block_len();
|
| + }
|
| 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;
|
| - case NOOP:
|
| - // NOOP. Swallow it.
|
| - CHANGE_STATE(SPDY_AUTO_RESET);
|
| - return;
|
| - case GOAWAY:
|
| - if (current_control_frame.length() !=
|
| - SpdyGoAwayControlFrame::size() - SpdyFrame::size())
|
| - set_error(SPDY_INVALID_CONTROL_FRAME);
|
| + {
|
| + SpdySynReplyControlFrame syn_frame(decompressed_frame->data(), false);
|
| + header_data = syn_frame.header_block();
|
| + header_length = syn_frame.header_block_len();
|
| + }
|
| 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;
|
| - default:
|
| - LOG(WARNING) << "Valid spdy control frame with unknown 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 amount_to_consume = std::min(remaining_control_payload_, len);
|
| - memcpy(¤t_frame_buffer_[current_frame_len_], data,
|
| - amount_to_consume);
|
| - current_frame_len_ += amount_to_consume;
|
| - data += amount_to_consume;
|
| - len -= amount_to_consume;
|
| - remaining_control_payload_ -= amount_to_consume;
|
| - remaining_payload_ -= amount_to_consume;
|
| - 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_payload_) {
|
| - size_t amount_to_forward = std::min(remaining_payload_, 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_payload_ -= 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_payload_ &&
|
| - 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_LT(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;
|
| -}
|
| -
|
| -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();
|
| - }
|
| + {
|
| + SpdyHeadersControlFrame header_frame(decompressed_frame->data(), false);
|
| + header_data = header_frame.header_block();
|
| + header_length = header_frame.header_block_len();
|
| + }
|
| break;
|
| }
|
|
|
| @@ -508,26 +235,6 @@ bool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame,
|
| 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, SpdyHeaderBlock* headers) {
|
| @@ -727,6 +434,26 @@ 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) {
|
| @@ -743,49 +470,335 @@ SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
|
| flags_length.flags_[0] = flags;
|
| frame.WriteBytes(&flags_length, sizeof(flags_length));
|
|
|
| - frame.WriteBytes(data, len);
|
| - scoped_ptr<SpdyFrame> data_frame(frame.take());
|
| - SpdyDataFrame* rv;
|
| - if (flags & DATA_FLAG_COMPRESSED) {
|
| - rv = reinterpret_cast<SpdyDataFrame*>(CompressFrame(*data_frame.get()));
|
| - } else {
|
| - rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release());
|
| - }
|
| + frame.WriteBytes(data, len);
|
| + scoped_ptr<SpdyFrame> data_frame(frame.take());
|
| + SpdyDataFrame* rv;
|
| + if (flags & DATA_FLAG_COMPRESSED) {
|
| + rv = reinterpret_cast<SpdyDataFrame*>(CompressFrame(*data_frame.get()));
|
| + } else {
|
| + rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release());
|
| + }
|
| +
|
| + if (flags & DATA_FLAG_FIN) {
|
| + CleanupCompressorForStream(stream_id);
|
| + }
|
| +
|
| + return rv;
|
| +}
|
| +
|
| +SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) {
|
| + if (frame.is_control_frame()) {
|
| + return CompressControlFrame(
|
| + reinterpret_cast<const SpdyControlFrame&>(frame));
|
| + }
|
| + return CompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
|
| +}
|
| +
|
| +SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) {
|
| + if (frame.is_control_frame()) {
|
| + return DecompressControlFrame(
|
| + reinterpret_cast<const SpdyControlFrame&>(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
|
| + // and SYN_REPLY.
|
| + // TODO(mbelshe): Reconcile this with the spec when the spec is
|
| + // explicit about which frames compress and which do not.
|
| + if (frame.is_control_frame()) {
|
| + const SpdyControlFrame& control_frame =
|
| + reinterpret_cast<const SpdyControlFrame&>(frame);
|
| + return control_frame.type() == SYN_STREAM ||
|
| + control_frame.type() == SYN_REPLY;
|
| + }
|
| +
|
| + const SpdyDataFrame& data_frame =
|
| + reinterpret_cast<const SpdyDataFrame&>(frame);
|
| + 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";
|
| + }
|
| + 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_;
|
| + size_t bytes_to_append = std::min(bytes_desired, len);
|
| + char* header_buffer = current_frame_buffer_;
|
| + memcpy(&header_buffer[current_frame_len_], data, bytes_to_append);
|
| + current_frame_len_ += bytes_to_append;
|
| + data += bytes_to_append;
|
| + len -= bytes_to_append;
|
| + // 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_payload_ = current_frame.length();
|
| +
|
| + // This is just a sanity check for help debugging early frame errors.
|
| + if (remaining_payload_ > 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;
|
| + case NOOP:
|
| + // NOOP. Swallow it.
|
| + 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;
|
| + default:
|
| + LOG(WARNING) << "Valid spdy control frame with unknown 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 amount_to_consume = std::min(remaining_control_payload_, len);
|
| + memcpy(¤t_frame_buffer_[current_frame_len_], data,
|
| + amount_to_consume);
|
| + current_frame_len_ += amount_to_consume;
|
| + data += amount_to_consume;
|
| + len -= amount_to_consume;
|
| + remaining_control_payload_ -= amount_to_consume;
|
| + remaining_payload_ -= amount_to_consume;
|
| + 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_payload_) {
|
| + size_t amount_to_forward = std::min(remaining_payload_, 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_payload_ -= amount_to_forward;
|
|
|
| - if (flags & DATA_FLAG_FIN) {
|
| - CleanupCompressorForStream(stream_id);
|
| + // 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_payload_ &&
|
| + 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 rv;
|
| + return original_len - len;
|
| }
|
|
|
| -// 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);
|
| -
|
| -static uLong dictionary_id = 0;
|
| -
|
| z_stream* SpdyFramer::GetHeaderCompressor() {
|
| if (header_compressor_.get())
|
| return header_compressor_.get(); // Already initialized.
|
| @@ -873,74 +886,6 @@ 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;
|
| -}
|
| -
|
| -SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) {
|
| - if (frame.is_control_frame()) {
|
| - return CompressControlFrame(
|
| - reinterpret_cast<const SpdyControlFrame&>(frame));
|
| - }
|
| - return CompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
|
| -}
|
| -
|
| -SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) {
|
| - if (frame.is_control_frame()) {
|
| - return DecompressControlFrame(
|
| - reinterpret_cast<const SpdyControlFrame&>(frame));
|
| - }
|
| - return DecompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
|
| -}
|
| -
|
| SpdyControlFrame* SpdyFramer::CompressControlFrame(
|
| const SpdyControlFrame& frame) {
|
| z_stream* compressor = GetHeaderCompressor();
|
| @@ -950,6 +895,14 @@ SpdyControlFrame* SpdyFramer::CompressControlFrame(
|
| CompressFrameWithZStream(frame, compressor));
|
| }
|
|
|
| +SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) {
|
| + z_stream* compressor = GetStreamCompressor(frame.stream_id());
|
| + if (!compressor)
|
| + return NULL;
|
| + return reinterpret_cast<SpdyDataFrame*>(
|
| + CompressFrameWithZStream(frame, compressor));
|
| +}
|
| +
|
| SpdyControlFrame* SpdyFramer::DecompressControlFrame(
|
| const SpdyControlFrame& frame) {
|
| z_stream* decompressor = GetHeaderDecompressor();
|
| @@ -959,14 +912,6 @@ SpdyControlFrame* SpdyFramer::DecompressControlFrame(
|
| DecompressFrameWithZStream(frame, decompressor));
|
| }
|
|
|
| -SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) {
|
| - z_stream* compressor = GetStreamCompressor(frame.stream_id());
|
| - if (!compressor)
|
| - return NULL;
|
| - return reinterpret_cast<SpdyDataFrame*>(
|
| - CompressFrameWithZStream(frame, compressor));
|
| -}
|
| -
|
| SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) {
|
| z_stream* decompressor = GetStreamDecompressor(frame.stream_id());
|
| if (!decompressor)
|
| @@ -1145,37 +1090,96 @@ 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;
|
| -}
|
| -
|
| -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
|
| - // and SYN_REPLY.
|
| - // TODO(mbelshe): Reconcile this with the spec when the spec is
|
| - // explicit about which frames compress and which do not.
|
| - if (frame.is_control_frame()) {
|
| - const SpdyControlFrame& control_frame =
|
| - reinterpret_cast<const SpdyControlFrame&>(frame);
|
| - return control_frame.type() == SYN_STREAM ||
|
| - control_frame.type() == SYN_REPLY;
|
| +size_t SpdyFramer::BytesSafeToRead() const {
|
| + switch (state_) {
|
| + case SPDY_ERROR:
|
| + case SPDY_DONE:
|
| + case SPDY_AUTO_RESET:
|
| + case SPDY_RESET:
|
| + return 0;
|
| + case SPDY_READING_COMMON_HEADER:
|
| + DCHECK_LT(current_frame_len_, SpdyFrame::size());
|
| + return SpdyFrame::size() - current_frame_len_;
|
| + case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
|
| + return 0;
|
| + case SPDY_CONTROL_FRAME_PAYLOAD:
|
| + case SPDY_IGNORE_REMAINING_PAYLOAD:
|
| + case SPDY_FORWARD_STREAM_FRAME:
|
| + return remaining_payload_;
|
| }
|
| + // We should never get to here.
|
| + return 0;
|
| +}
|
|
|
| - const SpdyDataFrame& data_frame =
|
| - reinterpret_cast<const SpdyDataFrame&>(frame);
|
| - return (data_frame.flags() & DATA_FLAG_COMPRESSED) != 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_LT(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;
|
| }
|
|
|
| } // namespace spdy
|
|
|