| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/filter.h" | 5 #include "net/base/filter.h" |
| 6 | 6 |
| 7 #include "base/file_path.h" | 7 #include "base/file_path.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "net/base/gzip_filter.h" | 9 #include "net/base/gzip_filter.h" |
| 10 #include "net/base/bzip2_filter.h" | 10 #include "net/base/bzip2_filter.h" |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 // When viewing a .svgz file, we need to uncompress it, but we don't | 110 // When viewing a .svgz file, we need to uncompress it, but we don't |
| 111 // want to do that when downloading. | 111 // want to do that when downloading. |
| 112 if (0 == extension.compare(FILE_PATH_LITERAL(".gz")) || | 112 if (0 == extension.compare(FILE_PATH_LITERAL(".gz")) || |
| 113 0 == extension.compare(FILE_PATH_LITERAL(".tgz")) || | 113 0 == extension.compare(FILE_PATH_LITERAL(".tgz")) || |
| 114 (0 == extension.compare(FILE_PATH_LITERAL(".svgz")) && | 114 (0 == extension.compare(FILE_PATH_LITERAL(".svgz")) && |
| 115 filter_context.IsDownload())) { | 115 filter_context.IsDownload())) { |
| 116 encoding_types->clear(); | 116 encoding_types->clear(); |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 | 119 |
| 120 // If the request was for SDCH content, then we might need additional fixups. |
| 120 if (!filter_context.IsSdchResponse()) { | 121 if (!filter_context.IsSdchResponse()) { |
| 122 // It was not an SDCH request, so we'll just record stats. |
| 121 if (1 < encoding_types->size()) { | 123 if (1 < encoding_types->size()) { |
| 122 // Multiple filters were intended to only be used for SDCH (thus far!) | 124 // Multiple filters were intended to only be used for SDCH (thus far!) |
| 123 SdchManager::SdchErrorRecovery( | 125 SdchManager::SdchErrorRecovery( |
| 124 SdchManager::MULTIENCODING_FOR_NON_SDCH_REQUEST); | 126 SdchManager::MULTIENCODING_FOR_NON_SDCH_REQUEST); |
| 125 } | 127 } |
| 126 if ((1 == encoding_types->size()) && | 128 if ((1 == encoding_types->size()) && |
| 127 (FILTER_TYPE_SDCH == encoding_types->front())) { | 129 (FILTER_TYPE_SDCH == encoding_types->front())) { |
| 128 SdchManager::SdchErrorRecovery( | 130 SdchManager::SdchErrorRecovery( |
| 129 SdchManager::SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST); | 131 SdchManager::SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST); |
| 130 } | 132 } |
| 131 return; | 133 return; |
| 132 } | 134 } |
| 133 | 135 |
| 134 // If content encoding included SDCH, then everything is fine. | 136 // The request was tagged as an SDCH request, which means the server supplied |
| 137 // a dictionary, and we advertised it in the request. Some proxies will do |
| 138 // very strange things to the request, or the response, so we have to handle |
| 139 // them gracefully. |
| 140 |
| 141 // If content encoding included SDCH, then everything is "relatively" fine. |
| 135 if (!encoding_types->empty() && | 142 if (!encoding_types->empty() && |
| 136 (FILTER_TYPE_SDCH == encoding_types->front())) { | 143 (FILTER_TYPE_SDCH == encoding_types->front())) { |
| 137 // Some proxies (found currently in Argentina) strip the Content-Encoding | 144 // Some proxies (found currently in Argentina) strip the Content-Encoding |
| 138 // text from "sdch,gzip" to a mere "sdch" without modifying the compressed | 145 // text from "sdch,gzip" to a mere "sdch" without modifying the compressed |
| 139 // payload. To handle this gracefully, we simulate the "probably" deleted | 146 // payload. To handle this gracefully, we simulate the "probably" deleted |
| 140 // ",gzip" by appending a tentative gzip decode, which will default to a | 147 // ",gzip" by appending a tentative gzip decode, which will default to a |
| 141 // no-op pass through filter if it doesn't get gzip headers where expected. | 148 // no-op pass through filter if it doesn't get gzip headers where expected. |
| 142 if (1 == encoding_types->size()) { | 149 if (1 == encoding_types->size()) { |
| 143 encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH); | 150 encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH); |
| 144 SdchManager::SdchErrorRecovery( | 151 SdchManager::SdchErrorRecovery( |
| 145 SdchManager::OPTIONAL_GUNZIP_ENCODING_ADDED); | 152 SdchManager::OPTIONAL_GUNZIP_ENCODING_ADDED); |
| 146 } | 153 } |
| 147 return; | 154 return; |
| 148 } | 155 } |
| 149 | 156 |
| 150 // SDCH "search results" protective hack: To make sure we don't break the only | 157 // There are now several cases to handle for an SDCH request. Foremost, if |
| 151 // currently deployed SDCH enabled server! Be VERY cautious about proxies that | 158 // the outbound request was stripped so as not to advertise support for |
| 152 // strip all content-encoding to not include sdch. IF we don't see content | 159 // encodings, we might get back content with no encoding, or (for example) |
| 153 // encodings that seem to match what we'd expect from a server that asked us | 160 // just gzip. We have to be sure that any changes we make allow for such |
| 154 // to use a dictionary (and we advertised said dictionary in the GET), then | 161 // minimal coding to work. That issue is why we use TENTATIVE filters if we |
| 155 // we set the encoding to (try to) use SDCH to decode. Note that SDCH will | 162 // add any, as those filters sniff the content, and act as pass-through |
| 156 // degrade into a pass-through filter if it doesn't have a viable dictionary | 163 // filters if headers are not found. |
| 157 // hash in its header. Also note that a solo "sdch" will implicitly create | 164 |
| 158 // a "sdch,gzip" decoding filter, where the gzip portion will degrade to a | 165 // If the outbound GET is not modified, then the server will generally try to |
| 159 // pass through if a gzip header is not encountered. Hence we can replace | 166 // send us SDCH encoded content. As that content returns, there are several |
| 160 // "gzip" with "sdch" and "everything will work." | 167 // corruptions of the header "content-encoding" that proxies may perform (and |
| 161 // The one failure mode comes when we advertise a dictionary, and the server | 168 // have been detected in the wild). We already dealt with the a honest |
| 162 // tries to *send* a gzipped file (not gzip encode content), and then we could | 169 // content encoding of "sdch,gzip" being corrupted into "sdch" with on change |
| 163 // do a gzip decode :-(. Since current server support does not ever see such | 170 // of the actual content. Another common corruption is to either disscard |
| 164 // a transfer, we are safe (for now). | 171 // the accurate content encoding, or to replace it with gzip only (again, with |
| 172 // no change in actual content). The last observed corruption it to actually |
| 173 // change the content, such as by re-gzipping it, and that may happen along |
| 174 // with corruption of the stated content encoding (wow!). |
| 175 |
| 176 // The one unresolved failure mode comes when we advertise a dictionary, and |
| 177 // the server tries to *send* a gzipped file (not gzip encode content), and |
| 178 // then we could do a gzip decode :-(. Since SDCH is only (currently) |
| 179 // supported server side on paths that only send HTML content, this mode has |
| 180 // never surfaced in the wild (and is unlikely to). |
| 181 // We will gather a lot of stats as we perform the fixups |
| 165 if (StartsWithASCII(mime_type, kTextHtml, false)) { | 182 if (StartsWithASCII(mime_type, kTextHtml, false)) { |
| 166 // Suspicious case: Advertised dictionary, but server didn't use sdch, and | 183 // Suspicious case: Advertised dictionary, but server didn't use sdch, and |
| 167 // we're HTML tagged. | 184 // we're HTML tagged. |
| 168 if (encoding_types->empty()) { | 185 if (encoding_types->empty()) { |
| 169 SdchManager::SdchErrorRecovery(SdchManager::ADDED_CONTENT_ENCODING); | 186 SdchManager::SdchErrorRecovery(SdchManager::ADDED_CONTENT_ENCODING); |
| 170 } else if (1 == encoding_types->size()) { | 187 } else if (1 == encoding_types->size()) { |
| 171 SdchManager::SdchErrorRecovery(SdchManager::FIXED_CONTENT_ENCODING); | 188 SdchManager::SdchErrorRecovery(SdchManager::FIXED_CONTENT_ENCODING); |
| 172 } else { | 189 } else { |
| 173 SdchManager::SdchErrorRecovery(SdchManager::FIXED_CONTENT_ENCODINGS); | 190 SdchManager::SdchErrorRecovery(SdchManager::FIXED_CONTENT_ENCODINGS); |
| 174 } | 191 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 186 SdchManager::BINARY_ADDED_CONTENT_ENCODING); | 203 SdchManager::BINARY_ADDED_CONTENT_ENCODING); |
| 187 } else if (1 == encoding_types->size()) { | 204 } else if (1 == encoding_types->size()) { |
| 188 SdchManager::SdchErrorRecovery( | 205 SdchManager::SdchErrorRecovery( |
| 189 SdchManager::BINARY_FIXED_CONTENT_ENCODING); | 206 SdchManager::BINARY_FIXED_CONTENT_ENCODING); |
| 190 } else { | 207 } else { |
| 191 SdchManager::SdchErrorRecovery( | 208 SdchManager::SdchErrorRecovery( |
| 192 SdchManager::BINARY_FIXED_CONTENT_ENCODINGS); | 209 SdchManager::BINARY_FIXED_CONTENT_ENCODINGS); |
| 193 } | 210 } |
| 194 } | 211 } |
| 195 | 212 |
| 196 encoding_types->clear(); | 213 // Leave the existing encoding type to be processed first, and add our |
| 197 encoding_types->push_back(FILTER_TYPE_SDCH_POSSIBLE); | 214 // tentative decodings to be done afterwards. Vodaphone UK reportedyl will |
| 198 encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH); | 215 // perform a second layer of gzip encoding atop the server's sdch,gzip |
| 216 // encoding, and then claim that the content encoding is a mere gzip. As a |
| 217 // result we'll need (in that case) to do the gunzip, plus our tentative |
| 218 // gunzip and tentative SDCH decoding. |
| 219 // This approach nicely handles the empty() list as well, and should work with |
| 220 // other (as yet undiscovered) proxies the choose to re-compressed with some |
| 221 // other encoding (such as bzip2, etc.). |
| 222 encoding_types->insert(encoding_types->begin(), |
| 223 FILTER_TYPE_GZIP_HELPING_SDCH); |
| 224 encoding_types->insert(encoding_types->begin(), FILTER_TYPE_SDCH_POSSIBLE); |
| 199 return; | 225 return; |
| 200 } | 226 } |
| 201 | 227 |
| 202 // static | 228 // static |
| 203 Filter* Filter::PrependNewFilter(FilterType type_id, | 229 Filter* Filter::PrependNewFilter(FilterType type_id, |
| 204 const FilterContext& filter_context, | 230 const FilterContext& filter_context, |
| 205 Filter* filter_list) { | 231 Filter* filter_list) { |
| 206 Filter* first_filter = NULL; // Soon to be start of chain. | 232 Filter* first_filter = NULL; // Soon to be start of chain. |
| 207 switch (type_id) { | 233 switch (type_id) { |
| 208 case FILTER_TYPE_GZIP_HELPING_SDCH: | 234 case FILTER_TYPE_GZIP_HELPING_SDCH: |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 | 386 |
| 361 DCHECK(stream_buffer()); | 387 DCHECK(stream_buffer()); |
| 362 // Bail out if there is more data in the stream buffer to be filtered. | 388 // Bail out if there is more data in the stream buffer to be filtered. |
| 363 if (!stream_buffer() || stream_data_len_) | 389 if (!stream_buffer() || stream_data_len_) |
| 364 return false; | 390 return false; |
| 365 | 391 |
| 366 next_stream_data_ = stream_buffer()->data(); | 392 next_stream_data_ = stream_buffer()->data(); |
| 367 stream_data_len_ = stream_data_len; | 393 stream_data_len_ = stream_data_len; |
| 368 return true; | 394 return true; |
| 369 } | 395 } |
| OLD | NEW |