Index: net/filter/gzip_filter.cc |
diff --git a/net/filter/gzip_filter.cc b/net/filter/gzip_filter.cc |
deleted file mode 100644 |
index 209e3c45d6260d1ad2d1be94a9fbca17b9e8eb51..0000000000000000000000000000000000000000 |
--- a/net/filter/gzip_filter.cc |
+++ /dev/null |
@@ -1,300 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/filter/gzip_filter.h" |
- |
-#include "base/bit_cast.h" |
-#include "base/logging.h" |
-#include "net/filter/gzip_header.h" |
-#include "third_party/zlib/zlib.h" |
- |
-namespace net { |
- |
-GZipFilter::GZipFilter(FilterType type) |
- : Filter(type), |
- decoding_status_(DECODING_UNINITIALIZED), |
- decoding_mode_(DECODE_MODE_UNKNOWN), |
- gzip_header_status_(GZIP_CHECK_HEADER_IN_PROGRESS), |
- zlib_header_added_(false), |
- gzip_footer_bytes_(0), |
- possible_sdch_pass_through_(false) { |
-} |
- |
-GZipFilter::~GZipFilter() { |
- if (decoding_status_ != DECODING_UNINITIALIZED) { |
- inflateEnd(zlib_stream_.get()); |
- } |
-} |
- |
-bool GZipFilter::InitDecoding(Filter::FilterType filter_type) { |
- if (decoding_status_ != DECODING_UNINITIALIZED) |
- return false; |
- |
- // Initialize zlib control block |
- zlib_stream_.reset(new z_stream); |
- if (!zlib_stream_.get()) |
- return false; |
- memset(zlib_stream_.get(), 0, sizeof(z_stream)); |
- |
- // Set decoding mode |
- switch (filter_type) { |
- case Filter::FILTER_TYPE_DEFLATE: { |
- if (inflateInit(zlib_stream_.get()) != Z_OK) |
- return false; |
- decoding_mode_ = DECODE_MODE_DEFLATE; |
- break; |
- } |
- case Filter::FILTER_TYPE_GZIP_HELPING_SDCH: |
- possible_sdch_pass_through_ = true; // Needed to optionally help sdch. |
- // Fall through to GZIP case. |
- case Filter::FILTER_TYPE_GZIP: { |
- gzip_header_.reset(new GZipHeader()); |
- if (!gzip_header_.get()) |
- return false; |
- if (inflateInit2(zlib_stream_.get(), -MAX_WBITS) != Z_OK) |
- return false; |
- decoding_mode_ = DECODE_MODE_GZIP; |
- break; |
- } |
- default: { |
- return false; |
- } |
- } |
- |
- decoding_status_ = DECODING_IN_PROGRESS; |
- return true; |
-} |
- |
-Filter::FilterStatus GZipFilter::ReadFilteredData(char* dest_buffer, |
- int* dest_len) { |
- if (!dest_buffer || !dest_len || *dest_len <= 0) |
- return Filter::FILTER_ERROR; |
- |
- if (decoding_status_ == DECODING_DONE) { |
- if (GZIP_GET_INVALID_HEADER != gzip_header_status_) |
- SkipGZipFooter(); |
- // Some server might send extra data after the gzip footer. We just copy |
- // them out. Mozilla does this too. |
- return CopyOut(dest_buffer, dest_len); |
- } |
- |
- if (decoding_status_ != DECODING_IN_PROGRESS) |
- return Filter::FILTER_ERROR; |
- |
- Filter::FilterStatus status; |
- |
- if (decoding_mode_ == DECODE_MODE_GZIP && |
- gzip_header_status_ == GZIP_CHECK_HEADER_IN_PROGRESS) { |
- // With gzip encoding the content is wrapped with a gzip header. |
- // We need to parse and verify the header first. |
- status = CheckGZipHeader(); |
- switch (status) { |
- case Filter::FILTER_NEED_MORE_DATA: { |
- // We have consumed all input data, either getting a complete header or |
- // a partial header. Return now to get more data. |
- *dest_len = 0; |
- // Partial header means it can't be an SDCH header. |
- // Reason: SDCH *always* starts with 8 printable characters [a-zA-Z/_]. |
- // Gzip always starts with two non-printable characters. Hence even a |
- // single character (partial header) means that this can't be an SDCH |
- // encoded body masquerading as a GZIP body. |
- possible_sdch_pass_through_ = false; |
- return status; |
- } |
- case Filter::FILTER_OK: { |
- // The header checking succeeds, and there are more data in the input. |
- // We must have got a complete header here. |
- DCHECK_EQ(gzip_header_status_, GZIP_GET_COMPLETE_HEADER); |
- break; |
- } |
- case Filter::FILTER_ERROR: { |
- if (possible_sdch_pass_through_ && |
- GZIP_GET_INVALID_HEADER == gzip_header_status_) { |
- decoding_status_ = DECODING_DONE; // Become a pass through filter. |
- return CopyOut(dest_buffer, dest_len); |
- } |
- decoding_status_ = DECODING_ERROR; |
- return status; |
- } |
- default: { |
- status = Filter::FILTER_ERROR; // Unexpected. |
- decoding_status_ = DECODING_ERROR; |
- return status; |
- } |
- } |
- } |
- |
- int dest_orig_size = *dest_len; |
- status = DoInflate(dest_buffer, dest_len); |
- |
- if (decoding_mode_ == DECODE_MODE_DEFLATE && status == Filter::FILTER_ERROR) { |
- // As noted in Mozilla implementation, some servers such as Apache with |
- // mod_deflate don't generate zlib headers. |
- // See 677409 for instances where this work around is needed. |
- // Insert a dummy zlib header and try again. |
- if (InsertZlibHeader()) { |
- *dest_len = dest_orig_size; |
- status = DoInflate(dest_buffer, dest_len); |
- } |
- } |
- |
- if (status == Filter::FILTER_DONE) { |
- decoding_status_ = DECODING_DONE; |
- } else if (status == Filter::FILTER_ERROR) { |
- decoding_status_ = DECODING_ERROR; |
- } |
- |
- return status; |
-} |
- |
-Filter::FilterStatus GZipFilter::CheckGZipHeader() { |
- DCHECK_EQ(gzip_header_status_, GZIP_CHECK_HEADER_IN_PROGRESS); |
- |
- // Check input data in pre-filter buffer. |
- if (!next_stream_data_ || stream_data_len_ <= 0) |
- return Filter::FILTER_ERROR; |
- |
- const char* header_end = NULL; |
- GZipHeader::Status header_status; |
- header_status = gzip_header_->ReadMore(next_stream_data_, stream_data_len_, |
- &header_end); |
- |
- switch (header_status) { |
- case GZipHeader::INCOMPLETE_HEADER: { |
- // We read all the data but only got a partial header. |
- next_stream_data_ = NULL; |
- stream_data_len_ = 0; |
- return Filter::FILTER_NEED_MORE_DATA; |
- } |
- case GZipHeader::COMPLETE_HEADER: { |
- // We have a complete header. Check whether there are more data. |
- int num_chars_left = static_cast<int>(stream_data_len_ - |
- (header_end - next_stream_data_)); |
- gzip_header_status_ = GZIP_GET_COMPLETE_HEADER; |
- |
- if (num_chars_left > 0) { |
- next_stream_data_ = const_cast<char*>(header_end); |
- stream_data_len_ = num_chars_left; |
- return Filter::FILTER_OK; |
- } else { |
- next_stream_data_ = NULL; |
- stream_data_len_ = 0; |
- return Filter::FILTER_NEED_MORE_DATA; |
- } |
- } |
- case GZipHeader::INVALID_HEADER: { |
- gzip_header_status_ = GZIP_GET_INVALID_HEADER; |
- return Filter::FILTER_ERROR; |
- } |
- default: { |
- break; |
- } |
- } |
- |
- return Filter::FILTER_ERROR; |
-} |
- |
-Filter::FilterStatus GZipFilter::DoInflate(char* dest_buffer, int* dest_len) { |
- // Make sure we have both valid input data and output buffer. |
- if (!dest_buffer || !dest_len || *dest_len <= 0) // output |
- return Filter::FILTER_ERROR; |
- |
- if (!next_stream_data_ || stream_data_len_ <= 0) { // input |
- *dest_len = 0; |
- return Filter::FILTER_NEED_MORE_DATA; |
- } |
- |
- // Fill in zlib control block |
- zlib_stream_.get()->next_in = bit_cast<Bytef*>(next_stream_data_); |
- zlib_stream_.get()->avail_in = stream_data_len_; |
- zlib_stream_.get()->next_out = bit_cast<Bytef*>(dest_buffer); |
- zlib_stream_.get()->avail_out = *dest_len; |
- |
- int inflate_code = inflate(zlib_stream_.get(), Z_NO_FLUSH); |
- int bytesWritten = *dest_len - zlib_stream_.get()->avail_out; |
- |
- Filter::FilterStatus status; |
- |
- switch (inflate_code) { |
- case Z_STREAM_END: { |
- *dest_len = bytesWritten; |
- |
- stream_data_len_ = zlib_stream_.get()->avail_in; |
- next_stream_data_ = bit_cast<char*>(zlib_stream_.get()->next_in); |
- |
- SkipGZipFooter(); |
- |
- status = Filter::FILTER_DONE; |
- break; |
- } |
- case Z_BUF_ERROR: { |
- // According to zlib documentation, when calling inflate with Z_NO_FLUSH, |
- // getting Z_BUF_ERROR means no progress is possible. Neither processing |
- // more input nor producing more output can be done. |
- // Since we have checked both input data and output buffer before calling |
- // inflate, this result is unexpected. |
- status = Filter::FILTER_ERROR; |
- break; |
- } |
- case Z_OK: { |
- // Some progress has been made (more input processed or more output |
- // produced). |
- *dest_len = bytesWritten; |
- |
- // Check whether we have consumed all input data. |
- stream_data_len_ = zlib_stream_.get()->avail_in; |
- if (stream_data_len_ == 0) { |
- next_stream_data_ = NULL; |
- status = Filter::FILTER_NEED_MORE_DATA; |
- } else { |
- next_stream_data_ = bit_cast<char*>(zlib_stream_.get()->next_in); |
- status = Filter::FILTER_OK; |
- } |
- break; |
- } |
- default: { |
- status = Filter::FILTER_ERROR; |
- break; |
- } |
- } |
- |
- return status; |
-} |
- |
-bool GZipFilter::InsertZlibHeader() { |
- static char dummy_head[2] = { 0x78, 0x1 }; |
- |
- char dummy_output[4]; |
- |
- // We only try add additional header once. |
- if (zlib_header_added_) |
- return false; |
- |
- inflateReset(zlib_stream_.get()); |
- zlib_stream_.get()->next_in = bit_cast<Bytef*>(&dummy_head[0]); |
- zlib_stream_.get()->avail_in = sizeof(dummy_head); |
- zlib_stream_.get()->next_out = bit_cast<Bytef*>(&dummy_output[0]); |
- zlib_stream_.get()->avail_out = sizeof(dummy_output); |
- |
- int code = inflate(zlib_stream_.get(), Z_NO_FLUSH); |
- zlib_header_added_ = true; |
- |
- return (code == Z_OK); |
-} |
- |
- |
-void GZipFilter::SkipGZipFooter() { |
- int footer_bytes_expected = kGZipFooterSize - gzip_footer_bytes_; |
- if (footer_bytes_expected > 0) { |
- int footer_byte_avail = std::min(footer_bytes_expected, stream_data_len_); |
- stream_data_len_ -= footer_byte_avail; |
- next_stream_data_ += footer_byte_avail; |
- gzip_footer_bytes_ += footer_byte_avail; |
- |
- if (stream_data_len_ == 0) |
- next_stream_data_ = NULL; |
- } |
-} |
- |
-} // namespace net |