| Index: net/filter/sdch_filter.cc
|
| diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc
|
| deleted file mode 100644
|
| index 85be8905fa76cb179dbbcfb3b629a9b6e48b381a..0000000000000000000000000000000000000000
|
| --- a/net/filter/sdch_filter.cc
|
| +++ /dev/null
|
| @@ -1,568 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/filter/sdch_filter.h"
|
| -
|
| -#include <ctype.h>
|
| -#include <limits.h>
|
| -#include <algorithm>
|
| -#include <utility>
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/metrics/histogram_macros.h"
|
| -#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"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -const size_t kServerIdLength = 9; // Dictionary hash plus null from server.
|
| -
|
| -// Disambiguate various types of responses that trigger a meta-refresh,
|
| -// failure, or fallback to pass-through.
|
| -enum ResponseCorruptionDetectionCause {
|
| - RESPONSE_NONE,
|
| -
|
| - // 404 Http Response Code
|
| - RESPONSE_404 = 1,
|
| -
|
| - // Not a 200 Http Response Code
|
| - RESPONSE_NOT_200 = 2,
|
| -
|
| - // Cached before dictionary retrieved.
|
| - RESPONSE_OLD_UNENCODED = 3,
|
| -
|
| - // Speculative but incorrect SDCH filtering was added added.
|
| - RESPONSE_TENTATIVE_SDCH = 4,
|
| -
|
| - // Missing correct dict for decoding.
|
| - RESPONSE_NO_DICTIONARY = 5,
|
| -
|
| - // Not an SDCH response but should be.
|
| - RESPONSE_CORRUPT_SDCH = 6,
|
| -
|
| - // No dictionary was advertised with the request, the server claims
|
| - // to have encoded with SDCH anyway, but it isn't an SDCH response.
|
| - RESPONSE_ENCODING_LIE = 7,
|
| -
|
| - RESPONSE_MAX,
|
| -};
|
| -
|
| -const char* ResponseCorruptionDetectionCauseToString(
|
| - ResponseCorruptionDetectionCause cause) {
|
| - const char* cause_string = "<unknown>";
|
| - switch (cause) {
|
| - case RESPONSE_NONE:
|
| - cause_string = "NONE";
|
| - break;
|
| - case RESPONSE_404:
|
| - cause_string = "404";
|
| - break;
|
| - case RESPONSE_NOT_200:
|
| - cause_string = "NOT_200";
|
| - break;
|
| - case RESPONSE_OLD_UNENCODED:
|
| - cause_string = "OLD_UNENCODED";
|
| - break;
|
| - case RESPONSE_TENTATIVE_SDCH:
|
| - cause_string = "TENTATIVE_SDCH";
|
| - break;
|
| - case RESPONSE_NO_DICTIONARY:
|
| - cause_string = "NO_DICTIONARY";
|
| - break;
|
| - case RESPONSE_CORRUPT_SDCH:
|
| - cause_string = "CORRUPT_SDCH";
|
| - break;
|
| - case RESPONSE_ENCODING_LIE:
|
| - cause_string = "ENCODING_LIE";
|
| - break;
|
| - case RESPONSE_MAX:
|
| - cause_string = "<Error: max enum value>";
|
| - break;
|
| - }
|
| - return cause_string;
|
| -}
|
| -
|
| -std::unique_ptr<base::Value> NetLogSdchResponseCorruptionDetectionCallback(
|
| - ResponseCorruptionDetectionCause cause,
|
| - bool cached,
|
| - NetLogCaptureMode capture_mode) {
|
| - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
|
| - dict->SetString("cause", ResponseCorruptionDetectionCauseToString(cause));
|
| - dict->SetBoolean("cached", cached);
|
| - return std::move(dict);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -SdchFilter::SdchFilter(FilterType type, const FilterContext& filter_context)
|
| - : Filter(type),
|
| - filter_context_(filter_context),
|
| - decoding_status_(DECODING_UNINITIALIZED),
|
| - dictionary_hash_(),
|
| - dictionary_hash_is_plausible_(false),
|
| - url_request_context_(filter_context.GetURLRequestContext()),
|
| - dest_buffer_excess_(),
|
| - dest_buffer_excess_index_(0),
|
| - source_bytes_(0),
|
| - output_bytes_(0),
|
| - possible_pass_through_(false) {
|
| - bool success = filter_context.GetMimeType(&mime_type_);
|
| - DCHECK(success);
|
| - success = filter_context.GetURL(&url_);
|
| - DCHECK(success);
|
| - DCHECK(url_request_context_->sdch_manager());
|
| -}
|
| -
|
| -SdchFilter::~SdchFilter() {
|
| - // All code here is for gathering stats, and can be removed when SDCH is
|
| - // considered stable.
|
| -
|
| - // References to filter_context_ and vcdiff_streaming_decoder_ (which
|
| - // contains a reference to the dictionary text) are safe because
|
| - // ~URLRequestHttpJob calls URLRequestJob::DestroyFilters, destroying
|
| - // this object before the filter context in URLRequestHttpJob and its
|
| - // members go out of scope.
|
| -
|
| - static int filter_use_count = 0;
|
| - ++filter_use_count;
|
| - if (META_REFRESH_RECOVERY == decoding_status_) {
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.FilterUseBeforeDisabling", filter_use_count);
|
| - }
|
| -
|
| - if (vcdiff_streaming_decoder_.get()) {
|
| - if (!vcdiff_streaming_decoder_->FinishDecoding()) {
|
| - decoding_status_ = DECODING_ERROR;
|
| - LogSdchProblem(SDCH_INCOMPLETE_SDCH_CONTENT);
|
| - // Make it possible for the user to hit reload, and get non-sdch content.
|
| - // Note this will "wear off" quickly enough, and is just meant to assure
|
| - // in some rare case that the user is not stuck.
|
| - url_request_context_->sdch_manager()->BlacklistDomain(
|
| - url_, SDCH_INCOMPLETE_SDCH_CONTENT);
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.PartialBytesIn",
|
| - static_cast<int>(filter_context_.GetByteReadCount()));
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffIn", source_bytes_);
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffOut", output_bytes_);
|
| - }
|
| - }
|
| -
|
| - if (!dest_buffer_excess_.empty()) {
|
| - // Filter chaining error, or premature teardown.
|
| - LogSdchProblem(SDCH_UNFLUSHED_CONTENT);
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBytesIn",
|
| - static_cast<int>(filter_context_.GetByteReadCount()));
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBufferSize",
|
| - dest_buffer_excess_.size());
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedVcdiffIn", source_bytes_);
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedVcdiffOut", output_bytes_);
|
| - }
|
| -
|
| - if (filter_context_.IsCachedContent()) {
|
| - // Not a real error, but it is useful to have this tally.
|
| - // TODO(jar): Remove this stat after SDCH stability is validated.
|
| - LogSdchProblem(SDCH_CACHE_DECODED);
|
| - return; // We don't need timing stats, and we aready got ratios.
|
| - }
|
| -
|
| - switch (decoding_status_) {
|
| - case DECODING_IN_PROGRESS: {
|
| - if (output_bytes_) {
|
| - UMA_HISTOGRAM_PERCENTAGE("Sdch3.Network_Decode_Ratio_a",
|
| - static_cast<int>(
|
| - (filter_context_.GetByteReadCount() * 100) / output_bytes_));
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.NetworkBytesSavedByCompression",
|
| - output_bytes_ - source_bytes_);
|
| - }
|
| - UMA_HISTOGRAM_COUNTS("Sdch3.Network_Decode_Bytes_VcdiffOut_a",
|
| - output_bytes_);
|
| - filter_context_.RecordPacketStats(FilterContext::SDCH_DECODE);
|
| -
|
| - // Allow latency experiments to proceed.
|
| - url_request_context_->sdch_manager()->SetAllowLatencyExperiment(
|
| - url_, true);
|
| -
|
| - // Notify successful dictionary usage.
|
| - url_request_context_->sdch_manager()->OnDictionaryUsed(
|
| - std::string(dictionary_hash_, 0, kServerIdLength - 1));
|
| -
|
| - return;
|
| - }
|
| - case PASS_THROUGH: {
|
| - filter_context_.RecordPacketStats(FilterContext::SDCH_PASSTHROUGH);
|
| - return;
|
| - }
|
| - case DECODING_UNINITIALIZED: {
|
| - LogSdchProblem(SDCH_UNINITIALIZED);
|
| - return;
|
| - }
|
| - case WAITING_FOR_DICTIONARY_SELECTION: {
|
| - LogSdchProblem(SDCH_PRIOR_TO_DICTIONARY);
|
| - return;
|
| - }
|
| - case DECODING_ERROR: {
|
| - LogSdchProblem(SDCH_DECODE_ERROR);
|
| - return;
|
| - }
|
| - case META_REFRESH_RECOVERY: {
|
| - // Already accounted for when set.
|
| - return;
|
| - }
|
| - } // end of switch.
|
| -}
|
| -
|
| -bool SdchFilter::InitDecoding(Filter::FilterType filter_type) {
|
| - if (decoding_status_ != DECODING_UNINITIALIZED)
|
| - return false;
|
| -
|
| - // Handle case where sdch filter is guessed, but not required.
|
| - if (FILTER_TYPE_SDCH_POSSIBLE == filter_type)
|
| - possible_pass_through_ = true;
|
| -
|
| - // Initialize decoder only after we have a dictionary in hand.
|
| - decoding_status_ = WAITING_FOR_DICTIONARY_SELECTION;
|
| - return true;
|
| -}
|
| -
|
| -#ifndef NDEBUG
|
| -static const char* kDecompressionErrorHtml =
|
| - "<head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0\"></head>"
|
| - "<div style=\"position:fixed;top:0;left:0;width:100%;border-width:thin;"
|
| - "border-color:black;border-style:solid;text-align:left;font-family:arial;"
|
| - "font-size:10pt;foreground-color:black;background-color:white\">"
|
| - "An error occurred. This page will be reloaded shortly. "
|
| - "Or press the \"reload\" button now to reload it immediately."
|
| - "</div>";
|
| -#else
|
| -static const char* kDecompressionErrorHtml =
|
| - "<head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0\"></head>";
|
| -#endif
|
| -
|
| -Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer,
|
| - int* dest_len) {
|
| - int available_space = *dest_len;
|
| - *dest_len = 0; // Nothing output yet.
|
| -
|
| - if (!dest_buffer || available_space <= 0)
|
| - return FILTER_ERROR;
|
| -
|
| - if (WAITING_FOR_DICTIONARY_SELECTION == decoding_status_) {
|
| - FilterStatus status = InitializeDictionary();
|
| - if (FILTER_NEED_MORE_DATA == status)
|
| - return FILTER_NEED_MORE_DATA;
|
| - if (FILTER_ERROR == status) {
|
| - DCHECK_EQ(DECODING_ERROR, decoding_status_);
|
| - DCHECK_EQ(0u, dest_buffer_excess_index_);
|
| - DCHECK(dest_buffer_excess_.empty());
|
| - // This is where we try very hard to do error recovery, and make this
|
| - // protocol robust in the face of proxies that do many different things.
|
| - // If we decide that things are looking very bad (too hard to recover),
|
| - // we may even issue a "meta-refresh" to reload the page without an SDCH
|
| - // 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
|
| - // 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
|
| - // meta-refresh.
|
| - LogSdchProblem(SDCH_PASS_THROUGH_404_CODE);
|
| - cause = RESPONSE_404;
|
| - decoding_status_ = PASS_THROUGH;
|
| - } else if (filter_context_.GetResponseCode() != 200) {
|
| - // We need to meta-refresh, with SDCH disabled.
|
| - cause = RESPONSE_NOT_200;
|
| - } else if (filter_context_.IsCachedContent()
|
| - && !dictionary_hash_is_plausible_) {
|
| - // We must have hit the back button, and gotten content that was fetched
|
| - // before we *really* advertised SDCH and a dictionary.
|
| - LogSdchProblem(SDCH_PASS_THROUGH_OLD_CACHED);
|
| - decoding_status_ = PASS_THROUGH;
|
| - cause = RESPONSE_OLD_UNENCODED;
|
| - } else if (possible_pass_through_) {
|
| - // This is the potentially most graceful response. There really was no
|
| - // 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
|
| - // 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
|
| - // the meta-refresh result.
|
| - // TODO(jar): Improve robustness by sniffing for valid text that we can
|
| - // actual use re: decoding_status_ = PASS_THROUGH;
|
| - cause = RESPONSE_TENTATIVE_SDCH;
|
| - } else if (dictionary_hash_is_plausible_) {
|
| - // We need a meta-refresh since we don't have the dictionary.
|
| - // 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_.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;
|
| - } else {
|
| - // One of the first 9 bytes precluded consideration as a hash.
|
| - // This can't be an SDCH payload, even though the server said it was.
|
| - // This is a major error, as the server or proxy tagged this SDCH even
|
| - // though it is not!
|
| - // Meta-refresh won't help, as we didn't advertise an SDCH dictionary!!
|
| - // Worse yet, meta-refresh could lead to an infinite refresh loop.
|
| - LogSdchProblem(SDCH_PASSING_THROUGH_NON_SDCH);
|
| - decoding_status_ = PASS_THROUGH;
|
| - // ... but further back-off on advertising SDCH support.
|
| - url_request_context_->sdch_manager()->BlacklistDomain(
|
| - url_, SDCH_PASSING_THROUGH_NON_SDCH);
|
| - cause = RESPONSE_ENCODING_LIE;
|
| - }
|
| - DCHECK_NE(RESPONSE_NONE, cause);
|
| -
|
| - // Use if statement rather than ?: because UMA_HISTOGRAM_ENUMERATION
|
| - // caches the histogram name based on the call site.
|
| - if (filter_context_.IsCachedContent()) {
|
| - UMA_HISTOGRAM_ENUMERATION(
|
| - "Sdch3.ResponseCorruptionDetection.Cached", cause, RESPONSE_MAX);
|
| - } else {
|
| - UMA_HISTOGRAM_ENUMERATION(
|
| - "Sdch3.ResponseCorruptionDetection.Uncached", cause, RESPONSE_MAX);
|
| - }
|
| - filter_context_.GetNetLog().AddEvent(
|
| - NetLog::TYPE_SDCH_RESPONSE_CORRUPTION_DETECTION,
|
| - base::Bind(&NetLogSdchResponseCorruptionDetectionCallback, cause,
|
| - filter_context_.IsCachedContent()));
|
| -
|
| - if (decoding_status_ == PASS_THROUGH) {
|
| - dest_buffer_excess_ = dictionary_hash_; // Send what we scanned.
|
| - } else {
|
| - // This is where we try to do the expensive meta-refresh.
|
| - if (std::string::npos == mime_type_.find("text/html")) {
|
| - // Since we can't do a meta-refresh (along with an exponential
|
| - // backoff), we'll just make sure this NEVER happens again.
|
| - SdchProblemCode problem = (filter_context_.IsCachedContent()
|
| - ? SDCH_CACHED_META_REFRESH_UNSUPPORTED
|
| - : SDCH_META_REFRESH_UNSUPPORTED);
|
| - url_request_context_->sdch_manager()->BlacklistDomainForever(
|
| - url_, problem);
|
| - LogSdchProblem(problem);
|
| - return FILTER_ERROR;
|
| - }
|
| - // HTML content means we can issue a meta-refresh, and get the content
|
| - // again, perhaps without SDCH (to be safe).
|
| - if (filter_context_.IsCachedContent()) {
|
| - // Cached content is probably a startup tab, so we'll just get fresh
|
| - // content and try again, without disabling sdch.
|
| - LogSdchProblem(SDCH_META_REFRESH_CACHED_RECOVERY);
|
| - } else {
|
| - // Since it wasn't in the cache, we definately need at least some
|
| - // period of blacklisting to get the correct content.
|
| - url_request_context_->sdch_manager()->BlacklistDomain(
|
| - url_, SDCH_META_REFRESH_RECOVERY);
|
| - LogSdchProblem(SDCH_META_REFRESH_RECOVERY);
|
| - }
|
| - decoding_status_ = META_REFRESH_RECOVERY;
|
| - // Issue a meta redirect with SDCH disabled.
|
| - dest_buffer_excess_ = kDecompressionErrorHtml;
|
| - }
|
| - } else {
|
| - DCHECK_EQ(DECODING_IN_PROGRESS, decoding_status_);
|
| - }
|
| - }
|
| -
|
| - int amount = OutputBufferExcess(dest_buffer, available_space);
|
| - *dest_len += amount;
|
| - dest_buffer += amount;
|
| - available_space -= amount;
|
| - DCHECK_GE(available_space, 0);
|
| -
|
| - if (available_space <= 0)
|
| - return FILTER_OK;
|
| - DCHECK(dest_buffer_excess_.empty());
|
| - DCHECK_EQ(0u, dest_buffer_excess_index_);
|
| -
|
| - if (decoding_status_ != DECODING_IN_PROGRESS) {
|
| - if (META_REFRESH_RECOVERY == decoding_status_) {
|
| - // Absorb all input data. We've already output page reload HTML.
|
| - next_stream_data_ = NULL;
|
| - stream_data_len_ = 0;
|
| - return FILTER_NEED_MORE_DATA;
|
| - }
|
| - if (PASS_THROUGH == decoding_status_) {
|
| - // We must pass in available_space, but it will be changed to bytes_used.
|
| - FilterStatus result = CopyOut(dest_buffer, &available_space);
|
| - // Accumulate the returned count of bytes_used (a.k.a., available_space).
|
| - *dest_len += available_space;
|
| - return result;
|
| - }
|
| - DCHECK(false);
|
| - decoding_status_ = DECODING_ERROR;
|
| - return FILTER_ERROR;
|
| - }
|
| -
|
| - if (!next_stream_data_ || stream_data_len_ <= 0)
|
| - return FILTER_NEED_MORE_DATA;
|
| -
|
| - // A note on accounting: DecodeChunk() appends to its output buffer, so any
|
| - // preexisting data in |dest_buffer_excess_| could skew the value of
|
| - // |output_bytes_|. However, OutputBufferExcess guarantees that it will
|
| - // consume all of |dest_buffer_excess_| when called above unless the
|
| - // destination buffer runs out of space, and if the destination buffer runs
|
| - // out of space, this code returns FILTER_OK early above. Therefore, if
|
| - // execution reaches this point, |dest_buffer_excess_| is empty, which is
|
| - // DCHECKed above.
|
| - bool ret = vcdiff_streaming_decoder_->DecodeChunk(
|
| - next_stream_data_, stream_data_len_, &dest_buffer_excess_);
|
| - // Assume all data was used in decoding.
|
| - next_stream_data_ = NULL;
|
| - source_bytes_ += stream_data_len_;
|
| - stream_data_len_ = 0;
|
| - output_bytes_ += dest_buffer_excess_.size();
|
| - if (!ret) {
|
| - vcdiff_streaming_decoder_.reset(NULL); // Don't call it again.
|
| - decoding_status_ = DECODING_ERROR;
|
| - LogSdchProblem(SDCH_DECODE_BODY_ERROR);
|
| - return FILTER_ERROR;
|
| - }
|
| -
|
| - amount = OutputBufferExcess(dest_buffer, available_space);
|
| - *dest_len += amount;
|
| - dest_buffer += amount;
|
| - available_space -= amount;
|
| - if (0 == available_space && !dest_buffer_excess_.empty())
|
| - return FILTER_OK;
|
| - return FILTER_NEED_MORE_DATA;
|
| -}
|
| -
|
| -Filter::FilterStatus SdchFilter::InitializeDictionary() {
|
| - size_t bytes_needed = kServerIdLength - dictionary_hash_.size();
|
| - DCHECK_GT(bytes_needed, 0u);
|
| - if (!next_stream_data_)
|
| - return FILTER_NEED_MORE_DATA;
|
| - if (static_cast<size_t>(stream_data_len_) < bytes_needed) {
|
| - dictionary_hash_.append(next_stream_data_, stream_data_len_);
|
| - next_stream_data_ = NULL;
|
| - stream_data_len_ = 0;
|
| - return FILTER_NEED_MORE_DATA;
|
| - }
|
| - dictionary_hash_.append(next_stream_data_, bytes_needed);
|
| - DCHECK(kServerIdLength == dictionary_hash_.size());
|
| - stream_data_len_ -= bytes_needed;
|
| - DCHECK_LE(0, stream_data_len_);
|
| - if (stream_data_len_ > 0)
|
| - next_stream_data_ += bytes_needed;
|
| - else
|
| - next_stream_data_ = NULL;
|
| -
|
| - const std::string* dictionary_text = nullptr;
|
| - dictionary_hash_is_plausible_ = true; // Assume plausible, but check.
|
| -
|
| - SdchProblemCode rv = SDCH_OK;
|
| - if ('\0' == dictionary_hash_[kServerIdLength - 1]) {
|
| - std::string server_hash(dictionary_hash_, 0, kServerIdLength - 1);
|
| - SdchManager::DictionarySet* handle =
|
| - filter_context_.SdchDictionariesAdvertised();
|
| - if (handle)
|
| - dictionary_text = handle->GetDictionaryText(server_hash);
|
| - if (!dictionary_text) {
|
| - // 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_text =
|
| - unexpected_dictionary_handle_->GetDictionaryText(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;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - } else {
|
| - dictionary_hash_is_plausible_ = false;
|
| - rv = SDCH_DICTIONARY_HASH_MALFORMED;
|
| - }
|
| -
|
| - if (rv != SDCH_OK)
|
| - LogSdchProblem(rv);
|
| -
|
| - if (!dictionary_text) {
|
| - decoding_status_ = DECODING_ERROR;
|
| - return FILTER_ERROR;
|
| - }
|
| -
|
| - vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
|
| - vcdiff_streaming_decoder_->SetAllowVcdTarget(false);
|
| -
|
| - // The validity of the dictionary_text pointer is guaranteed for the
|
| - // lifetime of the SdchFilter by the ownership of the DictionarySet by
|
| - // the FilterContext/URLRequestHttpJob. All URLRequestJob filters are
|
| - // torn down in ~URLRequestHttpJob by a call to
|
| - // URLRequestJob::DestroyFilters.
|
| - vcdiff_streaming_decoder_->StartDecoding(dictionary_text->data(),
|
| - dictionary_text->size());
|
| - decoding_status_ = DECODING_IN_PROGRESS;
|
| - return FILTER_OK;
|
| -}
|
| -
|
| -int SdchFilter::OutputBufferExcess(char* const dest_buffer,
|
| - size_t available_space) {
|
| - if (dest_buffer_excess_.empty())
|
| - return 0;
|
| - DCHECK(dest_buffer_excess_.size() > dest_buffer_excess_index_);
|
| - size_t amount = std::min(available_space,
|
| - dest_buffer_excess_.size() - dest_buffer_excess_index_);
|
| - memcpy(dest_buffer, dest_buffer_excess_.data() + dest_buffer_excess_index_,
|
| - amount);
|
| - dest_buffer_excess_index_ += amount;
|
| - if (dest_buffer_excess_.size() <= dest_buffer_excess_index_) {
|
| - DCHECK(dest_buffer_excess_.size() == dest_buffer_excess_index_);
|
| - dest_buffer_excess_.clear();
|
| - dest_buffer_excess_index_ = 0;
|
| - }
|
| - return amount;
|
| -}
|
| -
|
| -void SdchFilter::LogSdchProblem(SdchProblemCode problem) {
|
| - SdchManager::SdchErrorRecovery(problem);
|
| - filter_context_.GetNetLog().AddEvent(
|
| - NetLog::TYPE_SDCH_DECODING_ERROR,
|
| - base::Bind(&NetLogSdchResourceProblemCallback, problem));
|
| -}
|
| -
|
| -} // namespace net
|
|
|