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); |