| Index: net/base/filter.cc
 | 
| ===================================================================
 | 
| --- net/base/filter.cc	(revision 4002)
 | 
| +++ net/base/filter.cc	(working copy)
 | 
| @@ -11,7 +11,7 @@
 | 
|  
 | 
|  namespace {
 | 
|  
 | 
| -// Filter types:
 | 
| +// Filter types (using canonical lower case only):
 | 
|  const char kDeflate[]      = "deflate";
 | 
|  const char kGZip[]         = "gzip";
 | 
|  const char kXGZip[]        = "x-gzip";
 | 
| @@ -32,53 +32,34 @@
 | 
|  const char kApplicationXGunzip[]   = "application/x-gunzip";
 | 
|  const char kApplicationXCompress[] = "application/x-compress";
 | 
|  const char kApplicationCompress[]  = "application/compress";
 | 
| +const char kTextHtml[]             = "text/html";
 | 
|  
 | 
|  }  // namespace
 | 
|  
 | 
| -Filter* Filter::Factory(const std::vector<std::string>& filter_types,
 | 
| -                        const std::string& mime_type,
 | 
| +Filter* Filter::Factory(const std::vector<FilterType>& filter_types,
 | 
|                          int buffer_size) {
 | 
|    if (filter_types.empty() || buffer_size < 0)
 | 
|      return NULL;
 | 
|  
 | 
| -  std::string safe_mime_type =  (filter_types.size() > 1) ? "" : mime_type;
 | 
|    Filter* filter_list = NULL;  // Linked list of filters.
 | 
| -  FilterType type_id = FILTER_TYPE_UNSUPPORTED;
 | 
|    for (size_t i = 0; i < filter_types.size(); i++) {
 | 
| -    type_id = ConvertEncodingToType(filter_types[i], safe_mime_type);
 | 
| -    filter_list = PrependNewFilter(type_id, buffer_size, filter_list);
 | 
| +    filter_list = PrependNewFilter(filter_types[i], buffer_size, filter_list);
 | 
|      if (!filter_list)
 | 
|        return NULL;
 | 
|    }
 | 
|  
 | 
| -  // Handle proxy that changes content encoding "sdch,gzip" into "sdch".
 | 
| -  if (1 == filter_types.size() && FILTER_TYPE_SDCH == type_id)
 | 
| -    filter_list = PrependNewFilter(FILTER_TYPE_GZIP_HELPING_SDCH, buffer_size,
 | 
| -                                   filter_list);
 | 
|    return filter_list;
 | 
|  }
 | 
|  
 | 
|  // static
 | 
| -Filter::FilterType Filter::ConvertEncodingToType(const std::string& filter_type,
 | 
| -                                                 const std::string& mime_type) {
 | 
| +Filter::FilterType Filter::ConvertEncodingToType(
 | 
| +    const std::string& filter_type) {
 | 
|    FilterType type_id;
 | 
|    if (LowerCaseEqualsASCII(filter_type, kDeflate)) {
 | 
|      type_id = FILTER_TYPE_DEFLATE;
 | 
|    } else if (LowerCaseEqualsASCII(filter_type, kGZip) ||
 | 
|               LowerCaseEqualsASCII(filter_type, kXGZip)) {
 | 
| -    if (LowerCaseEqualsASCII(mime_type, kApplicationXGzip) ||
 | 
| -        LowerCaseEqualsASCII(mime_type, kApplicationGzip) ||
 | 
| -        LowerCaseEqualsASCII(mime_type, kApplicationXGunzip)) {
 | 
| -      // The server has told us that it sent us gziped content with a gzip
 | 
| -      // content encoding.  Sadly, Apache mistakenly sets these headers for all
 | 
| -      // .gz files.  We match Firefox's nsHttpChannel::ProcessNormal and ignore
 | 
| -      // the Content-Encoding here.
 | 
| -      // TODO(jar): Move all this encoding type "fixup" into the
 | 
| -      // GetContentEncoding() methods.  Combine this defaulting with SDCH fixup.
 | 
| -      type_id = FILTER_TYPE_UNSUPPORTED;
 | 
| -    } else {
 | 
| -      type_id = FILTER_TYPE_GZIP;
 | 
| -    }
 | 
| +    type_id = FILTER_TYPE_GZIP;
 | 
|    } else if (LowerCaseEqualsASCII(filter_type, kBZip2) ||
 | 
|               LowerCaseEqualsASCII(filter_type, kXBZip2)) {
 | 
|      type_id = FILTER_TYPE_BZIP2;
 | 
| @@ -93,6 +74,79 @@
 | 
|  }
 | 
|  
 | 
|  // static
 | 
| +void Filter::FixupEncodingTypes(
 | 
| +    bool is_sdch_response,
 | 
| +    const std::string& mime_type,
 | 
| +    std::vector<FilterType>* encoding_types) {
 | 
| +
 | 
| +  if ((1 == encoding_types->size()) &&
 | 
| +      (FILTER_TYPE_GZIP == encoding_types->front())) {
 | 
| +    if (LowerCaseEqualsASCII(mime_type, kApplicationXGzip) ||
 | 
| +        LowerCaseEqualsASCII(mime_type, kApplicationGzip) ||
 | 
| +        LowerCaseEqualsASCII(mime_type, kApplicationXGunzip))
 | 
| +      // The server has told us that it sent us gziped content with a gzip
 | 
| +      // content encoding.  Sadly, Apache mistakenly sets these headers for all
 | 
| +      // .gz files.  We match Firefox's nsHttpChannel::ProcessNormal and ignore
 | 
| +      // the Content-Encoding here.
 | 
| +      encoding_types->clear();
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  if (!is_sdch_response)
 | 
| +    return;
 | 
| +
 | 
| +  // If content encoding included SDCH, then everything is fine.
 | 
| +  if (!encoding_types->empty() &&
 | 
| +      (FILTER_TYPE_SDCH == encoding_types->front())) {
 | 
| +    // Some proxies (found currently in Argentina) strip the Content-Encoding
 | 
| +    // text from "sdch,gzip" to a mere "sdch" without modifying the compressed
 | 
| +    // payload.   To handle this gracefully, we simulate the "probably" deleted
 | 
| +    // ",gzip" by appending a tentative gzip decode, which will default to a
 | 
| +    // no-op pass through filter if it doesn't get gzip headers where expected.
 | 
| +    if (1 == encoding_types->size())
 | 
| +      encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  // SDCH "search results" protective hack: To make sure we don't break the only
 | 
| +  // currently deployed SDCH enabled server! Be VERY cautious about proxies that
 | 
| +  // strip all content-encoding to not include sdch.  IF we don't see content
 | 
| +  // encodings that seem to match what we'd expect from a server that asked us
 | 
| +  // to use a dictionary (and we advertised said dictionary in the GET), then
 | 
| +  // we set the encoding to (try to) use SDCH to decode.  Note that SDCH will
 | 
| +  // degrade into a pass-through filter if it doesn't have a viable dictionary
 | 
| +  // hash in its header.  Also note that a solo "sdch" will implicitly create
 | 
| +  // a "sdch,gzip" decoding filter, where the gzip portion will degrade to a
 | 
| +  // pass through if a gzip header is not encountered.  Hence we can replace
 | 
| +  // "gzip" with "sdch" and "everything will work."
 | 
| +  // The one failure mode comes when we advertise a dictionary, and the server
 | 
| +  // tries to *send* a gzipped file (not gzip encode content), and then we could
 | 
| +  // do a gzip decode :-(.  Since current server support does not ever see such
 | 
| +  // a transfer, we are safe (for now).
 | 
| +  if (LowerCaseEqualsASCII(mime_type, kTextHtml)) {
 | 
| +    // Suspicious case: Advertised dictionary, but server didn't use sdch, even
 | 
| +    // though it is text_html content.
 | 
| +    if (encoding_types->empty())
 | 
| +      SdchManager::SdchErrorRecovery(SdchManager::ADDED_CONTENT_ENCODING);
 | 
| +    else if (1 == encoding_types->size())
 | 
| +      SdchManager::SdchErrorRecovery(SdchManager::FIXED_CONTENT_ENCODING);
 | 
| +    else
 | 
| +      SdchManager::SdchErrorRecovery(SdchManager::FIXED_CONTENT_ENCODINGS);
 | 
| +    encoding_types->clear();
 | 
| +    encoding_types->push_back(FILTER_TYPE_SDCH);
 | 
| +    encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  // It didn't have SDCH encoding... but it wasn't HTML... so maybe it really
 | 
| +  // wasn't SDCH encoded.  It would be nice if we knew this, and didn't bother
 | 
| +  // to propose a dictionary etc., but current SDCH spec does not provide a nice
 | 
| +  // way for us to conclude that.  Perhaps in the future, this case will be much
 | 
| +  // more rare.
 | 
| +  return;
 | 
| +}
 | 
| +
 | 
| +// static
 | 
|  Filter* Filter::PrependNewFilter(FilterType type_id, int buffer_size,
 | 
|                                   Filter* filter_list) {
 | 
|    Filter* first_filter = NULL;  // Soon to be start of chain.
 | 
| @@ -247,7 +301,7 @@
 | 
|      next_filter_->SetURL(url);
 | 
|  }
 | 
|  
 | 
| -void Filter::SetMimeType(std::string& mime_type) {
 | 
| +void Filter::SetMimeType(const std::string& mime_type) {
 | 
|    mime_type_ = mime_type;
 | 
|    if (next_filter_.get())
 | 
|      next_filter_->SetMimeType(mime_type);
 | 
| 
 |