summaryrefslogtreecommitdiffstats
path: root/net/spdy
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-14 18:25:33 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-14 18:25:33 +0000
commitc84b42002c558e2eaff044167b6c22a090c74bfc (patch)
treef838a2982b6f87108d9d3319fa1f530025e40a3e /net/spdy
parentf46da80874c20d9c1fc64787bb79e324f74812f6 (diff)
downloadchromium_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.cc5
-rw-r--r--net/spdy/buffered_spdy_framer.h1
-rw-r--r--net/spdy/spdy_framer.cc178
-rw-r--r--net/spdy/spdy_framer.h10
-rw-r--r--net/spdy/spdy_framer_test.cc80
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));