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