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