Commit c84b4200 authored by agl@chromium.org's avatar agl@chromium.org

Revert "net: workaround compression leaks"

This reverts r151502.

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151517 0039d316-1c4b-4281-b951-d872f2087c98
parent f46da808
...@@ -296,6 +296,11 @@ bool BufferedSpdyFramer::IsCompressible(const SpdyFrame& frame) const { ...@@ -296,6 +296,11 @@ bool BufferedSpdyFramer::IsCompressible(const SpdyFrame& frame) const {
return spdy_framer_.IsCompressible(frame); return spdy_framer_.IsCompressible(frame);
} }
SpdyControlFrame* BufferedSpdyFramer::CompressControlFrame(
const SpdyControlFrame& frame) {
return spdy_framer_.CompressControlFrame(frame);
}
// static // static
void BufferedSpdyFramer::set_enable_compression_default(bool value) { void BufferedSpdyFramer::set_enable_compression_default(bool value) {
g_enable_compression_default = value; g_enable_compression_default = value;
......
...@@ -177,6 +177,7 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramer ...@@ -177,6 +177,7 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramer
SpdyDataFlags flags); SpdyDataFlags flags);
SpdyPriority GetHighestPriority() const; SpdyPriority GetHighestPriority() const;
bool IsCompressible(const SpdyFrame& frame) const; bool IsCompressible(const SpdyFrame& frame) const;
SpdyControlFrame* CompressControlFrame(const SpdyControlFrame& frame);
// Specify if newly created SpdySessions should have compression enabled. // Specify if newly created SpdySessions should have compression enabled.
static void set_enable_compression_default(bool value); static void set_enable_compression_default(bool value);
......
...@@ -661,155 +661,6 @@ void SpdyFramer::WriteHeaderBlock(SpdyFrameBuilder* frame, ...@@ -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 SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
size_t len) { size_t len) {
...@@ -1271,7 +1122,7 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( ...@@ -1271,7 +1122,7 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
reinterpret_cast<SpdySynStreamControlFrame*>(frame.take())); reinterpret_cast<SpdySynStreamControlFrame*>(frame.take()));
if (compressed) { if (compressed) {
return reinterpret_cast<SpdySynStreamControlFrame*>( return reinterpret_cast<SpdySynStreamControlFrame*>(
CompressControlFrame(*syn_frame.get(), headers)); CompressControlFrame(*syn_frame.get()));
} }
return syn_frame.release(); return syn_frame.release();
} }
...@@ -1304,7 +1155,7 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply( ...@@ -1304,7 +1155,7 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(
reinterpret_cast<SpdySynReplyControlFrame*>(frame.take())); reinterpret_cast<SpdySynReplyControlFrame*>(frame.take()));
if (compressed) { if (compressed) {
return reinterpret_cast<SpdySynReplyControlFrame*>( return reinterpret_cast<SpdySynReplyControlFrame*>(
CompressControlFrame(*reply_frame.get(), headers)); CompressControlFrame(*reply_frame.get()));
} }
return reply_frame.release(); return reply_frame.release();
} }
...@@ -1400,7 +1251,7 @@ SpdyHeadersControlFrame* SpdyFramer::CreateHeaders( ...@@ -1400,7 +1251,7 @@ SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(
reinterpret_cast<SpdyHeadersControlFrame*>(frame.take())); reinterpret_cast<SpdyHeadersControlFrame*>(frame.take()));
if (compressed) { if (compressed) {
return reinterpret_cast<SpdyHeadersControlFrame*>( return reinterpret_cast<SpdyHeadersControlFrame*>(
CompressControlFrame(*headers_frame.get(), headers)); CompressControlFrame(*headers_frame.get()));
} }
return headers_frame.release(); return headers_frame.release();
} }
...@@ -1580,8 +1431,7 @@ bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame, ...@@ -1580,8 +1431,7 @@ bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame,
} }
SpdyControlFrame* SpdyFramer::CompressControlFrame( SpdyControlFrame* SpdyFramer::CompressControlFrame(
const SpdyControlFrame& frame, const SpdyControlFrame& frame) {
const SpdyHeaderBlock* headers) {
z_stream* compressor = GetHeaderCompressor(); z_stream* compressor = GetHeaderCompressor();
if (!compressor) if (!compressor)
return NULL; return NULL;
...@@ -1602,10 +1452,6 @@ SpdyControlFrame* SpdyFramer::CompressControlFrame( ...@@ -1602,10 +1452,6 @@ SpdyControlFrame* SpdyFramer::CompressControlFrame(
// Create an output frame. // Create an output frame.
int compressed_max_size = deflateBound(compressor, payload_length); 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; size_t new_frame_size = header_length + compressed_max_size;
if ((frame.type() == SYN_REPLY || frame.type() == HEADERS) && if ((frame.type() == SYN_REPLY || frame.type() == HEADERS) &&
spdy_version_ < 3) { spdy_version_ < 3) {
...@@ -1616,10 +1462,24 @@ SpdyControlFrame* SpdyFramer::CompressControlFrame( ...@@ -1616,10 +1462,24 @@ SpdyControlFrame* SpdyFramer::CompressControlFrame(
memcpy(new_frame->data(), frame.data(), memcpy(new_frame->data(), frame.data(),
frame.length() + SpdyFrame::kHeaderSize); 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()) + compressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) +
header_length; header_length;
compressor->avail_out = compressed_max_size; 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; int compressed_size = compressed_max_size - compressor->avail_out;
// We trust zlib. Also, we can't do anything about it. // We trust zlib. Also, we can't do anything about it.
......
...@@ -417,6 +417,9 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -417,6 +417,9 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// Returns true if a frame could be compressed. // Returns true if a frame could be compressed.
bool IsCompressible(const SpdyFrame& frame) const; 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 // Get the minimum size of the control frame for the given control frame
// type. This is useful for validating frame blocks. // type. This is useful for validating frame blocks.
static size_t GetMinimumControlFrameSize(int version, SpdyControlType type); static size_t GetMinimumControlFrameSize(int version, SpdyControlType type);
...@@ -525,9 +528,6 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -525,9 +528,6 @@ class NET_EXPORT_PRIVATE SpdyFramer {
void WriteHeaderBlock(SpdyFrameBuilder* frame, void WriteHeaderBlock(SpdyFrameBuilder* frame,
const SpdyHeaderBlock* headers) const; 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. // Set the error code and moves the framer into the error state.
void set_error(SpdyError error); void set_error(SpdyError error);
...@@ -536,10 +536,6 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -536,10 +536,6 @@ class NET_EXPORT_PRIVATE SpdyFramer {
bool GetFrameBoundaries(const SpdyFrame& frame, int* payload_length, bool GetFrameBoundaries(const SpdyFrame& frame, int* payload_length,
int* header_length, const char** payload) const; 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. // The size of the control frame buffer.
// Since this is only used for control frame headers, the maximum control // Since this is only used for control frame headers, the maximum control
// frame header size (SYN_STREAM) is sufficient; all remaining control // frame header size (SYN_STREAM) is sufficient; all remaining control
......
...@@ -1684,39 +1684,31 @@ TEST_P(SpdyFramerTest, CreateSynStreamCompressed) { ...@@ -1684,39 +1684,31 @@ TEST_P(SpdyFramerTest, CreateSynStreamCompressed) {
const SpdyPriority priority = IsSpdy2() ? 2 : 4; const SpdyPriority priority = IsSpdy2() ? 2 : 4;
const unsigned char kV2FrameData[] = { const unsigned char kV2FrameData[] = {
0x80, spdy_version_, 0x00, 0x01, 0x80, spdy_version_, 0x00, 0x01,
0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x25,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x38, 0xea, 0x80, 0x00, 0x38, 0xea,
0xdf, 0xa2, 0x51, 0xb2, 0xdf, 0xa2, 0x51, 0xb2,
0x62, 0x60, 0x62, 0x60, 0x62, 0x60, 0x62, 0x60,
0x4e, 0x4a, 0x2c, 0x62, 0x4e, 0x4a, 0x2c, 0x62,
0x60, 0x06, 0x08, 0xa0, 0x60, 0x4e, 0xcb, 0xcf,
0xb4, 0xfc, 0x7c, 0x80, 0x87, 0x12, 0x40, 0x2e,
0x00, 0x62, 0x60, 0x4e, 0x00, 0x00, 0x00, 0xff,
0xcb, 0xcf, 0x67, 0x60, 0xff
0x06, 0x08, 0xa0, 0xa4,
0xc4, 0x22, 0x80, 0x00,
0x02, 0x00, 0x00, 0x00,
0xff, 0xff,
}; };
const unsigned char kV3FrameData[] = { const unsigned char kV3FrameData[] = {
0x80, spdy_version_, 0x00, 0x01, 0x80, spdy_version_, 0x00, 0x01,
0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x27,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x38, 0xEA, 0x80, 0x00, 0x38, 0xEA,
0xE3, 0xC6, 0xA7, 0xC2, 0xE3, 0xC6, 0xA7, 0xC2,
0x02, 0xE5, 0x0E, 0x50, 0x02, 0xE5, 0x0E, 0x50,
0xC2, 0x4B, 0x4A, 0x04, 0xC2, 0x4B, 0x4A, 0x04,
0xE5, 0x0B, 0x66, 0x80, 0xE5, 0x0B, 0xE6, 0xB4,
0x00, 0x4A, 0xCB, 0xCF, 0xFC, 0x7C, 0x24, 0x0A,
0x07, 0x08, 0x20, 0x10, 0x28, 0x08, 0x00, 0x00,
0x95, 0x96, 0x9F, 0x0F, 0x00, 0xFF, 0xFF
0xA2, 0x00, 0x02, 0x28,
0x29, 0xB1, 0x08, 0x20,
0x80, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF,
}; };
scoped_ptr<SpdyFrame> frame( scoped_ptr<SpdyFrame> frame(
framer.CreateSynStream(1, // stream id framer.CreateSynStream(1, // stream id
...@@ -1870,37 +1862,29 @@ TEST_P(SpdyFramerTest, CreateSynReplyCompressed) { ...@@ -1870,37 +1862,29 @@ TEST_P(SpdyFramerTest, CreateSynReplyCompressed) {
const unsigned char kV2FrameData[] = { const unsigned char kV2FrameData[] = {
0x80, spdy_version_, 0x00, 0x02, 0x80, spdy_version_, 0x00, 0x02,
0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x21,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x38, 0xea, 0x00, 0x00, 0x38, 0xea,
0xdf, 0xa2, 0x51, 0xb2, 0xdf, 0xa2, 0x51, 0xb2,
0x62, 0x60, 0x62, 0x60, 0x62, 0x60, 0x62, 0x60,
0x4e, 0x4a, 0x2c, 0x62, 0x4e, 0x4a, 0x2c, 0x62,
0x60, 0x06, 0x08, 0xa0, 0x60, 0x4e, 0xcb, 0xcf,
0xb4, 0xfc, 0x7c, 0x80, 0x87, 0x12, 0x40, 0x2e,
0x00, 0x62, 0x60, 0x4e, 0x00, 0x00, 0x00, 0xff,
0xcb, 0xcf, 0x67, 0x60, 0xff
0x06, 0x08, 0xa0, 0xa4,
0xc4, 0x22, 0x80, 0x00,
0x02, 0x00, 0x00, 0x00,
0xff, 0xff,
}; };
const unsigned char kV3FrameData[] = { const unsigned char kV3FrameData[] = {
0x80, spdy_version_, 0x00, 0x02, 0x80, spdy_version_, 0x00, 0x02,
0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x21,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x38, 0xea, 0xe3, 0xc6, 0x38, 0xea, 0xe3, 0xc6,
0xa7, 0xc2, 0x02, 0xe5, 0xa7, 0xc2, 0x02, 0xe5,
0x0e, 0x50, 0xc2, 0x4b, 0x0e, 0x50, 0xc2, 0x4b,
0x4a, 0x04, 0xe5, 0x0b, 0x4a, 0x04, 0xe5, 0x0b,
0x66, 0x80, 0x00, 0x4a, 0xe6, 0xb4, 0xfc, 0x7c,
0xcb, 0xcf, 0x07, 0x08, 0x24, 0x0a, 0x28, 0x08,
0x20, 0x10, 0x95, 0x96,
0x9f, 0x0f, 0xa2, 0x00,
0x02, 0x28, 0x29, 0xb1,
0x08, 0x20, 0x80, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff
}; };
scoped_ptr<SpdyFrame> frame(framer.CreateSynReply( scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
1, CONTROL_FLAG_NONE, true, &headers)); 1, CONTROL_FLAG_NONE, true, &headers));
...@@ -2262,37 +2246,29 @@ TEST_P(SpdyFramerTest, CreateHeadersCompressed) { ...@@ -2262,37 +2246,29 @@ TEST_P(SpdyFramerTest, CreateHeadersCompressed) {
const unsigned char kV2FrameData[] = { const unsigned char kV2FrameData[] = {
0x80, spdy_version_, 0x00, 0x08, 0x80, spdy_version_, 0x00, 0x08,
0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x21,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x38, 0xea, 0x00, 0x00, 0x38, 0xea,
0xdf, 0xa2, 0x51, 0xb2, 0xdf, 0xa2, 0x51, 0xb2,
0x62, 0x60, 0x62, 0x60, 0x62, 0x60, 0x62, 0x60,
0x4e, 0x4a, 0x2c, 0x62, 0x4e, 0x4a, 0x2c, 0x62,
0x60, 0x06, 0x08, 0xa0, 0x60, 0x4e, 0xcb, 0xcf,
0xb4, 0xfc, 0x7c, 0x80, 0x87, 0x12, 0x40, 0x2e,
0x00, 0x62, 0x60, 0x4e, 0x00, 0x00, 0x00, 0xff,
0xcb, 0xcf, 0x67, 0x60, 0xff
0x06, 0x08, 0xa0, 0xa4,
0xc4, 0x22, 0x80, 0x00,
0x02, 0x00, 0x00, 0x00,
0xff, 0xff,
}; };
const unsigned char kV3FrameData[] = { const unsigned char kV3FrameData[] = {
0x80, spdy_version_, 0x00, 0x08, 0x80, spdy_version_, 0x00, 0x08,
0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x21,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x38, 0xea, 0xe3, 0xc6, 0x38, 0xea, 0xe3, 0xc6,
0xa7, 0xc2, 0x02, 0xe5, 0xa7, 0xc2, 0x02, 0xe5,
0x0e, 0x50, 0xc2, 0x4b, 0x0e, 0x50, 0xc2, 0x4b,
0x4a, 0x04, 0xe5, 0x0b, 0x4a, 0x04, 0xe5, 0x0b,
0x66, 0x80, 0x00, 0x4a, 0xe6, 0xb4, 0xfc, 0x7c,
0xcb, 0xcf, 0x07, 0x08, 0x24, 0x0a, 0x28, 0x08,
0x20, 0x10, 0x95, 0x96,
0x9f, 0x0f, 0xa2, 0x00,
0x02, 0x28, 0x29, 0xb1,
0x08, 0x20, 0x80, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff
}; };
scoped_ptr<SpdyFrame> frame(framer.CreateHeaders( scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
1, CONTROL_FLAG_NONE, true, &headers)); 1, CONTROL_FLAG_NONE, true, &headers));
......
...@@ -16,6 +16,3 @@ A few minor changes, all marked with "Google": ...@@ -16,6 +16,3 @@ A few minor changes, all marked with "Google":
- Added 'mozzconf.h' to mangle the function names. - Added 'mozzconf.h' to mangle the function names.
- Added an #ifdef to prevent zlib.h from mangling its functions. - Added an #ifdef to prevent zlib.h from mangling its functions.
The 'google.patch' file represents our changes from the original zlib-1.2.5. The 'google.patch' file represents our changes from the original zlib-1.2.5.
A more significant change to support mixed-source data compression. See
crbug.com/139744 and mixed-source.patch.
...@@ -70,15 +70,14 @@ typedef enum { ...@@ -70,15 +70,14 @@ typedef enum {
finish_done /* finish done, accept no more input or output */ finish_done /* finish done, accept no more input or output */
} block_state; } block_state;
typedef block_state (*compress_func) OF((deflate_state *s, int flush, typedef block_state (*compress_func) OF((deflate_state *s, int flush));
int clas));
/* Compression function. Returns the block state after the call. */ /* Compression function. Returns the block state after the call. */
local void fill_window OF((deflate_state *s)); local void fill_window OF((deflate_state *s));
local block_state deflate_stored OF((deflate_state *s, int flush, int clas)); local block_state deflate_stored OF((deflate_state *s, int flush));
local block_state deflate_fast OF((deflate_state *s, int flush, int clas)); local block_state deflate_fast OF((deflate_state *s, int flush));
#ifndef FASTEST #ifndef FASTEST
local block_state deflate_slow OF((deflate_state *s, int flush, int clas)); local block_state deflate_slow OF((deflate_state *s, int flush));
#endif #endif
local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_rle OF((deflate_state *s, int flush));
local block_state deflate_huff OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush));
...@@ -88,9 +87,9 @@ local void flush_pending OF((z_streamp strm)); ...@@ -88,9 +87,9 @@ local void flush_pending OF((z_streamp strm));
local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
#ifdef ASMV #ifdef ASMV
void match_init OF((void)); /* asm code initialization */ void match_init OF((void)); /* asm code initialization */
uInt longest_match OF((deflate_state *s, IPos cur_match, int clas)); uInt longest_match OF((deflate_state *s, IPos cur_match));
#else #else
local uInt longest_match OF((deflate_state *s, IPos cur_match, int clas)); local uInt longest_match OF((deflate_state *s, IPos cur_match));
#endif #endif
#ifdef DEBUG #ifdef DEBUG
...@@ -282,9 +281,6 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, ...@@ -282,9 +281,6 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
s->class_bitmap = NULL;
zmemzero(&s->cookie_locations, sizeof(s->cookie_locations));
strm->clas = 0;
s->high_water = 0; /* nothing written to s->window yet */ s->high_water = 0; /* nothing written to s->window yet */
...@@ -371,8 +367,6 @@ int ZEXPORT deflateReset (strm) ...@@ -371,8 +367,6 @@ int ZEXPORT deflateReset (strm)
s = (deflate_state *)strm->state; s = (deflate_state *)strm->state;
s->pending = 0; s->pending = 0;
s->pending_out = s->pending_buf; s->pending_out = s->pending_buf;
ZFREE(strm, s->class_bitmap);
s->class_bitmap = NULL;
if (s->wrap < 0) { if (s->wrap < 0) {
s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
...@@ -823,26 +817,9 @@ int ZEXPORT deflate (strm, flush) ...@@ -823,26 +817,9 @@ int ZEXPORT deflate (strm, flush)
(flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
block_state bstate; block_state bstate;
if (strm->clas && s->class_bitmap == NULL) { bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
/* This is the first time that we have seen alternative class (s->strategy == Z_RLE ? deflate_rle(s, flush) :
* data. All data up till this point has been standard class. */ (*(configuration_table[s->level].func))(s, flush));
s->class_bitmap = (Bytef*) ZALLOC(strm, s->w_size/4, sizeof(Byte));
zmemzero(s->class_bitmap, s->w_size/4);
}
if (strm->clas && s->strategy == Z_RLE) {
/* We haven't patched deflate_rle. */
ERR_RETURN(strm, Z_BUF_ERROR);
}
if (s->strategy == Z_HUFFMAN_ONLY) {
bstate = deflate_huff(s, flush);
} else if (s->strategy == Z_RLE) {
bstate = deflate_rle(s, flush);
} else {
bstate = (*(configuration_table[s->level].func))
(s, flush, strm->clas);
}
if (bstate == finish_started || bstate == finish_done) { if (bstate == finish_started || bstate == finish_done) {
s->status = FINISH_STATE; s->status = FINISH_STATE;
...@@ -1069,57 +1046,6 @@ local void lm_init (s) ...@@ -1069,57 +1046,6 @@ local void lm_init (s)
#endif #endif
} }
/* class_set sets bits [offset,offset+len) in s->class_bitmap to either 1 (if
* class != 0) or 0 (otherwise). */
local void class_set(s, offset, len, clas)
deflate_state *s;
IPos offset;
uInt len;
int clas;
{
IPos byte = offset >> 3;
IPos bit = offset & 7;
Bytef class_byte_value = clas ? 0xff : 0x00;
Bytef class_bit_value = clas ? 1 : 0;
static const Bytef mask[8] = {0xfe, 0xfd, 0xfb, 0xf7,
0xef, 0xdf, 0xbf, 0x7f};
if (bit) {
while (len) {
s->class_bitmap[byte] &= mask[bit];
s->class_bitmap[byte] |= class_bit_value << bit;
bit++;
len--;
if (bit == 8) {
bit = 0;
byte++;
break;
}
}
}
while (len >= 8) {
s->class_bitmap[byte++] = class_byte_value;
len -= 8;
}
while (len) {
s->class_bitmap[byte] &= mask[bit];
s->class_bitmap[byte] |= class_bit_value << bit;
bit++;
len--;
}
}
local int class_at(s, window_offset)
deflate_state *s;
IPos window_offset;
{
IPos byte = window_offset >> 3;
IPos bit = window_offset & 7;
return (s->class_bitmap[byte] >> bit) & 1;
}
#ifndef FASTEST #ifndef FASTEST
/* =========================================================================== /* ===========================================================================
* Set match_start to the longest match starting at the given string and * Set match_start to the longest match starting at the given string and
...@@ -1134,10 +1060,9 @@ local int class_at(s, window_offset) ...@@ -1134,10 +1060,9 @@ local int class_at(s, window_offset)
/* For 80x86 and 680x0, an optimized version will be provided in match.asm or /* For 80x86 and 680x0, an optimized version will be provided in match.asm or
* match.S. The code will be functionally equivalent. * match.S. The code will be functionally equivalent.
*/ */
local uInt longest_match(s, cur_match, clas) local uInt longest_match(s, cur_match)
deflate_state *s; deflate_state *s;
IPos cur_match; /* current match */ IPos cur_match; /* current match */
int clas;
{ {
unsigned chain_length = s->max_chain_length;/* max hash chain length */ unsigned chain_length = s->max_chain_length;/* max hash chain length */
register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *scan = s->window + s->strstart; /* current string */
...@@ -1185,9 +1110,6 @@ local uInt longest_match(s, cur_match, clas) ...@@ -1185,9 +1110,6 @@ local uInt longest_match(s, cur_match, clas)
do { do {
Assert(cur_match < s->strstart, "no future"); Assert(cur_match < s->strstart, "no future");
match = s->window + cur_match; match = s->window + cur_match;
/* If the matched data is in the wrong class, skip it. */
if (s->class_bitmap && class_at(s, cur_match) != clas)
continue;
/* Skip to next match if the match length cannot increase /* Skip to next match if the match length cannot increase
* or if the match length is less than 2. Note that the checks below * or if the match length is less than 2. Note that the checks below
...@@ -1230,8 +1152,6 @@ local uInt longest_match(s, cur_match, clas) ...@@ -1230,8 +1152,6 @@ local uInt longest_match(s, cur_match, clas)
len = (MAX_MATCH - 1) - (int)(strend-scan); len = (MAX_MATCH - 1) - (int)(strend-scan);
scan = strend - (MAX_MATCH-1); scan = strend - (MAX_MATCH-1);
#error "UNALIGNED_OK hasn't been patched."
#else /* UNALIGNED_OK */ #else /* UNALIGNED_OK */
if (match[best_len] != scan_end || if (match[best_len] != scan_end ||
...@@ -1248,7 +1168,6 @@ local uInt longest_match(s, cur_match, clas) ...@@ -1248,7 +1168,6 @@ local uInt longest_match(s, cur_match, clas)
scan += 2, match++; scan += 2, match++;
Assert(*scan == *match, "match[2]?"); Assert(*scan == *match, "match[2]?");
if (!s->class_bitmap) {
/* We check for insufficient lookahead only every 8th comparison; /* We check for insufficient lookahead only every 8th comparison;
* the 256th check will be made at strstart+258. * the 256th check will be made at strstart+258.
*/ */
...@@ -1258,13 +1177,6 @@ local uInt longest_match(s, cur_match, clas) ...@@ -1258,13 +1177,6 @@ local uInt longest_match(s, cur_match, clas)
*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match &&
scan < strend); scan < strend);
} else {
/* We have to be mindful of the class of the data and not stray. */
do {
} while (*++scan == *++match &&
class_at(s, match - s->window) == clas &&
scan < strend);
}
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
...@@ -1292,67 +1204,20 @@ local uInt longest_match(s, cur_match, clas) ...@@ -1292,67 +1204,20 @@ local uInt longest_match(s, cur_match, clas)
} }
#endif /* ASMV */ #endif /* ASMV */
/* cookie_match is a replacement for longest_match in the case of cookie data.
* Here we only wish to match the entire value so trying the partial matches in
* longest_match is both wasteful and often fails to find the correct match.
*
* So we take the djb2 hash of the cookie and look up the last position for a
* match in a special hash table. */
local uInt cookie_match(s, start, len)
deflate_state *s;
IPos start;
unsigned len;
{
unsigned hash = 5381;
Bytef *str = s->window + start;
unsigned i;
IPos cookie_location;
if (len >= MAX_MATCH)
return 0;
for (i = 0; i < len; i++)
hash = ((hash << 5) + hash) + str[i];
hash &= Z_COOKIE_HASH_MASK;
cookie_location = s->cookie_locations[hash];
s->cookie_locations[hash] = start;
s->match_start = 0;
if (cookie_location &&
(start - cookie_location) > len &&
(start - cookie_location) < MAX_DIST(s) &&
len <= s->lookahead) {
for (i = 0; i < len; i++) {
if (s->window[start+i] != s->window[cookie_location+i] ||
class_at(s, cookie_location+i) != 1) {
return 0;
}
}
s->match_start = cookie_location;
return len;
}
return 0;
}
#else /* FASTEST */ #else /* FASTEST */
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
* Optimized version for FASTEST only * Optimized version for FASTEST only
*/ */
local uInt longest_match(s, cur_match, clas) local uInt longest_match(s, cur_match)
deflate_state *s; deflate_state *s;
IPos cur_match; /* current match */ IPos cur_match; /* current match */
int clas;
{ {
register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *scan = s->window + s->strstart; /* current string */
register Bytef *match; /* matched string */ register Bytef *match; /* matched string */
register int len; /* length of current match */ register int len; /* length of current match */
register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Bytef *strend = s->window + s->strstart + MAX_MATCH;
#error "This code not patched"
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
* It is easy to get rid of this optimization if necessary. * It is easy to get rid of this optimization if necessary.
*/ */
...@@ -1495,21 +1360,6 @@ local void fill_window(s) ...@@ -1495,21 +1360,6 @@ local void fill_window(s)
*/ */
} while (--n); } while (--n);
#endif #endif
for (n = 0; n < Z_COOKIE_HASH_SIZE; n++) {
if (s->cookie_locations[n] > wsize) {
s->cookie_locations[n] -= wsize;
} else {
s->cookie_locations[n] = 0;
}
}
if (s->class_bitmap) {
zmemcpy(s->class_bitmap, s->class_bitmap + s->w_size/8,
s->w_size/8);
zmemzero(s->class_bitmap + s->w_size/8, s->w_size/8);
}
more += wsize; more += wsize;
} }
if (s->strm->avail_in == 0) return; if (s->strm->avail_in == 0) return;
...@@ -1528,9 +1378,6 @@ local void fill_window(s) ...@@ -1528,9 +1378,6 @@ local void fill_window(s)
Assert(more >= 2, "more < 2"); Assert(more >= 2, "more < 2");
n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
if (s->class_bitmap != NULL) {
class_set(s, s->strstart + s->lookahead, n, s->strm->clas);
}
s->lookahead += n; s->lookahead += n;
/* Initialize the hash value now that we have some input: */ /* Initialize the hash value now that we have some input: */
...@@ -1612,10 +1459,9 @@ local void fill_window(s) ...@@ -1612,10 +1459,9 @@ local void fill_window(s)
* NOTE: this function should be optimized to avoid extra copying from * NOTE: this function should be optimized to avoid extra copying from
* window to pending_buf. * window to pending_buf.
*/ */
local block_state deflate_stored(s, flush, clas) local block_state deflate_stored(s, flush)
deflate_state *s; deflate_state *s;
int flush; int flush;
int clas;
{ {
/* Stored blocks are limited to 0xffff bytes, pending_buf is limited /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
* to pending_buf_size, and each stored block has a 5 byte header: * to pending_buf_size, and each stored block has a 5 byte header:
...@@ -1671,19 +1517,13 @@ local block_state deflate_stored(s, flush, clas) ...@@ -1671,19 +1517,13 @@ local block_state deflate_stored(s, flush, clas)
* new strings in the dictionary only for unmatched strings or for short * new strings in the dictionary only for unmatched strings or for short
* matches. It is used only for the fast compression options. * matches. It is used only for the fast compression options.
*/ */
local block_state deflate_fast(s, flush, clas) local block_state deflate_fast(s, flush)
deflate_state *s; deflate_state *s;
int flush; int flush;
int clas;
{ {
IPos hash_head; /* head of the hash chain */ IPos hash_head; /* head of the hash chain */
int bflush; /* set if current block must be flushed */ int bflush; /* set if current block must be flushed */
if (clas != 0) {
/* We haven't patched this code for alternative class data. */
return Z_BUF_ERROR;
}
for (;;) { for (;;) {
/* Make sure that we always have enough lookahead, except /* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes * at the end of the input file. We need MAX_MATCH bytes
...@@ -1714,7 +1554,7 @@ local block_state deflate_fast(s, flush, clas) ...@@ -1714,7 +1554,7 @@ local block_state deflate_fast(s, flush, clas)
* of window index 0 (in particular we have to avoid a match * of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file). * of the string with itself at the start of the input file).
*/ */
s->match_length = longest_match (s, hash_head, clas); s->match_length = longest_match (s, hash_head);
/* longest_match() sets match_start */ /* longest_match() sets match_start */
} }
if (s->match_length >= MIN_MATCH) { if (s->match_length >= MIN_MATCH) {
...@@ -1773,25 +1613,12 @@ local block_state deflate_fast(s, flush, clas) ...@@ -1773,25 +1613,12 @@ local block_state deflate_fast(s, flush, clas)
* evaluation for matches: a match is finally adopted only if there is * evaluation for matches: a match is finally adopted only if there is
* no better match at the next window position. * no better match at the next window position.
*/ */
local block_state deflate_slow(s, flush, clas) local block_state deflate_slow(s, flush)
deflate_state *s; deflate_state *s;
int flush; int flush;
int clas;
{ {
IPos hash_head; /* head of hash chain */ IPos hash_head; /* head of hash chain */
int bflush; /* set if current block must be flushed */ int bflush; /* set if current block must be flushed */
uInt input_length ;
int first = 1; /* first says whether this is the first iteration
of the loop, below. */
if (clas == Z_CLASS_COOKIE) {
if (s->lookahead) {
/* Alternative class data must always be presented at the beginning
* of a block. */
return Z_BUF_ERROR;
}
input_length = s->strm->avail_in;
}
/* Process the input block. */ /* Process the input block. */
for (;;) { for (;;) {
...@@ -1821,18 +1648,13 @@ local block_state deflate_slow(s, flush, clas) ...@@ -1821,18 +1648,13 @@ local block_state deflate_slow(s, flush, clas)
s->prev_length = s->match_length, s->prev_match = s->match_start; s->prev_length = s->match_length, s->prev_match = s->match_start;
s->match_length = MIN_MATCH-1; s->match_length = MIN_MATCH-1;
if (clas == Z_CLASS_COOKIE && first) { if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
s->match_length = cookie_match(s, s->strstart, input_length);
} else if (clas == Z_CLASS_STANDARD &&
hash_head != NIL &&
s->prev_length < s->max_lazy_match &&
s->strstart - hash_head <= MAX_DIST(s)) { s->strstart - hash_head <= MAX_DIST(s)) {
/* To simplify the code, we prevent matches with the string /* To simplify the code, we prevent matches with the string
* of window index 0 (in particular we have to avoid a match * of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file). * of the string with itself at the start of the input file).
*/ */
s->match_length = longest_match (s, hash_head, clas); s->match_length = longest_match (s, hash_head);
/* longest_match() sets match_start */ /* longest_match() sets match_start */
if (s->match_length <= 5 && (s->strategy == Z_FILTERED if (s->match_length <= 5 && (s->strategy == Z_FILTERED
...@@ -1851,22 +1673,7 @@ local block_state deflate_slow(s, flush, clas) ...@@ -1851,22 +1673,7 @@ local block_state deflate_slow(s, flush, clas)
/* If there was a match at the previous step and the current /* If there was a match at the previous step and the current
* match is not better, output the previous match: * match is not better, output the previous match:
*/ */
first = 0; if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length &&
/* We will only accept an exact match for Z_CLASS_COOKIE data and
* we won't match Z_CLASS_HUFFMAN_ONLY data at all. */
(clas == Z_CLASS_STANDARD || (clas == Z_CLASS_COOKIE &&
s->prev_length == input_length &&
s->prev_match > 0 &&
/* We require that a Z_CLASS_COOKIE match be
* preceded by either a semicolon (which cannot be
* part of a cookie), or non-cookie data. This is
* to prevent
* a cookie from being a prefix of another.
* spdy_framer.cc ensures that cookies are always
* terminated by a semicolon. */
(class_at(s, s->prev_match-1) == Z_CLASS_STANDARD ||
*(s->window + s->prev_match-1) == ';')))) {
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
/* Do not insert strings in hash table beyond this. */ /* Do not insert strings in hash table beyond this. */
......
...@@ -91,9 +91,6 @@ typedef unsigned IPos; ...@@ -91,9 +91,6 @@ typedef unsigned IPos;
* save space in the various tables. IPos is used only for parameter passing. * save space in the various tables. IPos is used only for parameter passing.
*/ */
#define Z_COOKIE_HASH_SIZE 64
#define Z_COOKIE_HASH_MASK (Z_COOKIE_HASH_SIZE-1)
typedef struct internal_state { typedef struct internal_state {
z_streamp strm; /* pointer back to this zlib stream */ z_streamp strm; /* pointer back to this zlib stream */
int status; /* as the name implies */ int status; /* as the name implies */
...@@ -142,8 +139,6 @@ typedef struct internal_state { ...@@ -142,8 +139,6 @@ typedef struct internal_state {
uInt hash_mask; /* hash_size-1 */ uInt hash_mask; /* hash_size-1 */
uInt hash_shift; uInt hash_shift;
Bytef *class_bitmap; /* bitmap of class for each byte in window */
IPos cookie_locations[Z_COOKIE_HASH_SIZE];
/* Number of bits by which ins_h must be shifted at each input /* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest * step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is: * byte no longer takes part in the hash key, that is:
......
diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
index 5c4022f..e419858 100644
--- a/third_party/zlib/deflate.c
+++ b/third_party/zlib/deflate.c
@@ -70,14 +70,15 @@ typedef enum {
finish_done /* finish done, accept no more input or output */
} block_state;
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+typedef block_state (*compress_func) OF((deflate_state *s, int flush,
+ int clas));
/* Compression function. Returns the block state after the call. */
local void fill_window OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast OF((deflate_state *s, int flush));
+local block_state deflate_stored OF((deflate_state *s, int flush, int clas));
+local block_state deflate_fast OF((deflate_state *s, int flush, int clas));
#ifndef FASTEST
-local block_state deflate_slow OF((deflate_state *s, int flush));
+local block_state deflate_slow OF((deflate_state *s, int flush, int clas));
#endif
local block_state deflate_rle OF((deflate_state *s, int flush));
local block_state deflate_huff OF((deflate_state *s, int flush));
@@ -87,9 +88,9 @@ local void flush_pending OF((z_streamp strm));
local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
#ifdef ASMV
void match_init OF((void)); /* asm code initialization */
- uInt longest_match OF((deflate_state *s, IPos cur_match));
+ uInt longest_match OF((deflate_state *s, IPos cur_match, int clas));
#else
-local uInt longest_match OF((deflate_state *s, IPos cur_match));
+local uInt longest_match OF((deflate_state *s, IPos cur_match, int clas));
#endif
#ifdef DEBUG
@@ -281,6 +282,9 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+ s->class_bitmap = NULL;
+ zmemzero(&s->cookie_locations, sizeof(s->cookie_locations));
+ strm->clas = 0;
s->high_water = 0; /* nothing written to s->window yet */
@@ -367,6 +371,8 @@ int ZEXPORT deflateReset (strm)
s = (deflate_state *)strm->state;
s->pending = 0;
s->pending_out = s->pending_buf;
+ ZFREE(strm, s->class_bitmap);
+ s->class_bitmap = NULL;
if (s->wrap < 0) {
s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
@@ -817,9 +823,26 @@ int ZEXPORT deflate (strm, flush)
(flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
block_state bstate;
- bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
- (s->strategy == Z_RLE ? deflate_rle(s, flush) :
- (*(configuration_table[s->level].func))(s, flush));
+ if (strm->clas && s->class_bitmap == NULL) {
+ /* This is the first time that we have seen alternative class
+ * data. All data up till this point has been standard class. */
+ s->class_bitmap = (Bytef*) ZALLOC(strm, s->w_size/4, sizeof(Byte));
+ zmemzero(s->class_bitmap, s->w_size/4);
+ }
+
+ if (strm->clas && s->strategy == Z_RLE) {
+ /* We haven't patched deflate_rle. */
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ if (s->strategy == Z_HUFFMAN_ONLY) {
+ bstate = deflate_huff(s, flush);
+ } else if (s->strategy == Z_RLE) {
+ bstate = deflate_rle(s, flush);
+ } else {
+ bstate = (*(configuration_table[s->level].func))
+ (s, flush, strm->clas);
+ }
if (bstate == finish_started || bstate == finish_done) {
s->status = FINISH_STATE;
@@ -1046,6 +1069,57 @@ local void lm_init (s)
#endif
}
+/* class_set sets bits [offset,offset+len) in s->class_bitmap to either 1 (if
+ * class != 0) or 0 (otherwise). */
+local void class_set(s, offset, len, clas)
+ deflate_state *s;
+ IPos offset;
+ uInt len;
+ int clas;
+{
+ IPos byte = offset >> 3;
+ IPos bit = offset & 7;
+ Bytef class_byte_value = clas ? 0xff : 0x00;
+ Bytef class_bit_value = clas ? 1 : 0;
+ static const Bytef mask[8] = {0xfe, 0xfd, 0xfb, 0xf7,
+ 0xef, 0xdf, 0xbf, 0x7f};
+
+ if (bit) {
+ while (len) {
+ s->class_bitmap[byte] &= mask[bit];
+ s->class_bitmap[byte] |= class_bit_value << bit;
+ bit++;
+ len--;
+ if (bit == 8) {
+ bit = 0;
+ byte++;
+ break;
+ }
+ }
+ }
+
+ while (len >= 8) {
+ s->class_bitmap[byte++] = class_byte_value;
+ len -= 8;
+ }
+
+ while (len) {
+ s->class_bitmap[byte] &= mask[bit];
+ s->class_bitmap[byte] |= class_bit_value << bit;
+ bit++;
+ len--;
+ }
+}
+
+local int class_at(s, window_offset)
+ deflate_state *s;
+ IPos window_offset;
+{
+ IPos byte = window_offset >> 3;
+ IPos bit = window_offset & 7;
+ return (s->class_bitmap[byte] >> bit) & 1;
+}
+
#ifndef FASTEST
/* ===========================================================================
* Set match_start to the longest match starting at the given string and
@@ -1060,9 +1134,10 @@ local void lm_init (s)
/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
* match.S. The code will be functionally equivalent.
*/
-local uInt longest_match(s, cur_match)
+local uInt longest_match(s, cur_match, clas)
deflate_state *s;
IPos cur_match; /* current match */
+ int clas;
{
unsigned chain_length = s->max_chain_length;/* max hash chain length */
register Bytef *scan = s->window + s->strstart; /* current string */
@@ -1110,6 +1185,9 @@ local uInt longest_match(s, cur_match)
do {
Assert(cur_match < s->strstart, "no future");
match = s->window + cur_match;
+ /* If the matched data is in the wrong class, skip it. */
+ if (s->class_bitmap && class_at(s, cur_match) != clas)
+ continue;
/* Skip to next match if the match length cannot increase
* or if the match length is less than 2. Note that the checks below
@@ -1152,6 +1230,8 @@ local uInt longest_match(s, cur_match)
len = (MAX_MATCH - 1) - (int)(strend-scan);
scan = strend - (MAX_MATCH-1);
+#error "UNALIGNED_OK hasn't been patched."
+
#else /* UNALIGNED_OK */
if (match[best_len] != scan_end ||
@@ -1168,15 +1248,23 @@ local uInt longest_match(s, cur_match)
scan += 2, match++;
Assert(*scan == *match, "match[2]?");
- /* We check for insufficient lookahead only every 8th comparison;
- * the 256th check will be made at strstart+258.
- */
- do {
- } while (*++scan == *++match && *++scan == *++match &&
- *++scan == *++match && *++scan == *++match &&
- *++scan == *++match && *++scan == *++match &&
- *++scan == *++match && *++scan == *++match &&
- scan < strend);
+ if (!s->class_bitmap) {
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+ } else {
+ /* We have to be mindful of the class of the data and not stray. */
+ do {
+ } while (*++scan == *++match &&
+ class_at(s, match - s->window) == clas &&
+ scan < strend);
+ }
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
@@ -1204,20 +1292,67 @@ local uInt longest_match(s, cur_match)
}
#endif /* ASMV */
+/* cookie_match is a replacement for longest_match in the case of cookie data.
+ * Here we only wish to match the entire value so trying the partial matches in
+ * longest_match is both wasteful and often fails to find the correct match.
+ *
+ * So we take the djb2 hash of the cookie and look up the last position for a
+ * match in a special hash table. */
+local uInt cookie_match(s, start, len)
+ deflate_state *s;
+ IPos start;
+ unsigned len;
+{
+ unsigned hash = 5381;
+ Bytef *str = s->window + start;
+ unsigned i;
+ IPos cookie_location;
+
+ if (len >= MAX_MATCH)
+ return 0;
+
+ for (i = 0; i < len; i++)
+ hash = ((hash << 5) + hash) + str[i];
+
+ hash &= Z_COOKIE_HASH_MASK;
+ cookie_location = s->cookie_locations[hash];
+ s->cookie_locations[hash] = start;
+ s->match_start = 0;
+ if (cookie_location &&
+ (start - cookie_location) > len &&
+ (start - cookie_location) < MAX_DIST(s) &&
+ len <= s->lookahead) {
+ for (i = 0; i < len; i++) {
+ if (s->window[start+i] != s->window[cookie_location+i] ||
+ class_at(s, cookie_location+i) != 1) {
+ return 0;
+ }
+ }
+ s->match_start = cookie_location;
+ return len;
+ }
+
+ return 0;
+}
+
+
#else /* FASTEST */
/* ---------------------------------------------------------------------------
* Optimized version for FASTEST only
*/
-local uInt longest_match(s, cur_match)
+local uInt longest_match(s, cur_match, clas)
deflate_state *s;
IPos cur_match; /* current match */
+ int clas;
{
register Bytef *scan = s->window + s->strstart; /* current string */
register Bytef *match; /* matched string */
register int len; /* length of current match */
register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+#error "This code not patched"
+
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
* It is easy to get rid of this optimization if necessary.
*/
@@ -1360,6 +1495,21 @@ local void fill_window(s)
*/
} while (--n);
#endif
+
+ for (n = 0; n < Z_COOKIE_HASH_SIZE; n++) {
+ if (s->cookie_locations[n] > wsize) {
+ s->cookie_locations[n] -= wsize;
+ } else {
+ s->cookie_locations[n] = 0;
+ }
+ }
+
+ if (s->class_bitmap) {
+ zmemcpy(s->class_bitmap, s->class_bitmap + s->w_size/8,
+ s->w_size/8);
+ zmemzero(s->class_bitmap + s->w_size/8, s->w_size/8);
+ }
+
more += wsize;
}
if (s->strm->avail_in == 0) return;
@@ -1378,6 +1528,9 @@ local void fill_window(s)
Assert(more >= 2, "more < 2");
n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ if (s->class_bitmap != NULL) {
+ class_set(s, s->strstart + s->lookahead, n, s->strm->clas);
+ }
s->lookahead += n;
/* Initialize the hash value now that we have some input: */
@@ -1459,9 +1612,10 @@ local void fill_window(s)
* NOTE: this function should be optimized to avoid extra copying from
* window to pending_buf.
*/
-local block_state deflate_stored(s, flush)
+local block_state deflate_stored(s, flush, clas)
deflate_state *s;
int flush;
+ int clas;
{
/* Stored blocks are limited to 0xffff bytes, pending_buf is limited
* to pending_buf_size, and each stored block has a 5 byte header:
@@ -1517,13 +1671,19 @@ local block_state deflate_stored(s, flush)
* new strings in the dictionary only for unmatched strings or for short
* matches. It is used only for the fast compression options.
*/
-local block_state deflate_fast(s, flush)
+local block_state deflate_fast(s, flush, clas)
deflate_state *s;
int flush;
+ int clas;
{
IPos hash_head; /* head of the hash chain */
int bflush; /* set if current block must be flushed */
+ if (clas != 0) {
+ /* We haven't patched this code for alternative class data. */
+ return Z_BUF_ERROR;
+ }
+
for (;;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
@@ -1554,7 +1714,7 @@ local block_state deflate_fast(s, flush)
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
- s->match_length = longest_match (s, hash_head);
+ s->match_length = longest_match (s, hash_head, clas);
/* longest_match() sets match_start */
}
if (s->match_length >= MIN_MATCH) {
@@ -1613,12 +1773,25 @@ local block_state deflate_fast(s, flush)
* evaluation for matches: a match is finally adopted only if there is
* no better match at the next window position.
*/
-local block_state deflate_slow(s, flush)
+local block_state deflate_slow(s, flush, clas)
deflate_state *s;
int flush;
+ int clas;
{
IPos hash_head; /* head of hash chain */
int bflush; /* set if current block must be flushed */
+ uInt input_length ;
+ int first = 1; /* first says whether this is the first iteration
+ of the loop, below. */
+
+ if (clas == Z_CLASS_COOKIE) {
+ if (s->lookahead) {
+ /* Alternative class data must always be presented at the beginning
+ * of a block. */
+ return Z_BUF_ERROR;
+ }
+ input_length = s->strm->avail_in;
+ }
/* Process the input block. */
for (;;) {
@@ -1648,13 +1821,18 @@ local block_state deflate_slow(s, flush)
s->prev_length = s->match_length, s->prev_match = s->match_start;
s->match_length = MIN_MATCH-1;
- if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
- s->strstart - hash_head <= MAX_DIST(s)) {
+ if (clas == Z_CLASS_COOKIE && first) {
+ s->match_length = cookie_match(s, s->strstart, input_length);
+ } else if (clas == Z_CLASS_STANDARD &&
+ hash_head != NIL &&
+ s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
/* To simplify the code, we prevent matches with the string
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
- s->match_length = longest_match (s, hash_head);
+ s->match_length = longest_match (s, hash_head, clas);
+
/* longest_match() sets match_start */
if (s->match_length <= 5 && (s->strategy == Z_FILTERED
@@ -1673,7 +1851,22 @@ local block_state deflate_slow(s, flush)
/* If there was a match at the previous step and the current
* match is not better, output the previous match:
*/
- if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ first = 0;
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length &&
+ /* We will only accept an exact match for Z_CLASS_COOKIE data and
+ * we won't match Z_CLASS_HUFFMAN_ONLY data at all. */
+ (clas == Z_CLASS_STANDARD || (clas == Z_CLASS_COOKIE &&
+ s->prev_length == input_length &&
+ s->prev_match > 0 &&
+ /* We require that a Z_CLASS_COOKIE match be
+ * preceded by either a semicolon (which cannot be
+ * part of a cookie), or non-cookie data. This is
+ * to prevent
+ * a cookie from being a prefix of another.
+ * spdy_framer.cc ensures that cookies are always
+ * terminated by a semicolon. */
+ (class_at(s, s->prev_match-1) == Z_CLASS_STANDARD ||
+ *(s->window + s->prev_match-1) == ';')))) {
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
/* Do not insert strings in hash table beyond this. */
diff --git a/third_party/zlib/deflate.h b/third_party/zlib/deflate.h
index cbf0d1e..83b4602 100644
--- a/third_party/zlib/deflate.h
+++ b/third_party/zlib/deflate.h
@@ -91,6 +91,9 @@ typedef unsigned IPos;
* save space in the various tables. IPos is used only for parameter passing.
*/
+#define Z_COOKIE_HASH_SIZE 64
+#define Z_COOKIE_HASH_MASK (Z_COOKIE_HASH_SIZE-1)
+
typedef struct internal_state {
z_streamp strm; /* pointer back to this zlib stream */
int status; /* as the name implies */
@@ -139,6 +142,8 @@ typedef struct internal_state {
uInt hash_mask; /* hash_size-1 */
uInt hash_shift;
+ Bytef *class_bitmap; /* bitmap of class for each byte in window */
+ IPos cookie_locations[Z_COOKIE_HASH_SIZE];
/* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is:
diff --git a/third_party/zlib/zlib.h b/third_party/zlib/zlib.h
index 4d54af9..929f7b4 100644
--- a/third_party/zlib/zlib.h
+++ b/third_party/zlib/zlib.h
@@ -101,6 +101,7 @@ typedef struct z_stream_s {
int data_type; /* best guess about the data type: binary or text */
uLong adler; /* adler32 value of the uncompressed data */
uLong reserved; /* reserved for future use */
+ int clas;
} z_stream;
typedef z_stream FAR *z_streamp;
@@ -207,6 +208,10 @@ typedef gz_header FAR *gz_headerp;
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+#define Z_CLASS_STANDARD 0
+#define Z_CLASS_COOKIE 1
+#define Z_CLASS_HUFFMAN_ONLY 2
+
#define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
{ {
'variables': { 'variables': {
'conditions': [ 'conditions': [
[ 'OS=="none"', { [ 'os_posix == 1 and OS != "mac" and OS != "ios" and OS != "openbsd"', {
# Because we have a patched zlib, we cannot use the system libz. # Link to system .so since we already use it due to GTK.
# TODO(pvalchev): OpenBSD is purposefully left out, as the system # TODO(pvalchev): OpenBSD is purposefully left out, as the system
# zlib brings up an incompatibility that breaks rendering. # zlib brings up an incompatibility that breaks rendering.
'use_system_zlib%': 1, 'use_system_zlib%': 1,
}, { }, { # os_posix != 1 or OS == "mac" or OS == "ios" or OS == "openbsd"
'use_system_zlib%': 0, 'use_system_zlib%': 0,
}], }],
], ],
...@@ -70,8 +70,6 @@ ...@@ -70,8 +70,6 @@
'sources!': [ 'sources!': [
'contrib/minizip/iowin32.c' 'contrib/minizip/iowin32.c'
], ],
}], ['OS=="android"', {
'toolsets': ['target', 'host'],
}], }],
], ],
}, { }, {
......
...@@ -101,7 +101,6 @@ typedef struct z_stream_s { ...@@ -101,7 +101,6 @@ typedef struct z_stream_s {
int data_type; /* best guess about the data type: binary or text */ int data_type; /* best guess about the data type: binary or text */
uLong adler; /* adler32 value of the uncompressed data */ uLong adler; /* adler32 value of the uncompressed data */
uLong reserved; /* reserved for future use */ uLong reserved; /* reserved for future use */
int clas;
} z_stream; } z_stream;
typedef z_stream FAR *z_streamp; typedef z_stream FAR *z_streamp;
...@@ -208,10 +207,6 @@ typedef gz_header FAR *gz_headerp; ...@@ -208,10 +207,6 @@ typedef gz_header FAR *gz_headerp;
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
#define Z_CLASS_STANDARD 0
#define Z_CLASS_COOKIE 1
#define Z_CLASS_HUFFMAN_ONLY 2
#define zlib_version zlibVersion() #define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */ /* for compatibility with versions < 1.0.2 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment