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