diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-14 18:25:33 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-14 18:25:33 +0000 |
commit | c84b42002c558e2eaff044167b6c22a090c74bfc (patch) | |
tree | f838a2982b6f87108d9d3319fa1f530025e40a3e /net/spdy | |
parent | f46da80874c20d9c1fc64787bb79e324f74812f6 (diff) | |
download | chromium_src-c84b42002c558e2eaff044167b6c22a090c74bfc.zip chromium_src-c84b42002c558e2eaff044167b6c22a090c74bfc.tar.gz chromium_src-c84b42002c558e2eaff044167b6c22a090c74bfc.tar.bz2 |
Revert "net: workaround compression leaks"
This reverts r151502.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151517 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy')
-rw-r--r-- | net/spdy/buffered_spdy_framer.cc | 5 | ||||
-rw-r--r-- | net/spdy/buffered_spdy_framer.h | 1 | ||||
-rw-r--r-- | net/spdy/spdy_framer.cc | 178 | ||||
-rw-r--r-- | net/spdy/spdy_framer.h | 10 | ||||
-rw-r--r-- | net/spdy/spdy_framer_test.cc | 80 |
5 files changed, 56 insertions, 218 deletions
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc index bafb5ce..08012c9 100644 --- a/net/spdy/buffered_spdy_framer.cc +++ b/net/spdy/buffered_spdy_framer.cc @@ -296,6 +296,11 @@ bool BufferedSpdyFramer::IsCompressible(const SpdyFrame& frame) const { return spdy_framer_.IsCompressible(frame); } +SpdyControlFrame* BufferedSpdyFramer::CompressControlFrame( + const SpdyControlFrame& frame) { + return spdy_framer_.CompressControlFrame(frame); +} + // static void BufferedSpdyFramer::set_enable_compression_default(bool value) { g_enable_compression_default = value; diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h index 39a2d0e..e13df30 100644 --- a/net/spdy/buffered_spdy_framer.h +++ b/net/spdy/buffered_spdy_framer.h @@ -177,6 +177,7 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramer SpdyDataFlags flags); SpdyPriority GetHighestPriority() const; bool IsCompressible(const SpdyFrame& frame) const; + SpdyControlFrame* CompressControlFrame(const SpdyControlFrame& frame); // Specify if newly created SpdySessions should have compression enabled. static void set_enable_compression_default(bool value); diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index fc1bb06..1d14714 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc @@ -661,155 +661,6 @@ void SpdyFramer::WriteHeaderBlock(SpdyFrameBuilder* frame, } } -// These constants are used by zlib to differentiate between normal data and -// cookie data. Cookie data is handled specially by zlib when compressing. -enum ZDataClass { - // kZStandardData is compressed normally, save that it will never match - // against any other class of data in the window. - kZStandardData = Z_CLASS_STANDARD, - // kZCookieData is compressed in its own Huffman blocks and only matches in - // its entirety and only against other kZCookieData blocks. Any matches must - // be preceeded by a kZStandardData byte, or a semicolon to prevent matching - // a suffix. It's assumed that kZCookieData ends in a semicolon to prevent - // prefix matches. - kZCookieData = Z_CLASS_COOKIE, - // kZHuffmanOnlyData is only Huffman compressed - no matches are performed - // against the window. - kZHuffmanOnlyData = Z_CLASS_HUFFMAN_ONLY, -}; - -// WriteZ writes |data| to the deflate context |out|. WriteZ will flush as -// needed when switching between classes of data. -static void WriteZ(const base::StringPiece& data, - ZDataClass clas, - z_stream* out) { - int rv; - - // If we are switching from standard to non-standard data then we need to end - // the current Huffman context to avoid it leaking between them. - if (out->clas == kZStandardData && - clas != kZStandardData) { - out->avail_in = 0; - rv = deflate(out, Z_PARTIAL_FLUSH); - DCHECK_EQ(Z_OK, rv); - DCHECK_EQ(0u, out->avail_in); - DCHECK_LT(0u, out->avail_out); - } - - out->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data.data())); - out->avail_in = data.size(); - out->clas = clas; - if (clas == kZStandardData) { - rv = deflate(out, Z_NO_FLUSH); - } else { - rv = deflate(out, Z_PARTIAL_FLUSH); - } - DCHECK_EQ(Z_OK, rv); - DCHECK_EQ(0u, out->avail_in); - DCHECK_LT(0u, out->avail_out); -} - -// WriteLengthZ writes |n| as a |length|-byte, big-endian number to |out|. -static void WriteLengthZ(size_t n, - unsigned length, - ZDataClass clas, - z_stream* out) { - char buf[4]; - DCHECK_LE(length, sizeof(buf)); - for (unsigned i = 1; i <= length; i++) { - buf[length - i] = n; - n >>= 8; - } - WriteZ(base::StringPiece(buf, length), clas, out); -} - -// WriteHeaderBlockToZ serialises |headers| to the deflate context |z| in a -// manner that resists the length of the compressed data from compromising -// cookie data. -void SpdyFramer::WriteHeaderBlockToZ(const SpdyHeaderBlock* headers, - z_stream* z) const { - unsigned length_length = 4; - if (spdy_version_ < 3) - length_length = 2; - - WriteLengthZ(headers->size(), length_length, kZStandardData, z); - - std::map<std::string, std::string>::const_iterator it; - for (it = headers->begin(); it != headers->end(); ++it) { - WriteLengthZ(it->first.size(), length_length, kZStandardData, z); - WriteZ(it->first, kZStandardData, z); - - if (it->first == "cookie") { - // We require the cookie values to end with a semi-colon and (save for - // the first) to start with one too. The values are already separated by - // semicolons in the header, but there's usually whitespace in there too. - // So we accumulate the values without whitespace in |cookie_values| and - // write them out, along with a final semicolon to terminate the last - // cookie. - - std::string last_cookie; - std::vector<base::StringPiece> cookie_values; - size_t cookie_length = 0; - base::StringPiece cookie_data(it->second); - - for (;;) { - while (!cookie_data.empty() && - (cookie_data[0] == ' ' || cookie_data[0] == '\t')) { - cookie_data.remove_prefix(1); - } - if (cookie_data.empty()) - break; - - size_t i; - for (i = 0; i < cookie_data.size(); i++) { - if (cookie_data[i] == ';') - break; - } - if (i < cookie_data.size()) { - cookie_values.push_back(cookie_data.substr(0, i+1)); - cookie_length += i+1; - cookie_data.remove_prefix(i + 1); - } else { - last_cookie = cookie_data.as_string() + ";"; - cookie_values.push_back(last_cookie); - cookie_length += last_cookie.size(); - cookie_data.remove_prefix(i); - } - } - - WriteLengthZ(cookie_length, length_length, kZStandardData, z); - for (std::vector<base::StringPiece>::const_iterator - i = cookie_values.begin(); i != cookie_values.end(); i++) { - WriteZ(*i, kZCookieData, z); - } - } else if (it->first == "accept" || - it->first == "accept-charset" || - it->first == "accept-encoding" || - it->first == "accept-language" || - it->first == "host" || - it->first == "version" || - it->first == "method" || - it->first == "scheme" || - it->first == ":host" || - it->first == ":version" || - it->first == ":method" || - it->first == ":scheme" || - it->first == "user-agent") { - WriteLengthZ(it->second.size(), length_length, kZStandardData, z); - WriteZ(it->second, kZStandardData, z); - } else { - // Non-whitelisted headers are Huffman compressed in their own block, but - // don't match against the window. - WriteLengthZ(it->second.size(), length_length, kZStandardData, z); - WriteZ(it->second, kZHuffmanOnlyData, z); - } - } - - z->avail_in = 0; - int rv = deflate(z, Z_SYNC_FLUSH); - DCHECK_EQ(Z_OK, rv); - z->clas = kZStandardData; -} size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data, size_t len) { @@ -1271,7 +1122,7 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( reinterpret_cast<SpdySynStreamControlFrame*>(frame.take())); if (compressed) { return reinterpret_cast<SpdySynStreamControlFrame*>( - CompressControlFrame(*syn_frame.get(), headers)); + CompressControlFrame(*syn_frame.get())); } return syn_frame.release(); } @@ -1304,7 +1155,7 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply( reinterpret_cast<SpdySynReplyControlFrame*>(frame.take())); if (compressed) { return reinterpret_cast<SpdySynReplyControlFrame*>( - CompressControlFrame(*reply_frame.get(), headers)); + CompressControlFrame(*reply_frame.get())); } return reply_frame.release(); } @@ -1400,7 +1251,7 @@ SpdyHeadersControlFrame* SpdyFramer::CreateHeaders( reinterpret_cast<SpdyHeadersControlFrame*>(frame.take())); if (compressed) { return reinterpret_cast<SpdyHeadersControlFrame*>( - CompressControlFrame(*headers_frame.get(), headers)); + CompressControlFrame(*headers_frame.get())); } return headers_frame.release(); } @@ -1580,8 +1431,7 @@ bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame, } SpdyControlFrame* SpdyFramer::CompressControlFrame( - const SpdyControlFrame& frame, - const SpdyHeaderBlock* headers) { + const SpdyControlFrame& frame) { z_stream* compressor = GetHeaderCompressor(); if (!compressor) return NULL; @@ -1602,10 +1452,6 @@ SpdyControlFrame* SpdyFramer::CompressControlFrame( // Create an output frame. int compressed_max_size = deflateBound(compressor, payload_length); - // Since we'll be performing lots of flushes when compressing the data, - // zlib's lower bounds may be insufficient. - compressed_max_size *= 2; - size_t new_frame_size = header_length + compressed_max_size; if ((frame.type() == SYN_REPLY || frame.type() == HEADERS) && spdy_version_ < 3) { @@ -1616,10 +1462,24 @@ SpdyControlFrame* SpdyFramer::CompressControlFrame( memcpy(new_frame->data(), frame.data(), frame.length() + SpdyFrame::kHeaderSize); + compressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload)); + compressor->avail_in = payload_length; compressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) + header_length; compressor->avail_out = compressed_max_size; - WriteHeaderBlockToZ(headers, compressor); + + // Make sure that all the data we pass to zlib is defined. + // This way, all Valgrind reports on the compressed data are zlib's fault. + (void)VALGRIND_CHECK_MEM_IS_DEFINED(compressor->next_in, + compressor->avail_in); + + 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; + return NULL; + } + int compressed_size = compressed_max_size - compressor->avail_out; // We trust zlib. Also, we can't do anything about it. diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h index 93f60e7..1f82876 100644 --- a/net/spdy/spdy_framer.h +++ b/net/spdy/spdy_framer.h @@ -417,6 +417,9 @@ class NET_EXPORT_PRIVATE SpdyFramer { // Returns true if a frame could be compressed. bool IsCompressible(const SpdyFrame& frame) const; + // Returns a new SpdyControlFrame with the compressed payload of |frame|. + SpdyControlFrame* CompressControlFrame(const SpdyControlFrame& frame); + // Get the minimum size of the control frame for the given control frame // type. This is useful for validating frame blocks. static size_t GetMinimumControlFrameSize(int version, SpdyControlType type); @@ -525,9 +528,6 @@ class NET_EXPORT_PRIVATE SpdyFramer { void WriteHeaderBlock(SpdyFrameBuilder* frame, const SpdyHeaderBlock* headers) const; - void WriteHeaderBlockToZ(const SpdyHeaderBlock* headers, - z_stream* out) const; - // Set the error code and moves the framer into the error state. void set_error(SpdyError error); @@ -536,10 +536,6 @@ class NET_EXPORT_PRIVATE SpdyFramer { bool GetFrameBoundaries(const SpdyFrame& frame, int* payload_length, int* header_length, const char** payload) const; - // Returns a new SpdyControlFrame with the compressed payload of |frame|. - SpdyControlFrame* CompressControlFrame(const SpdyControlFrame& frame, - const SpdyHeaderBlock* headers); - // The size of the control frame buffer. // Since this is only used for control frame headers, the maximum control // frame header size (SYN_STREAM) is sufficient; all remaining control diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc index fc78e20..fc1edde 100644 --- a/net/spdy/spdy_framer_test.cc +++ b/net/spdy/spdy_framer_test.cc @@ -1684,39 +1684,31 @@ TEST_P(SpdyFramerTest, CreateSynStreamCompressed) { const SpdyPriority priority = IsSpdy2() ? 2 : 4; const unsigned char kV2FrameData[] = { 0x80, spdy_version_, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x36, + 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x38, 0xea, 0xdf, 0xa2, 0x51, 0xb2, 0x62, 0x60, 0x62, 0x60, 0x4e, 0x4a, 0x2c, 0x62, - 0x60, 0x06, 0x08, 0xa0, - 0xb4, 0xfc, 0x7c, 0x80, - 0x00, 0x62, 0x60, 0x4e, - 0xcb, 0xcf, 0x67, 0x60, - 0x06, 0x08, 0xa0, 0xa4, - 0xc4, 0x22, 0x80, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0xff, 0xff, + 0x60, 0x4e, 0xcb, 0xcf, + 0x87, 0x12, 0x40, 0x2e, + 0x00, 0x00, 0x00, 0xff, + 0xff }; const unsigned char kV3FrameData[] = { 0x80, spdy_version_, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x37, + 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x38, 0xEA, 0xE3, 0xC6, 0xA7, 0xC2, 0x02, 0xE5, 0x0E, 0x50, 0xC2, 0x4B, 0x4A, 0x04, - 0xE5, 0x0B, 0x66, 0x80, - 0x00, 0x4A, 0xCB, 0xCF, - 0x07, 0x08, 0x20, 0x10, - 0x95, 0x96, 0x9F, 0x0F, - 0xA2, 0x00, 0x02, 0x28, - 0x29, 0xB1, 0x08, 0x20, - 0x80, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, + 0xE5, 0x0B, 0xE6, 0xB4, + 0xFC, 0x7C, 0x24, 0x0A, + 0x28, 0x08, 0x00, 0x00, + 0x00, 0xFF, 0xFF }; scoped_ptr<SpdyFrame> frame( framer.CreateSynStream(1, // stream id @@ -1870,37 +1862,29 @@ TEST_P(SpdyFramerTest, CreateSynReplyCompressed) { const unsigned char kV2FrameData[] = { 0x80, spdy_version_, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0xea, 0xdf, 0xa2, 0x51, 0xb2, 0x62, 0x60, 0x62, 0x60, 0x4e, 0x4a, 0x2c, 0x62, - 0x60, 0x06, 0x08, 0xa0, - 0xb4, 0xfc, 0x7c, 0x80, - 0x00, 0x62, 0x60, 0x4e, - 0xcb, 0xcf, 0x67, 0x60, - 0x06, 0x08, 0xa0, 0xa4, - 0xc4, 0x22, 0x80, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0xff, 0xff, + 0x60, 0x4e, 0xcb, 0xcf, + 0x87, 0x12, 0x40, 0x2e, + 0x00, 0x00, 0x00, 0xff, + 0xff }; const unsigned char kV3FrameData[] = { 0x80, spdy_version_, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x31, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x38, 0xea, 0xe3, 0xc6, 0xa7, 0xc2, 0x02, 0xe5, 0x0e, 0x50, 0xc2, 0x4b, 0x4a, 0x04, 0xe5, 0x0b, - 0x66, 0x80, 0x00, 0x4a, - 0xcb, 0xcf, 0x07, 0x08, - 0x20, 0x10, 0x95, 0x96, - 0x9f, 0x0f, 0xa2, 0x00, - 0x02, 0x28, 0x29, 0xb1, - 0x08, 0x20, 0x80, 0x00, + 0xe6, 0xb4, 0xfc, 0x7c, + 0x24, 0x0a, 0x28, 0x08, 0x00, 0x00, 0x00, 0xff, - 0xff, + 0xff }; scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( 1, CONTROL_FLAG_NONE, true, &headers)); @@ -2262,37 +2246,29 @@ TEST_P(SpdyFramerTest, CreateHeadersCompressed) { const unsigned char kV2FrameData[] = { 0x80, spdy_version_, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0xea, 0xdf, 0xa2, 0x51, 0xb2, 0x62, 0x60, 0x62, 0x60, 0x4e, 0x4a, 0x2c, 0x62, - 0x60, 0x06, 0x08, 0xa0, - 0xb4, 0xfc, 0x7c, 0x80, - 0x00, 0x62, 0x60, 0x4e, - 0xcb, 0xcf, 0x67, 0x60, - 0x06, 0x08, 0xa0, 0xa4, - 0xc4, 0x22, 0x80, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0xff, 0xff, + 0x60, 0x4e, 0xcb, 0xcf, + 0x87, 0x12, 0x40, 0x2e, + 0x00, 0x00, 0x00, 0xff, + 0xff }; const unsigned char kV3FrameData[] = { 0x80, spdy_version_, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x31, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x38, 0xea, 0xe3, 0xc6, 0xa7, 0xc2, 0x02, 0xe5, 0x0e, 0x50, 0xc2, 0x4b, 0x4a, 0x04, 0xe5, 0x0b, - 0x66, 0x80, 0x00, 0x4a, - 0xcb, 0xcf, 0x07, 0x08, - 0x20, 0x10, 0x95, 0x96, - 0x9f, 0x0f, 0xa2, 0x00, - 0x02, 0x28, 0x29, 0xb1, - 0x08, 0x20, 0x80, 0x00, + 0xe6, 0xb4, 0xfc, 0x7c, + 0x24, 0x0a, 0x28, 0x08, 0x00, 0x00, 0x00, 0xff, - 0xff, + 0xff }; scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( 1, CONTROL_FLAG_NONE, true, &headers)); |