| Index: net/spdy/spdy_framer.cc
|
| diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
|
| index f48a46c307c813676e169d281ea311be581c1c13..c99c2f83895a96ebd021295d97c783edb4ec682b 100644
|
| --- a/net/spdy/spdy_framer.cc
|
| +++ b/net/spdy/spdy_framer.cc
|
| @@ -8,6 +8,8 @@
|
|
|
| #include "net/spdy/spdy_framer.h"
|
|
|
| +#include <cstring>
|
| +
|
| #include "base/lazy_instance.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/metrics/stats_counters.h"
|
| @@ -129,11 +131,11 @@ SpdyFramer::SpdyFramer(SpdyMajorVersion version)
|
| }
|
|
|
| SpdyFramer::~SpdyFramer() {
|
| - if (header_compressor_.get()) {
|
| - deflateEnd(header_compressor_.get());
|
| + if (spdy_header_compressor_.get()) {
|
| + deflateEnd(spdy_header_compressor_.get());
|
| }
|
| - if (header_decompressor_.get()) {
|
| - inflateEnd(header_decompressor_.get());
|
| + if (spdy_header_decompressor_.get()) {
|
| + inflateEnd(spdy_header_decompressor_.get());
|
| }
|
| }
|
|
|
| @@ -1286,7 +1288,8 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
|
| LOG(DFATAL) << "Unhandled frame type in ProcessControlFrameHeaderBlock.";
|
| }
|
| size_t process_bytes = std::min(data_len, remaining_data_length_);
|
| - if (process_bytes > 0) {
|
| + if ((spdy_version_ < SPDY4 && process_bytes > 0) ||
|
| + ((spdy_version_ >= SPDY4))) {
|
| if (enable_compression_) {
|
| processed_successfully = IncrementallyDecompressControlFrameHeaderData(
|
| current_frame_stream_id_, data, process_bytes);
|
| @@ -1299,7 +1302,11 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
|
| }
|
|
|
| // Handle the case that there is no futher data in this frame.
|
| - if (remaining_data_length_ == 0 && processed_successfully) {
|
| + if ((spdy_version_ < SPDY4 &&
|
| + (remaining_data_length_ == 0 && processed_successfully)) ||
|
| + (spdy_version_ >= SPDY4 &&
|
| + ((current_frame_flags_ & HEADERS_FLAG_END_HEADERS) != 0) &&
|
| + processed_successfully)) {
|
| // The complete header block has been delivered. We send a zero-length
|
| // OnControlFrameHeaderData() to indicate this.
|
| visitor_->OnControlFrameHeaderData(current_frame_stream_id_, NULL, 0);
|
| @@ -2191,7 +2198,11 @@ size_t SpdyFramer::GetSerializedLength(const SpdyHeaderBlock& headers) {
|
| if (!enable_compression_) {
|
| return uncompressed_length;
|
| }
|
| - z_stream* compressor = GetHeaderCompressor();
|
| + if (spdy_version_ >= SPDY4) {
|
| + // TODO(akalin): Handle >= SPDY4 case properly.
|
| + return uncompressed_length;
|
| + }
|
| + z_stream* compressor = GetSpdyHeaderCompressor();
|
| // Since we'll be performing lots of flushes when compressing the data,
|
| // zlib's lower bounds may be insufficient.
|
| return 2 * deflateBound(compressor, uncompressed_length);
|
| @@ -2211,14 +2222,14 @@ static const int kCompressorLevel = 9;
|
| static const int kCompressorWindowSizeInBits = 11;
|
| static const int kCompressorMemLevel = 1;
|
|
|
| -z_stream* SpdyFramer::GetHeaderCompressor() {
|
| - if (header_compressor_.get())
|
| - return header_compressor_.get(); // Already initialized.
|
| +z_stream* SpdyFramer::GetSpdyHeaderCompressor() {
|
| + if (spdy_header_compressor_.get())
|
| + return spdy_header_compressor_.get(); // Already initialized.
|
|
|
| - header_compressor_.reset(new z_stream);
|
| - memset(header_compressor_.get(), 0, sizeof(z_stream));
|
| + spdy_header_compressor_.reset(new z_stream);
|
| + memset(spdy_header_compressor_.get(), 0, sizeof(z_stream));
|
|
|
| - int success = deflateInit2(header_compressor_.get(),
|
| + int success = deflateInit2(spdy_header_compressor_.get(),
|
| kCompressorLevel,
|
| Z_DEFLATED,
|
| kCompressorWindowSizeInBits,
|
| @@ -2229,32 +2240,44 @@ z_stream* SpdyFramer::GetHeaderCompressor() {
|
| : kV3Dictionary;
|
| const int dictionary_size = (spdy_version_ < 3) ? kV2DictionarySize
|
| : kV3DictionarySize;
|
| - success = deflateSetDictionary(header_compressor_.get(),
|
| + success = deflateSetDictionary(spdy_header_compressor_.get(),
|
| reinterpret_cast<const Bytef*>(dictionary),
|
| dictionary_size);
|
| }
|
| if (success != Z_OK) {
|
| LOG(WARNING) << "deflateSetDictionary failure: " << success;
|
| - header_compressor_.reset(NULL);
|
| + spdy_header_compressor_.reset(NULL);
|
| return NULL;
|
| }
|
| - return header_compressor_.get();
|
| + return spdy_header_compressor_.get();
|
| }
|
|
|
| -z_stream* SpdyFramer::GetHeaderDecompressor() {
|
| - if (header_decompressor_.get())
|
| - return header_decompressor_.get(); // Already initialized.
|
| +z_stream* SpdyFramer::GetSpdyHeaderDecompressor() {
|
| + if (spdy_header_decompressor_.get())
|
| + return spdy_header_decompressor_.get(); // Already initialized.
|
|
|
| - header_decompressor_.reset(new z_stream);
|
| - memset(header_decompressor_.get(), 0, sizeof(z_stream));
|
| + spdy_header_decompressor_.reset(new z_stream);
|
| + memset(spdy_header_decompressor_.get(), 0, sizeof(z_stream));
|
|
|
| - int success = inflateInit(header_decompressor_.get());
|
| + int success = inflateInit(spdy_header_decompressor_.get());
|
| if (success != Z_OK) {
|
| LOG(WARNING) << "inflateInit failure: " << success;
|
| - header_decompressor_.reset(NULL);
|
| + spdy_header_decompressor_.reset(NULL);
|
| return NULL;
|
| }
|
| - return header_decompressor_.get();
|
| + return spdy_header_decompressor_.get();
|
| +}
|
| +
|
| +Http2Compressor* SpdyFramer::GetHttp2HeaderCompressor() {
|
| + if (!http2_header_compressor_)
|
| + http2_header_compressor_.reset(new Http2Compressor());
|
| + return http2_header_compressor_.get();
|
| +}
|
| +
|
| +Http2Decompressor* SpdyFramer::GetHttp2HeaderDecompressor() {
|
| + if (!http2_header_decompressor_)
|
| + http2_header_decompressor_.reset(new Http2Decompressor());
|
| + return http2_header_decompressor_.get();
|
| }
|
|
|
| // Incrementally decompress the control frame's header block, feeding the
|
| @@ -2265,8 +2288,26 @@ bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
|
| SpdyStreamId stream_id,
|
| const char* data,
|
| size_t len) {
|
| + if (spdy_version_ >= SPDY4) {
|
| + SpdyNameValueBlock name_value_block;
|
| + if (!GetHttp2HeaderDecompressor()->DecodeNameValueBlock(
|
| + data, len, &name_value_block)) {
|
| + set_error(SPDY_DECOMPRESS_FAILURE);
|
| + return false;
|
| + }
|
| + const size_t uncompressed_length =
|
| + GetSerializedLength(spdy_version_, &name_value_block);
|
| + SpdyFrameBuilder builder(uncompressed_length);
|
| + SerializeNameValueBlockWithoutCompression(&builder, name_value_block);
|
| + scoped_ptr<SpdyFrame> frame(builder.take());
|
| + if (!visitor_->OnControlFrameHeaderData(
|
| + stream_id, frame->data(), frame->size()))
|
| + return false;
|
| + return true;
|
| + }
|
| +
|
| // Get a decompressor or set error.
|
| - z_stream* decomp = GetHeaderDecompressor();
|
| + z_stream* decomp = GetSpdyHeaderDecompressor();
|
| if (decomp == NULL) {
|
| LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers.";
|
| set_error(SPDY_DECOMPRESS_FAILURE);
|
| @@ -2380,58 +2421,70 @@ void SpdyFramer::SerializeNameValueBlock(
|
| frame.name_value_block());
|
| }
|
|
|
| + base::StatsCounter compressed_frames("spdy.CompressedFrames");
|
| + base::StatsCounter pre_compress_bytes("spdy.PreCompressSize");
|
| + base::StatsCounter post_compress_bytes("spdy.PostCompressSize");
|
| +
|
| // First build an uncompressed version to be fed into the compressor.
|
| const size_t uncompressed_len = GetSerializedLength(
|
| protocol_version(), &(frame.name_value_block()));
|
| - SpdyFrameBuilder uncompressed_builder(uncompressed_len);
|
| - SerializeNameValueBlockWithoutCompression(&uncompressed_builder,
|
| - frame.name_value_block());
|
| - scoped_ptr<SpdyFrame> uncompressed_payload(uncompressed_builder.take());
|
| -
|
| - z_stream* compressor = GetHeaderCompressor();
|
| - if (!compressor) {
|
| - LOG(DFATAL) << "Could not obtain compressor.";
|
| - return;
|
| - }
|
| + int compressed_size = 0;
|
|
|
| - base::StatsCounter compressed_frames("spdy.CompressedFrames");
|
| - base::StatsCounter pre_compress_bytes("spdy.PreCompressSize");
|
| - base::StatsCounter post_compress_bytes("spdy.PostCompressSize");
|
| + if (spdy_version_ >= SPDY4) {
|
| + Http2Compressor* compressor = GetHttp2HeaderCompressor();
|
| + const std::string& compressed =
|
| + compressor->EncodeNameValueBlock(frame.name_value_block());
|
| + char* out = builder->GetWritableBuffer(compressed.size());
|
| + std::memcpy(out, compressed.data(), compressed.size());
|
| + compressed_size = compressed.size();
|
| + } else {
|
| + SpdyFrameBuilder uncompressed_builder(uncompressed_len);
|
| + SerializeNameValueBlockWithoutCompression(&uncompressed_builder,
|
| + frame.name_value_block());
|
| + scoped_ptr<SpdyFrame> uncompressed_payload(uncompressed_builder.take());
|
| +
|
| + z_stream* compressor = GetSpdyHeaderCompressor();
|
| + if (!compressor) {
|
| + LOG(DFATAL) << "Could not obtain compressor.";
|
| + return;
|
| + }
|
|
|
| - // Create an output frame.
|
| - // Since we'll be performing lots of flushes when compressing the data,
|
| - // zlib's lower bounds may be insufficient.
|
| - //
|
| - // TODO(akalin): Avoid the duplicate calculation with
|
| - // GetSerializedLength(const SpdyHeaderBlock&).
|
| - const int compressed_max_size =
|
| - 2 * deflateBound(compressor, uncompressed_len);
|
| -
|
| - // TODO(phajdan.jr): Clean up after we no longer need
|
| - // to workaround http://crbug.com/139744.
|
| + // Create an output frame.
|
| + // Since we'll be performing lots of flushes when compressing the data,
|
| + // zlib's lower bounds may be insufficient.
|
| + //
|
| + // TODO(akalin): Avoid the duplicate calculation with
|
| + // GetSerializedLength(const SpdyHeaderBlock&).
|
| + const int compressed_max_size =
|
| + 2 * deflateBound(compressor, uncompressed_len);
|
| +
|
| + // TODO(phajdan.jr): Clean up after we no longer need
|
| + // to workaround http://crbug.com/139744.
|
| #if defined(USE_SYSTEM_ZLIB)
|
| - compressor->next_in = reinterpret_cast<Bytef*>(uncompressed_payload->data());
|
| - compressor->avail_in = uncompressed_len;
|
| + compressor->next_in = reinterpret_cast<Bytef*>(uncompressed_payload->data());
|
| + compressor->avail_in = uncompressed_len;
|
| #endif // defined(USE_SYSTEM_ZLIB)
|
| - compressor->next_out = reinterpret_cast<Bytef*>(
|
| - builder->GetWritableBuffer(compressed_max_size));
|
| - compressor->avail_out = compressed_max_size;
|
| + compressor->next_out = reinterpret_cast<Bytef*>(
|
| + builder->GetWritableBuffer(compressed_max_size));
|
| + compressor->avail_out = compressed_max_size;
|
|
|
| - // TODO(phajdan.jr): Clean up after we no longer need
|
| - // to workaround http://crbug.com/139744.
|
| + // TODO(phajdan.jr): Clean up after we no longer need
|
| + // to workaround http://crbug.com/139744.
|
| #if defined(USE_SYSTEM_ZLIB)
|
| - int rv = deflate(compressor, Z_SYNC_FLUSH);
|
| - if (rv != Z_OK) { // How can we know that it compressed everything?
|
| - // This shouldn't happen, right?
|
| - LOG(WARNING) << "deflate failure: " << rv;
|
| - // TODO(akalin): Upstream this return.
|
| - return;
|
| - }
|
| + int rv = deflate(compressor, Z_SYNC_FLUSH);
|
| + if (rv != Z_OK) { // How can we know that it compressed everything?
|
| + // This shouldn't happen, right?
|
| + LOG(WARNING) << "deflate failure: " << rv;
|
| + // TODO(akalin): Upstream this return.
|
| + return;
|
| + }
|
| #else
|
| - WriteHeaderBlockToZ(&frame.name_value_block(), compressor);
|
| + WriteHeaderBlockToZ(&frame.name_value_block(), compressor);
|
| #endif // defined(USE_SYSTEM_ZLIB)
|
|
|
| - int compressed_size = compressed_max_size - compressor->avail_out;
|
| + compressed_size = compressed_max_size - compressor->avail_out;
|
| + }
|
| +
|
| builder->Seek(compressed_size);
|
| builder->RewriteLength(*this);
|
|
|
|
|