Chromium Code Reviews

Side by Side Diff: net/filter/sdch_filter.cc

Issue 754433003: Update from https://crrev.com/305340 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « net/filter/sdch_filter.h ('k') | net/filter/sdch_filter_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/filter/sdch_filter.h" 5 #include "net/filter/sdch_filter.h"
6 6
7 #include <ctype.h> 7 #include <ctype.h>
8 #include <limits.h> 8 #include <limits.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 11
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/values.h" 14 #include "base/values.h"
15 #include "net/base/sdch_manager.h" 15 #include "net/base/sdch_manager.h"
16 #include "net/base/sdch_net_log_params.h" 16 #include "net/base/sdch_net_log_params.h"
17 #include "net/base/sdch_problem_codes.h"
17 #include "net/url_request/url_request_context.h" 18 #include "net/url_request/url_request_context.h"
18 19
19 #include "sdch/open-vcdiff/src/google/vcdecoder.h" 20 #include "sdch/open-vcdiff/src/google/vcdecoder.h"
20 21
21 namespace net { 22 namespace net {
22 23
23 namespace { 24 namespace {
24 25
25 // Disambiguate various types of responses that trigger a meta-refresh, 26 // Disambiguate various types of responses that trigger a meta-refresh,
26 // failure, or fallback to pass-through. 27 // failure, or fallback to pass-through.
(...skipping 217 matching lines...)
244 DCHECK_EQ(DECODING_ERROR, decoding_status_); 245 DCHECK_EQ(DECODING_ERROR, decoding_status_);
245 DCHECK_EQ(0u, dest_buffer_excess_index_); 246 DCHECK_EQ(0u, dest_buffer_excess_index_);
246 DCHECK(dest_buffer_excess_.empty()); 247 DCHECK(dest_buffer_excess_.empty());
247 // This is where we try very hard to do error recovery, and make this 248 // This is where we try very hard to do error recovery, and make this
248 // protocol robust in the face of proxies that do many different things. 249 // protocol robust in the face of proxies that do many different things.
249 // If we decide that things are looking very bad (too hard to recover), 250 // If we decide that things are looking very bad (too hard to recover),
250 // we may even issue a "meta-refresh" to reload the page without an SDCH 251 // we may even issue a "meta-refresh" to reload the page without an SDCH
251 // advertisement (so that we are sure we're not hurting anything). 252 // advertisement (so that we are sure we're not hurting anything).
252 // 253 //
253 // Watch out for an error page inserted by the proxy as part of a 40x 254 // Watch out for an error page inserted by the proxy as part of a 40x
254 // error response. When we see such content molestation, we certainly 255 // error response. When we see such content molestation, we certainly
255 // need to fall into the meta-refresh case. 256 // need to fall into the meta-refresh case.
256 ResponseCorruptionDetectionCause cause = RESPONSE_NONE; 257 ResponseCorruptionDetectionCause cause = RESPONSE_NONE;
257 if (filter_context_.GetResponseCode() == 404) { 258 if (filter_context_.GetResponseCode() == 404) {
258 // We could be more generous, but for now, only a "NOT FOUND" code will 259 // We could be more generous, but for now, only a "NOT FOUND" code will
259 // cause a pass through. All other bad codes will fall into a 260 // cause a pass through. All other bad codes will fall into a
260 // meta-refresh. 261 // meta-refresh.
261 LogSdchProblem(SDCH_PASS_THROUGH_404_CODE); 262 LogSdchProblem(SDCH_PASS_THROUGH_404_CODE);
262 cause = RESPONSE_404; 263 cause = RESPONSE_404;
263 decoding_status_ = PASS_THROUGH; 264 decoding_status_ = PASS_THROUGH;
264 } else if (filter_context_.GetResponseCode() != 200) { 265 } else if (filter_context_.GetResponseCode() != 200) {
265 // We need to meta-refresh, with SDCH disabled. 266 // We need to meta-refresh, with SDCH disabled.
266 cause = RESPONSE_NOT_200; 267 cause = RESPONSE_NOT_200;
267 } else if (filter_context_.IsCachedContent() 268 } else if (filter_context_.IsCachedContent()
268 && !dictionary_hash_is_plausible_) { 269 && !dictionary_hash_is_plausible_) {
269 // We must have hit the back button, and gotten content that was fetched 270 // We must have hit the back button, and gotten content that was fetched
270 // before we *really* advertised SDCH and a dictionary. 271 // before we *really* advertised SDCH and a dictionary.
271 LogSdchProblem(SDCH_PASS_THROUGH_OLD_CACHED); 272 LogSdchProblem(SDCH_PASS_THROUGH_OLD_CACHED);
272 decoding_status_ = PASS_THROUGH; 273 decoding_status_ = PASS_THROUGH;
273 cause = RESPONSE_OLD_UNENCODED; 274 cause = RESPONSE_OLD_UNENCODED;
274 } else if (possible_pass_through_) { 275 } else if (possible_pass_through_) {
275 // This is the potentially most graceful response. There really was no 276 // This is the potentially most graceful response. There really was no
276 // error. We were just overly cautious when we added a TENTATIVE_SDCH. 277 // error. We were just overly cautious when we added a TENTATIVE_SDCH.
277 // We added the sdch coding tag, and it should not have been added. 278 // We added the sdch coding tag, and it should not have been added.
278 // This can happen in server experiments, where the server decides 279 // This can happen in server experiments, where the server decides
279 // not to use sdch, even though there is a dictionary. To be 280 // not to use sdch, even though there is a dictionary. To be
280 // conservative, we locally added the tentative sdch (fearing that a 281 // conservative, we locally added the tentative sdch (fearing that a
281 // proxy stripped it!) and we must now recant (pass through). 282 // proxy stripped it!) and we must now recant (pass through).
282 // 283 //
283 // However.... just to be sure we don't get burned by proxies that 284 // However.... just to be sure we don't get burned by proxies that
284 // re-compress with gzip or other system, we can sniff to see if this 285 // re-compress with gzip or other system, we can sniff to see if this
285 // is compressed data etc. For now, we do nothing, which gets us into 286 // is compressed data etc. For now, we do nothing, which gets us into
286 // the meta-refresh result. 287 // the meta-refresh result.
287 // TODO(jar): Improve robustness by sniffing for valid text that we can 288 // TODO(jar): Improve robustness by sniffing for valid text that we can
288 // actual use re: decoding_status_ = PASS_THROUGH; 289 // actual use re: decoding_status_ = PASS_THROUGH;
289 cause = RESPONSE_TENTATIVE_SDCH; 290 cause = RESPONSE_TENTATIVE_SDCH;
290 } else if (dictionary_hash_is_plausible_) { 291 } else if (dictionary_hash_is_plausible_) {
291 // We need a meta-refresh since we don't have the dictionary. 292 // We need a meta-refresh since we don't have the dictionary.
292 // The common cause is a restart of the browser, where we try to render 293 // The common cause is a restart of the browser, where we try to render
293 // cached content that was saved when we had a dictionary. 294 // cached content that was saved when we had a dictionary.
294 cause = RESPONSE_NO_DICTIONARY; 295 cause = RESPONSE_NO_DICTIONARY;
295 } else if (filter_context_.SdchResponseExpected()) { 296 } else if (filter_context_.SdchDictionariesAdvertised()) {
296 // This is a very corrupt SDCH request response. We can't decode it. 297 // This is a very corrupt SDCH request response. We can't decode it.
297 // We'll use a meta-refresh, and get content without asking for SDCH. 298 // We'll use a meta-refresh, and get content without asking for SDCH.
298 // This will also progressively disable SDCH for this domain. 299 // This will also progressively disable SDCH for this domain.
299 cause = RESPONSE_CORRUPT_SDCH; 300 cause = RESPONSE_CORRUPT_SDCH;
300 } else { 301 } else {
301 // One of the first 9 bytes precluded consideration as a hash. 302 // One of the first 9 bytes precluded consideration as a hash.
302 // This can't be an SDCH payload, even though the server said it was. 303 // This can't be an SDCH payload, even though the server said it was.
303 // This is a major error, as the server or proxy tagged this SDCH even 304 // This is a major error, as the server or proxy tagged this SDCH even
304 // though it is not! 305 // though it is not!
305 // Meta-refresh won't help, as we didn't advertise an SDCH dictionary!! 306 // Meta-refresh won't help, as we didn't advertise an SDCH dictionary!!
306 // Worse yet, meta-refresh could lead to an infinite refresh loop. 307 // Worse yet, meta-refresh could lead to an infinite refresh loop.
(...skipping 63 matching lines...)
370 available_space -= amount; 371 available_space -= amount;
371 DCHECK_GE(available_space, 0); 372 DCHECK_GE(available_space, 0);
372 373
373 if (available_space <= 0) 374 if (available_space <= 0)
374 return FILTER_OK; 375 return FILTER_OK;
375 DCHECK(dest_buffer_excess_.empty()); 376 DCHECK(dest_buffer_excess_.empty());
376 DCHECK_EQ(0u, dest_buffer_excess_index_); 377 DCHECK_EQ(0u, dest_buffer_excess_index_);
377 378
378 if (decoding_status_ != DECODING_IN_PROGRESS) { 379 if (decoding_status_ != DECODING_IN_PROGRESS) {
379 if (META_REFRESH_RECOVERY == decoding_status_) { 380 if (META_REFRESH_RECOVERY == decoding_status_) {
380 // Absorb all input data. We've already output page reload HTML. 381 // Absorb all input data. We've already output page reload HTML.
381 next_stream_data_ = NULL; 382 next_stream_data_ = NULL;
382 stream_data_len_ = 0; 383 stream_data_len_ = 0;
383 return FILTER_NEED_MORE_DATA; 384 return FILTER_NEED_MORE_DATA;
384 } 385 }
385 if (PASS_THROUGH == decoding_status_) { 386 if (PASS_THROUGH == decoding_status_) {
386 // We must pass in available_space, but it will be changed to bytes_used. 387 // We must pass in available_space, but it will be changed to bytes_used.
387 FilterStatus result = CopyOut(dest_buffer, &available_space); 388 FilterStatus result = CopyOut(dest_buffer, &available_space);
388 // Accumulate the returned count of bytes_used (a.k.a., available_space). 389 // Accumulate the returned count of bytes_used (a.k.a., available_space).
389 *dest_len += available_space; 390 *dest_len += available_space;
390 return result; 391 return result;
(...skipping 43 matching lines...)
434 } 435 }
435 dictionary_hash_.append(next_stream_data_, bytes_needed); 436 dictionary_hash_.append(next_stream_data_, bytes_needed);
436 DCHECK(kServerIdLength == dictionary_hash_.size()); 437 DCHECK(kServerIdLength == dictionary_hash_.size());
437 stream_data_len_ -= bytes_needed; 438 stream_data_len_ -= bytes_needed;
438 DCHECK_LE(0, stream_data_len_); 439 DCHECK_LE(0, stream_data_len_);
439 if (stream_data_len_ > 0) 440 if (stream_data_len_ > 0)
440 next_stream_data_ += bytes_needed; 441 next_stream_data_ += bytes_needed;
441 else 442 else
442 next_stream_data_ = NULL; 443 next_stream_data_ = NULL;
443 444
444 DCHECK(!dictionary_.get()); 445 DCHECK(!dictionary_);
445 dictionary_hash_is_plausible_ = true; // Assume plausible, but check. 446 dictionary_hash_is_plausible_ = true; // Assume plausible, but check.
446 447
447 SdchProblemCode rv = SDCH_OK; 448 SdchProblemCode rv = SDCH_OK;
448 if ('\0' == dictionary_hash_[kServerIdLength - 1]) { 449 if ('\0' == dictionary_hash_[kServerIdLength - 1]) {
449 SdchManager* manager(url_request_context_->sdch_manager()); 450 std::string server_hash(dictionary_hash_, 0, kServerIdLength - 1);
450 rv = manager->GetVcdiffDictionary( 451 SdchManager::DictionarySet* handle =
451 std::string(dictionary_hash_, 0, kServerIdLength - 1), url_, 452 filter_context_.SdchDictionariesAdvertised();
452 &dictionary_); 453 if (handle)
453 if (rv == SDCH_DICTIONARY_HASH_NOT_FOUND) { 454 dictionary_ = handle->GetDictionary(server_hash);
454 DCHECK(dictionary_hash_.size() == kServerIdLength); 455 if (!dictionary_) {
455 // Since dictionary was not found, check to see if hash was even 456 // This is a hack. Naively, the dictionaries available for
456 // plausible. 457 // decoding should be only the ones advertised. However, there are
457 for (size_t i = 0; i < kServerIdLength - 1; ++i) { 458 // cases, specifically resources encoded with old dictionaries living
458 char base64_char = dictionary_hash_[i]; 459 // in the cache, that mean the full set of dictionaries should be made
459 if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) { 460 // available for decoding. It's not known how often this happens;
460 rv = SDCH_DICTIONARY_HASH_MALFORMED; 461 // if it happens rarely enough, this code can be removed.
461 dictionary_hash_is_plausible_ = false; 462 //
462 break; 463 // TODO(rdsmith): Long-term, a better solution is necessary, since
464 // an entry in the cache being encoded with the dictionary doesn't
465 // guarantee that the dictionary is present. That solution probably
466 // involves storing unencoded resources in the cache, but might
467 // involve evicting encoded resources on dictionary removal.
468 // See http://crbug.com/383405.
469 unexpected_dictionary_handle_ =
470 url_request_context_->sdch_manager()->GetDictionarySetByHash(
471 url_, server_hash, &rv);
472 if (unexpected_dictionary_handle_) {
473 dictionary_ = unexpected_dictionary_handle_->GetDictionary(server_hash);
474 // Override SDCH_OK rv; this is still worth logging.
475 rv = (filter_context_.IsCachedContent() ?
476 SDCH_UNADVERTISED_DICTIONARY_USED_CACHED :
477 SDCH_UNADVERTISED_DICTIONARY_USED);
478 } else {
479 // Since dictionary was not found, check to see if hash was
480 // even plausible.
481 DCHECK(dictionary_hash_.size() == kServerIdLength);
482 rv = SDCH_DICTIONARY_HASH_NOT_FOUND;
483 for (size_t i = 0; i < kServerIdLength - 1; ++i) {
484 char base64_char = dictionary_hash_[i];
485 if (!isalnum(base64_char) &&
486 '-' != base64_char && '_' != base64_char) {
487 dictionary_hash_is_plausible_ = false;
488 rv = SDCH_DICTIONARY_HASH_MALFORMED;
489 break;
490 }
463 } 491 }
464 } 492 }
465 } 493 }
466 } else { 494 } else {
467 dictionary_hash_is_plausible_ = false; 495 dictionary_hash_is_plausible_ = false;
468 rv = SDCH_DICTIONARY_HASH_MALFORMED; 496 rv = SDCH_DICTIONARY_HASH_MALFORMED;
469 } 497 }
470 if (rv != SDCH_OK) { 498
499 if (rv != SDCH_OK)
471 LogSdchProblem(rv); 500 LogSdchProblem(rv);
501
502 if (!dictionary_) {
472 decoding_status_ = DECODING_ERROR; 503 decoding_status_ = DECODING_ERROR;
473 return FILTER_ERROR; 504 return FILTER_ERROR;
474 } 505 }
475 DCHECK(dictionary_.get()); 506
476 vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder); 507 vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
477 vcdiff_streaming_decoder_->SetAllowVcdTarget(false); 508 vcdiff_streaming_decoder_->SetAllowVcdTarget(false);
478 vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(), 509 vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(),
479 dictionary_->text().size()); 510 dictionary_->text().size());
480 decoding_status_ = DECODING_IN_PROGRESS; 511 decoding_status_ = DECODING_IN_PROGRESS;
481 return FILTER_OK; 512 return FILTER_OK;
482 } 513 }
483 514
484 int SdchFilter::OutputBufferExcess(char* const dest_buffer, 515 int SdchFilter::OutputBufferExcess(char* const dest_buffer,
485 size_t available_space) { 516 size_t available_space) {
(...skipping 14 matching lines...)
500 } 531 }
501 532
502 void SdchFilter::LogSdchProblem(SdchProblemCode problem) { 533 void SdchFilter::LogSdchProblem(SdchProblemCode problem) {
503 SdchManager::SdchErrorRecovery(problem); 534 SdchManager::SdchErrorRecovery(problem);
504 filter_context_.GetNetLog().AddEvent( 535 filter_context_.GetNetLog().AddEvent(
505 NetLog::TYPE_SDCH_DECODING_ERROR, 536 NetLog::TYPE_SDCH_DECODING_ERROR,
506 base::Bind(&NetLogSdchResourceProblemCallback, problem)); 537 base::Bind(&NetLogSdchResourceProblemCallback, problem));
507 } 538 }
508 539
509 } // namespace net 540 } // namespace net
OLDNEW
« no previous file with comments | « net/filter/sdch_filter.h ('k') | net/filter/sdch_filter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine