Index: net/filter/sdch_filter.cc |
diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc |
index d1eb7f4d12d51a24cc64909f6244b094019c5dc5..30392cd06ad07166144dbadfaca4543f23a56878 100644 |
--- a/net/filter/sdch_filter.cc |
+++ b/net/filter/sdch_filter.cc |
@@ -14,6 +14,7 @@ |
#include "base/values.h" |
#include "net/base/sdch_manager.h" |
#include "net/base/sdch_net_log_params.h" |
+#include "net/base/sdch_problem_codes.h" |
#include "net/url_request/url_request_context.h" |
#include "sdch/open-vcdiff/src/google/vcdecoder.h" |
@@ -251,12 +252,12 @@ Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer, |
// advertisement (so that we are sure we're not hurting anything). |
// |
// Watch out for an error page inserted by the proxy as part of a 40x |
- // error response. When we see such content molestation, we certainly |
+ // error response. When we see such content molestation, we certainly |
// need to fall into the meta-refresh case. |
ResponseCorruptionDetectionCause cause = RESPONSE_NONE; |
if (filter_context_.GetResponseCode() == 404) { |
// We could be more generous, but for now, only a "NOT FOUND" code will |
- // cause a pass through. All other bad codes will fall into a |
+ // cause a pass through. All other bad codes will fall into a |
// meta-refresh. |
LogSdchProblem(SDCH_PASS_THROUGH_404_CODE); |
cause = RESPONSE_404; |
@@ -276,13 +277,13 @@ Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer, |
// error. We were just overly cautious when we added a TENTATIVE_SDCH. |
// We added the sdch coding tag, and it should not have been added. |
// This can happen in server experiments, where the server decides |
- // not to use sdch, even though there is a dictionary. To be |
+ // not to use sdch, even though there is a dictionary. To be |
// conservative, we locally added the tentative sdch (fearing that a |
// proxy stripped it!) and we must now recant (pass through). |
// |
// However.... just to be sure we don't get burned by proxies that |
// re-compress with gzip or other system, we can sniff to see if this |
- // is compressed data etc. For now, we do nothing, which gets us into |
+ // is compressed data etc. For now, we do nothing, which gets us into |
// the meta-refresh result. |
// TODO(jar): Improve robustness by sniffing for valid text that we can |
// actual use re: decoding_status_ = PASS_THROUGH; |
@@ -292,8 +293,8 @@ Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer, |
// The common cause is a restart of the browser, where we try to render |
// cached content that was saved when we had a dictionary. |
cause = RESPONSE_NO_DICTIONARY; |
- } else if (filter_context_.SdchResponseExpected()) { |
- // This is a very corrupt SDCH request response. We can't decode it. |
+ } else if (filter_context_.SdchDictionariesAdvertised()) { |
+ // This is a very corrupt SDCH request response. We can't decode it. |
// We'll use a meta-refresh, and get content without asking for SDCH. |
// This will also progressively disable SDCH for this domain. |
cause = RESPONSE_CORRUPT_SDCH; |
@@ -377,7 +378,7 @@ Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer, |
if (decoding_status_ != DECODING_IN_PROGRESS) { |
if (META_REFRESH_RECOVERY == decoding_status_) { |
- // Absorb all input data. We've already output page reload HTML. |
+ // Absorb all input data. We've already output page reload HTML. |
next_stream_data_ = NULL; |
stream_data_len_ = 0; |
return FILTER_NEED_MORE_DATA; |
@@ -441,25 +442,52 @@ Filter::FilterStatus SdchFilter::InitializeDictionary() { |
else |
next_stream_data_ = NULL; |
- DCHECK(!dictionary_.get()); |
+ DCHECK(!dictionary_); |
dictionary_hash_is_plausible_ = true; // Assume plausible, but check. |
SdchProblemCode rv = SDCH_OK; |
if ('\0' == dictionary_hash_[kServerIdLength - 1]) { |
- SdchManager* manager(url_request_context_->sdch_manager()); |
- rv = manager->GetVcdiffDictionary( |
- std::string(dictionary_hash_, 0, kServerIdLength - 1), url_, |
- &dictionary_); |
- if (rv == SDCH_DICTIONARY_HASH_NOT_FOUND) { |
- DCHECK(dictionary_hash_.size() == kServerIdLength); |
- // Since dictionary was not found, check to see if hash was even |
- // plausible. |
- for (size_t i = 0; i < kServerIdLength - 1; ++i) { |
- char base64_char = dictionary_hash_[i]; |
- if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) { |
- rv = SDCH_DICTIONARY_HASH_MALFORMED; |
- dictionary_hash_is_plausible_ = false; |
- break; |
+ std::string server_hash(dictionary_hash_, 0, kServerIdLength - 1); |
+ SdchManager::DictionarySet* handle = |
+ filter_context_.SdchDictionariesAdvertised(); |
+ if (handle) |
+ dictionary_ = handle->GetDictionary(server_hash); |
+ if (!dictionary_) { |
+ // This is a hack. Naively, the dictionaries available for |
+ // decoding should be only the ones advertised. However, there are |
+ // cases, specifically resources encoded with old dictionaries living |
+ // in the cache, that mean the full set of dictionaries should be made |
+ // available for decoding. It's not known how often this happens; |
+ // if it happens rarely enough, this code can be removed. |
+ // |
+ // TODO(rdsmith): Long-term, a better solution is necessary, since |
+ // an entry in the cache being encoded with the dictionary doesn't |
+ // guarantee that the dictionary is present. That solution probably |
+ // involves storing unencoded resources in the cache, but might |
+ // involve evicting encoded resources on dictionary removal. |
+ // See http://crbug.com/383405. |
+ unexpected_dictionary_handle_ = |
+ url_request_context_->sdch_manager()->GetDictionarySetByHash( |
+ url_, server_hash, &rv); |
+ if (unexpected_dictionary_handle_) { |
+ dictionary_ = unexpected_dictionary_handle_->GetDictionary(server_hash); |
+ // Override SDCH_OK rv; this is still worth logging. |
+ rv = (filter_context_.IsCachedContent() ? |
+ SDCH_UNADVERTISED_DICTIONARY_USED_CACHED : |
+ SDCH_UNADVERTISED_DICTIONARY_USED); |
+ } else { |
+ // Since dictionary was not found, check to see if hash was |
+ // even plausible. |
+ DCHECK(dictionary_hash_.size() == kServerIdLength); |
+ rv = SDCH_DICTIONARY_HASH_NOT_FOUND; |
+ for (size_t i = 0; i < kServerIdLength - 1; ++i) { |
+ char base64_char = dictionary_hash_[i]; |
+ if (!isalnum(base64_char) && |
+ '-' != base64_char && '_' != base64_char) { |
+ dictionary_hash_is_plausible_ = false; |
+ rv = SDCH_DICTIONARY_HASH_MALFORMED; |
+ break; |
+ } |
} |
} |
} |
@@ -467,12 +495,15 @@ Filter::FilterStatus SdchFilter::InitializeDictionary() { |
dictionary_hash_is_plausible_ = false; |
rv = SDCH_DICTIONARY_HASH_MALFORMED; |
} |
- if (rv != SDCH_OK) { |
+ |
+ if (rv != SDCH_OK) |
LogSdchProblem(rv); |
+ |
+ if (!dictionary_) { |
decoding_status_ = DECODING_ERROR; |
return FILTER_ERROR; |
} |
- DCHECK(dictionary_.get()); |
+ |
vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder); |
vcdiff_streaming_decoder_->SetAllowVcdTarget(false); |
vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(), |