| OLD | NEW | 
|    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 "net/base/sdch_manager.h" |   15 #include "net/base/sdch_manager.h" | 
 |   16 #include "net/base/sdch_net_log_params.h" | 
|   15 #include "net/url_request/url_request_context.h" |   17 #include "net/url_request/url_request_context.h" | 
|   16  |   18  | 
|   17 #include "sdch/open-vcdiff/src/google/vcdecoder.h" |   19 #include "sdch/open-vcdiff/src/google/vcdecoder.h" | 
|   18  |   20  | 
|   19 namespace net { |   21 namespace net { | 
|   20  |   22  | 
|   21 namespace { |   23 namespace { | 
|   22  |   24  | 
|   23 // Disambiguate various types of responses that trigger a meta-refresh, |   25 // Disambiguate various types of responses that trigger a meta-refresh, | 
|   24 // failure, or fallback to pass-through. |   26 // failure, or fallback to pass-through. | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
|   43   // Not an SDCH response but should be. |   45   // Not an SDCH response but should be. | 
|   44   RESPONSE_CORRUPT_SDCH = 6, |   46   RESPONSE_CORRUPT_SDCH = 6, | 
|   45  |   47  | 
|   46   // No dictionary was advertised with the request, the server claims |   48   // No dictionary was advertised with the request, the server claims | 
|   47   // to have encoded with SDCH anyway, but it isn't an SDCH response. |   49   // to have encoded with SDCH anyway, but it isn't an SDCH response. | 
|   48   RESPONSE_ENCODING_LIE = 7, |   50   RESPONSE_ENCODING_LIE = 7, | 
|   49  |   51  | 
|   50   RESPONSE_MAX, |   52   RESPONSE_MAX, | 
|   51 }; |   53 }; | 
|   52  |   54  | 
 |   55 const char* ResponseCorruptionDetectionCauseToString( | 
 |   56     ResponseCorruptionDetectionCause cause) { | 
 |   57   const char* cause_string = "<unknown>"; | 
 |   58   switch (cause) { | 
 |   59     case RESPONSE_NONE: | 
 |   60       cause_string = "NONE"; | 
 |   61       break; | 
 |   62     case RESPONSE_404: | 
 |   63       cause_string = "404"; | 
 |   64       break; | 
 |   65     case RESPONSE_NOT_200: | 
 |   66       cause_string = "NOT_200"; | 
 |   67       break; | 
 |   68     case RESPONSE_OLD_UNENCODED: | 
 |   69       cause_string = "OLD_UNENCODED"; | 
 |   70       break; | 
 |   71     case RESPONSE_TENTATIVE_SDCH: | 
 |   72       cause_string = "TENTATIVE_SDCH"; | 
 |   73       break; | 
 |   74     case RESPONSE_NO_DICTIONARY: | 
 |   75       cause_string = "NO_DICTIONARY"; | 
 |   76       break; | 
 |   77     case RESPONSE_CORRUPT_SDCH: | 
 |   78       cause_string = "CORRUPT_SDCH"; | 
 |   79       break; | 
 |   80     case RESPONSE_ENCODING_LIE: | 
 |   81       cause_string = "ENCODING_LIE"; | 
 |   82       break; | 
 |   83     case RESPONSE_MAX: | 
 |   84       cause_string = "<Error: max enum value>"; | 
 |   85       break; | 
 |   86   } | 
 |   87   return cause_string; | 
 |   88 } | 
 |   89  | 
 |   90 base::Value* NetLogSdchResponseCorruptionDetectionCallback( | 
 |   91     ResponseCorruptionDetectionCause cause, | 
 |   92     bool cached, | 
 |   93     NetLog::LogLevel log_level) { | 
 |   94   base::DictionaryValue* dict = new base::DictionaryValue(); | 
 |   95   dict->SetString("cause", ResponseCorruptionDetectionCauseToString(cause)); | 
 |   96   dict->SetBoolean("cached", cached); | 
 |   97   return dict; | 
 |   98 } | 
 |   99  | 
|   53 }  // namespace |  100 }  // namespace | 
|   54  |  101  | 
|   55 SdchFilter::SdchFilter(const FilterContext& filter_context) |  102 SdchFilter::SdchFilter(const FilterContext& filter_context) | 
|   56     : filter_context_(filter_context), |  103     : filter_context_(filter_context), | 
|   57       decoding_status_(DECODING_UNINITIALIZED), |  104       decoding_status_(DECODING_UNINITIALIZED), | 
|   58       dictionary_hash_(), |  105       dictionary_hash_(), | 
|   59       dictionary_hash_is_plausible_(false), |  106       dictionary_hash_is_plausible_(false), | 
|   60       dictionary_(NULL), |  107       dictionary_(NULL), | 
|   61       url_request_context_(filter_context.GetURLRequestContext()), |  108       url_request_context_(filter_context.GetURLRequestContext()), | 
|   62       dest_buffer_excess_(), |  109       dest_buffer_excess_(), | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
|   77  |  124  | 
|   78   static int filter_use_count = 0; |  125   static int filter_use_count = 0; | 
|   79   ++filter_use_count; |  126   ++filter_use_count; | 
|   80   if (META_REFRESH_RECOVERY == decoding_status_) { |  127   if (META_REFRESH_RECOVERY == decoding_status_) { | 
|   81     UMA_HISTOGRAM_COUNTS("Sdch3.FilterUseBeforeDisabling", filter_use_count); |  128     UMA_HISTOGRAM_COUNTS("Sdch3.FilterUseBeforeDisabling", filter_use_count); | 
|   82   } |  129   } | 
|   83  |  130  | 
|   84   if (vcdiff_streaming_decoder_.get()) { |  131   if (vcdiff_streaming_decoder_.get()) { | 
|   85     if (!vcdiff_streaming_decoder_->FinishDecoding()) { |  132     if (!vcdiff_streaming_decoder_->FinishDecoding()) { | 
|   86       decoding_status_ = DECODING_ERROR; |  133       decoding_status_ = DECODING_ERROR; | 
|   87       SdchManager::SdchErrorRecovery(SdchManager::INCOMPLETE_SDCH_CONTENT); |  134       LogSdchProblem(SDCH_INCOMPLETE_SDCH_CONTENT); | 
|   88       // Make it possible for the user to hit reload, and get non-sdch content. |  135       // Make it possible for the user to hit reload, and get non-sdch content. | 
|   89       // Note this will "wear off" quickly enough, and is just meant to assure |  136       // Note this will "wear off" quickly enough, and is just meant to assure | 
|   90       // in some rare case that the user is not stuck. |  137       // in some rare case that the user is not stuck. | 
|   91       url_request_context_->sdch_manager()->BlacklistDomain( |  138       url_request_context_->sdch_manager()->BlacklistDomain( | 
|   92           url_, SdchManager::INCOMPLETE_SDCH_CONTENT); |  139           url_, SDCH_INCOMPLETE_SDCH_CONTENT); | 
|   93       UMA_HISTOGRAM_COUNTS("Sdch3.PartialBytesIn", |  140       UMA_HISTOGRAM_COUNTS("Sdch3.PartialBytesIn", | 
|   94            static_cast<int>(filter_context_.GetByteReadCount())); |  141            static_cast<int>(filter_context_.GetByteReadCount())); | 
|   95       UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffIn", source_bytes_); |  142       UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffIn", source_bytes_); | 
|   96       UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffOut", output_bytes_); |  143       UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffOut", output_bytes_); | 
|   97     } |  144     } | 
|   98   } |  145   } | 
|   99  |  146  | 
|  100   if (!dest_buffer_excess_.empty()) { |  147   if (!dest_buffer_excess_.empty()) { | 
|  101     // Filter chaining error, or premature teardown. |  148     // Filter chaining error, or premature teardown. | 
|  102     SdchManager::SdchErrorRecovery(SdchManager::UNFLUSHED_CONTENT); |  149     LogSdchProblem(SDCH_UNFLUSHED_CONTENT); | 
|  103     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBytesIn", |  150     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBytesIn", | 
|  104          static_cast<int>(filter_context_.GetByteReadCount())); |  151          static_cast<int>(filter_context_.GetByteReadCount())); | 
|  105     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBufferSize", |  152     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBufferSize", | 
|  106                          dest_buffer_excess_.size()); |  153                          dest_buffer_excess_.size()); | 
|  107     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedVcdiffIn", source_bytes_); |  154     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedVcdiffIn", source_bytes_); | 
|  108     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedVcdiffOut", output_bytes_); |  155     UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedVcdiffOut", output_bytes_); | 
|  109   } |  156   } | 
|  110  |  157  | 
|  111   if (filter_context_.IsCachedContent()) { |  158   if (filter_context_.IsCachedContent()) { | 
|  112     // Not a real error, but it is useful to have this tally. |  159     // Not a real error, but it is useful to have this tally. | 
|  113     // TODO(jar): Remove this stat after SDCH stability is validated. |  160     // TODO(jar): Remove this stat after SDCH stability is validated. | 
|  114     SdchManager::SdchErrorRecovery(SdchManager::CACHE_DECODED); |  161     LogSdchProblem(SDCH_CACHE_DECODED); | 
|  115     return;  // We don't need timing stats, and we aready got ratios. |  162     return;  // We don't need timing stats, and we aready got ratios. | 
|  116   } |  163   } | 
|  117  |  164  | 
|  118   switch (decoding_status_) { |  165   switch (decoding_status_) { | 
|  119     case DECODING_IN_PROGRESS: { |  166     case DECODING_IN_PROGRESS: { | 
|  120       if (output_bytes_) |  167       if (output_bytes_) | 
|  121         UMA_HISTOGRAM_PERCENTAGE("Sdch3.Network_Decode_Ratio_a", |  168         UMA_HISTOGRAM_PERCENTAGE("Sdch3.Network_Decode_Ratio_a", | 
|  122             static_cast<int>( |  169             static_cast<int>( | 
|  123                 (filter_context_.GetByteReadCount() * 100) / output_bytes_)); |  170                 (filter_context_.GetByteReadCount() * 100) / output_bytes_)); | 
|  124       UMA_HISTOGRAM_COUNTS("Sdch3.Network_Decode_Bytes_VcdiffOut_a", |  171       UMA_HISTOGRAM_COUNTS("Sdch3.Network_Decode_Bytes_VcdiffOut_a", | 
|  125                            output_bytes_); |  172                            output_bytes_); | 
|  126       filter_context_.RecordPacketStats(FilterContext::SDCH_DECODE); |  173       filter_context_.RecordPacketStats(FilterContext::SDCH_DECODE); | 
|  127  |  174  | 
|  128       // Allow latency experiments to proceed. |  175       // Allow latency experiments to proceed. | 
|  129       url_request_context_->sdch_manager()->SetAllowLatencyExperiment( |  176       url_request_context_->sdch_manager()->SetAllowLatencyExperiment( | 
|  130           url_, true); |  177           url_, true); | 
|  131       return; |  178       return; | 
|  132     } |  179     } | 
|  133     case PASS_THROUGH: { |  180     case PASS_THROUGH: { | 
|  134       filter_context_.RecordPacketStats(FilterContext::SDCH_PASSTHROUGH); |  181       filter_context_.RecordPacketStats(FilterContext::SDCH_PASSTHROUGH); | 
|  135       return; |  182       return; | 
|  136     } |  183     } | 
|  137     case DECODING_UNINITIALIZED: { |  184     case DECODING_UNINITIALIZED: { | 
|  138       SdchManager::SdchErrorRecovery(SdchManager::UNINITIALIZED); |  185       LogSdchProblem(SDCH_UNINITIALIZED); | 
|  139       return; |  186       return; | 
|  140     } |  187     } | 
|  141     case WAITING_FOR_DICTIONARY_SELECTION: { |  188     case WAITING_FOR_DICTIONARY_SELECTION: { | 
|  142       SdchManager::SdchErrorRecovery(SdchManager::PRIOR_TO_DICTIONARY); |  189       LogSdchProblem(SDCH_PRIOR_TO_DICTIONARY); | 
|  143       return; |  190       return; | 
|  144     } |  191     } | 
|  145     case DECODING_ERROR: { |  192     case DECODING_ERROR: { | 
|  146       SdchManager::SdchErrorRecovery(SdchManager::DECODE_ERROR); |  193       LogSdchProblem(SDCH_DECODE_ERROR); | 
|  147       return; |  194       return; | 
|  148     } |  195     } | 
|  149     case META_REFRESH_RECOVERY: { |  196     case META_REFRESH_RECOVERY: { | 
|  150       // Already accounted for when set. |  197       // Already accounted for when set. | 
|  151       return; |  198       return; | 
|  152     } |  199     } | 
|  153   }  // end of switch. |  200   }  // end of switch. | 
|  154 } |  201 } | 
|  155  |  202  | 
|  156 bool SdchFilter::InitDecoding(Filter::FilterType filter_type) { |  203 bool SdchFilter::InitDecoding(Filter::FilterType filter_type) { | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  203       // advertisement (so that we are sure we're not hurting anything). |  250       // advertisement (so that we are sure we're not hurting anything). | 
|  204       // |  251       // | 
|  205       // Watch out for an error page inserted by the proxy as part of a 40x |  252       // Watch out for an error page inserted by the proxy as part of a 40x | 
|  206       // error response.  When we see such content molestation, we certainly |  253       // error response.  When we see such content molestation, we certainly | 
|  207       // need to fall into the meta-refresh case. |  254       // need to fall into the meta-refresh case. | 
|  208       ResponseCorruptionDetectionCause cause = RESPONSE_NONE; |  255       ResponseCorruptionDetectionCause cause = RESPONSE_NONE; | 
|  209       if (filter_context_.GetResponseCode() == 404) { |  256       if (filter_context_.GetResponseCode() == 404) { | 
|  210         // We could be more generous, but for now, only a "NOT FOUND" code will |  257         // We could be more generous, but for now, only a "NOT FOUND" code will | 
|  211         // cause a pass through.  All other bad codes will fall into a |  258         // cause a pass through.  All other bad codes will fall into a | 
|  212         // meta-refresh. |  259         // meta-refresh. | 
|  213         SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_404_CODE); |  260         LogSdchProblem(SDCH_PASS_THROUGH_404_CODE); | 
|  214         cause = RESPONSE_404; |  261         cause = RESPONSE_404; | 
|  215         decoding_status_ = PASS_THROUGH; |  262         decoding_status_ = PASS_THROUGH; | 
|  216       } else if (filter_context_.GetResponseCode() != 200) { |  263       } else if (filter_context_.GetResponseCode() != 200) { | 
|  217         // We need to meta-refresh, with SDCH disabled. |  264         // We need to meta-refresh, with SDCH disabled. | 
|  218         cause = RESPONSE_NOT_200; |  265         cause = RESPONSE_NOT_200; | 
|  219       } else if (filter_context_.IsCachedContent() |  266       } else if (filter_context_.IsCachedContent() | 
|  220                  && !dictionary_hash_is_plausible_) { |  267                  && !dictionary_hash_is_plausible_) { | 
|  221         // We must have hit the back button, and gotten content that was fetched |  268         // We must have hit the back button, and gotten content that was fetched | 
|  222         // before we *really* advertised SDCH and a dictionary. |  269         // before we *really* advertised SDCH and a dictionary. | 
|  223         SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_OLD_CACHED); |  270         LogSdchProblem(SDCH_PASS_THROUGH_OLD_CACHED); | 
|  224         decoding_status_ = PASS_THROUGH; |  271         decoding_status_ = PASS_THROUGH; | 
|  225         cause = RESPONSE_OLD_UNENCODED; |  272         cause = RESPONSE_OLD_UNENCODED; | 
|  226       } else if (possible_pass_through_) { |  273       } else if (possible_pass_through_) { | 
|  227         // This is the potentially most graceful response. There really was no |  274         // This is the potentially most graceful response. There really was no | 
|  228         // error. We were just overly cautious when we added a TENTATIVE_SDCH. |  275         // error. We were just overly cautious when we added a TENTATIVE_SDCH. | 
|  229         // We added the sdch coding tag, and it should not have been added. |  276         // We added the sdch coding tag, and it should not have been added. | 
|  230         // This can happen in server experiments, where the server decides |  277         // This can happen in server experiments, where the server decides | 
|  231         // not to use sdch, even though there is a dictionary.  To be |  278         // not to use sdch, even though there is a dictionary.  To be | 
|  232         // conservative, we locally added the tentative sdch (fearing that a |  279         // conservative, we locally added the tentative sdch (fearing that a | 
|  233         // proxy stripped it!) and we must now recant (pass through). |  280         // proxy stripped it!) and we must now recant (pass through). | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
|  249         // We'll use a meta-refresh, and get content without asking for SDCH. |  296         // We'll use a meta-refresh, and get content without asking for SDCH. | 
|  250         // This will also progressively disable SDCH for this domain. |  297         // This will also progressively disable SDCH for this domain. | 
|  251         cause = RESPONSE_CORRUPT_SDCH; |  298         cause = RESPONSE_CORRUPT_SDCH; | 
|  252       } else { |  299       } else { | 
|  253         // One of the first 9 bytes precluded consideration as a hash. |  300         // One of the first 9 bytes precluded consideration as a hash. | 
|  254         // This can't be an SDCH payload, even though the server said it was. |  301         // This can't be an SDCH payload, even though the server said it was. | 
|  255         // This is a major error, as the server or proxy tagged this SDCH even |  302         // This is a major error, as the server or proxy tagged this SDCH even | 
|  256         // though it is not! |  303         // though it is not! | 
|  257         // Meta-refresh won't help, as we didn't advertise an SDCH dictionary!! |  304         // Meta-refresh won't help, as we didn't advertise an SDCH dictionary!! | 
|  258         // Worse yet, meta-refresh could lead to an infinite refresh loop. |  305         // Worse yet, meta-refresh could lead to an infinite refresh loop. | 
|  259         SdchManager::SdchErrorRecovery(SdchManager::PASSING_THROUGH_NON_SDCH); |  306         LogSdchProblem(SDCH_PASSING_THROUGH_NON_SDCH); | 
|  260         decoding_status_ = PASS_THROUGH; |  307         decoding_status_ = PASS_THROUGH; | 
|  261         // ... but further back-off on advertising SDCH support. |  308         // ... but further back-off on advertising SDCH support. | 
|  262         url_request_context_->sdch_manager()->BlacklistDomain( |  309         url_request_context_->sdch_manager()->BlacklistDomain( | 
|  263             url_, SdchManager::PASSING_THROUGH_NON_SDCH); |  310             url_, SDCH_PASSING_THROUGH_NON_SDCH); | 
|  264         cause = RESPONSE_ENCODING_LIE; |  311         cause = RESPONSE_ENCODING_LIE; | 
|  265       } |  312       } | 
|  266       DCHECK_NE(RESPONSE_NONE, cause); |  313       DCHECK_NE(RESPONSE_NONE, cause); | 
|  267  |  314  | 
|  268       // Use if statement rather than ?: because UMA_HISTOGRAM_ENUMERATION |  315       // Use if statement rather than ?: because UMA_HISTOGRAM_ENUMERATION | 
|  269       // caches the histogram name based on the call site. |  316       // caches the histogram name based on the call site. | 
|  270       if (filter_context_.IsCachedContent()) { |  317       if (filter_context_.IsCachedContent()) { | 
|  271         UMA_HISTOGRAM_ENUMERATION( |  318         UMA_HISTOGRAM_ENUMERATION( | 
|  272             "Sdch3.ResponseCorruptionDetection.Cached", cause, RESPONSE_MAX); |  319             "Sdch3.ResponseCorruptionDetection.Cached", cause, RESPONSE_MAX); | 
|  273       } else { |  320       } else { | 
|  274         UMA_HISTOGRAM_ENUMERATION( |  321         UMA_HISTOGRAM_ENUMERATION( | 
|  275             "Sdch3.ResponseCorruptionDetection.Uncached", cause, RESPONSE_MAX); |  322             "Sdch3.ResponseCorruptionDetection.Uncached", cause, RESPONSE_MAX); | 
|  276       } |  323       } | 
 |  324       filter_context_.GetNetLog().AddEvent( | 
 |  325           NetLog::TYPE_SDCH_RESPONSE_CORRUPTION_DETECTION, | 
 |  326           base::Bind(&NetLogSdchResponseCorruptionDetectionCallback, cause, | 
 |  327                      filter_context_.IsCachedContent())); | 
|  277  |  328  | 
|  278       if (decoding_status_ == PASS_THROUGH) { |  329       if (decoding_status_ == PASS_THROUGH) { | 
|  279         dest_buffer_excess_ = dictionary_hash_;  // Send what we scanned. |  330         dest_buffer_excess_ = dictionary_hash_;  // Send what we scanned. | 
|  280       } else { |  331       } else { | 
|  281         // This is where we try to do the expensive meta-refresh. |  332         // This is where we try to do the expensive meta-refresh. | 
|  282         if (std::string::npos == mime_type_.find("text/html")) { |  333         if (std::string::npos == mime_type_.find("text/html")) { | 
|  283           // Since we can't do a meta-refresh (along with an exponential |  334           // Since we can't do a meta-refresh (along with an exponential | 
|  284           // backoff), we'll just make sure this NEVER happens again. |  335           // backoff), we'll just make sure this NEVER happens again. | 
|  285           SdchManager::ProblemCodes problem = |  336           SdchProblemCode problem = (filter_context_.IsCachedContent() | 
|  286               (filter_context_.IsCachedContent() ? |  337                                          ? SDCH_CACHED_META_REFRESH_UNSUPPORTED | 
|  287                SdchManager::CACHED_META_REFRESH_UNSUPPORTED : |  338                                          : SDCH_META_REFRESH_UNSUPPORTED); | 
|  288                SdchManager::META_REFRESH_UNSUPPORTED); |  | 
|  289           url_request_context_->sdch_manager()->BlacklistDomainForever( |  339           url_request_context_->sdch_manager()->BlacklistDomainForever( | 
|  290               url_, problem); |  340               url_, problem); | 
|  291           SdchManager::SdchErrorRecovery(problem); |  341           LogSdchProblem(problem); | 
|  292           return FILTER_ERROR; |  342           return FILTER_ERROR; | 
|  293         } |  343         } | 
|  294         // HTML content means we can issue a meta-refresh, and get the content |  344         // HTML content means we can issue a meta-refresh, and get the content | 
|  295         // again, perhaps without SDCH (to be safe). |  345         // again, perhaps without SDCH (to be safe). | 
|  296         if (filter_context_.IsCachedContent()) { |  346         if (filter_context_.IsCachedContent()) { | 
|  297           // Cached content is probably a startup tab, so we'll just get fresh |  347           // Cached content is probably a startup tab, so we'll just get fresh | 
|  298           // content and try again, without disabling sdch. |  348           // content and try again, without disabling sdch. | 
|  299           SdchManager::SdchErrorRecovery( |  349           LogSdchProblem(SDCH_META_REFRESH_CACHED_RECOVERY); | 
|  300               SdchManager::META_REFRESH_CACHED_RECOVERY); |  | 
|  301         } else { |  350         } else { | 
|  302           // Since it wasn't in the cache, we definately need at least some |  351           // Since it wasn't in the cache, we definately need at least some | 
|  303           // period of blacklisting to get the correct content. |  352           // period of blacklisting to get the correct content. | 
|  304           url_request_context_->sdch_manager()->BlacklistDomain( |  353           url_request_context_->sdch_manager()->BlacklistDomain( | 
|  305               url_, SdchManager::META_REFRESH_RECOVERY); |  354               url_, SDCH_META_REFRESH_RECOVERY); | 
|  306           SdchManager::SdchErrorRecovery(SdchManager::META_REFRESH_RECOVERY); |  355           LogSdchProblem(SDCH_META_REFRESH_RECOVERY); | 
|  307         } |  356         } | 
|  308         decoding_status_ = META_REFRESH_RECOVERY; |  357         decoding_status_ = META_REFRESH_RECOVERY; | 
|  309         // Issue a meta redirect with SDCH disabled. |  358         // Issue a meta redirect with SDCH disabled. | 
|  310         dest_buffer_excess_ = kDecompressionErrorHtml; |  359         dest_buffer_excess_ = kDecompressionErrorHtml; | 
|  311       } |  360       } | 
|  312     } else { |  361     } else { | 
|  313       DCHECK_EQ(DECODING_IN_PROGRESS, decoding_status_); |  362       DCHECK_EQ(DECODING_IN_PROGRESS, decoding_status_); | 
|  314     } |  363     } | 
|  315   } |  364   } | 
|  316  |  365  | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  350   bool ret = vcdiff_streaming_decoder_->DecodeChunk( |  399   bool ret = vcdiff_streaming_decoder_->DecodeChunk( | 
|  351     next_stream_data_, stream_data_len_, &dest_buffer_excess_); |  400     next_stream_data_, stream_data_len_, &dest_buffer_excess_); | 
|  352   // Assume all data was used in decoding. |  401   // Assume all data was used in decoding. | 
|  353   next_stream_data_ = NULL; |  402   next_stream_data_ = NULL; | 
|  354   source_bytes_ += stream_data_len_; |  403   source_bytes_ += stream_data_len_; | 
|  355   stream_data_len_ = 0; |  404   stream_data_len_ = 0; | 
|  356   output_bytes_ += dest_buffer_excess_.size(); |  405   output_bytes_ += dest_buffer_excess_.size(); | 
|  357   if (!ret) { |  406   if (!ret) { | 
|  358     vcdiff_streaming_decoder_.reset(NULL);  // Don't call it again. |  407     vcdiff_streaming_decoder_.reset(NULL);  // Don't call it again. | 
|  359     decoding_status_ = DECODING_ERROR; |  408     decoding_status_ = DECODING_ERROR; | 
|  360     SdchManager::SdchErrorRecovery(SdchManager::DECODE_BODY_ERROR); |  409     LogSdchProblem(SDCH_DECODE_BODY_ERROR); | 
|  361     return FILTER_ERROR; |  410     return FILTER_ERROR; | 
|  362   } |  411   } | 
|  363  |  412  | 
|  364   amount = OutputBufferExcess(dest_buffer, available_space); |  413   amount = OutputBufferExcess(dest_buffer, available_space); | 
|  365   *dest_len += amount; |  414   *dest_len += amount; | 
|  366   dest_buffer += amount; |  415   dest_buffer += amount; | 
|  367   available_space -= amount; |  416   available_space -= amount; | 
|  368   if (0 == available_space && !dest_buffer_excess_.empty()) |  417   if (0 == available_space && !dest_buffer_excess_.empty()) | 
|  369       return FILTER_OK; |  418       return FILTER_OK; | 
|  370   return FILTER_NEED_MORE_DATA; |  419   return FILTER_NEED_MORE_DATA; | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
|  387   stream_data_len_ -= bytes_needed; |  436   stream_data_len_ -= bytes_needed; | 
|  388   DCHECK_LE(0, stream_data_len_); |  437   DCHECK_LE(0, stream_data_len_); | 
|  389   if (stream_data_len_ > 0) |  438   if (stream_data_len_ > 0) | 
|  390     next_stream_data_ += bytes_needed; |  439     next_stream_data_ += bytes_needed; | 
|  391   else |  440   else | 
|  392     next_stream_data_ = NULL; |  441     next_stream_data_ = NULL; | 
|  393  |  442  | 
|  394   DCHECK(!dictionary_.get()); |  443   DCHECK(!dictionary_.get()); | 
|  395   dictionary_hash_is_plausible_ = true;  // Assume plausible, but check. |  444   dictionary_hash_is_plausible_ = true;  // Assume plausible, but check. | 
|  396  |  445  | 
 |  446   SdchProblemCode rv = SDCH_OK; | 
|  397   if ('\0' == dictionary_hash_[kServerIdLength - 1]) { |  447   if ('\0' == dictionary_hash_[kServerIdLength - 1]) { | 
|  398     SdchManager* manager(url_request_context_->sdch_manager()); |  448     SdchManager* manager(url_request_context_->sdch_manager()); | 
|  399     manager->GetVcdiffDictionary( |  449     rv = manager->GetVcdiffDictionary( | 
|  400         std::string(dictionary_hash_, 0, kServerIdLength - 1), |  450         std::string(dictionary_hash_, 0, kServerIdLength - 1), url_, | 
|  401         url_, &dictionary_); |  451         &dictionary_); | 
 |  452     if (rv == SDCH_DICTIONARY_HASH_NOT_FOUND) { | 
 |  453       DCHECK(dictionary_hash_.size() == kServerIdLength); | 
 |  454       // Since dictionary was not found, check to see if hash was even | 
 |  455       // plausible. | 
 |  456       for (size_t i = 0; i < kServerIdLength - 1; ++i) { | 
 |  457         char base64_char = dictionary_hash_[i]; | 
 |  458         if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) { | 
 |  459           rv = SDCH_DICTIONARY_HASH_MALFORMED; | 
 |  460           dictionary_hash_is_plausible_ = false; | 
 |  461           break; | 
 |  462         } | 
 |  463       } | 
 |  464     } | 
|  402   } else { |  465   } else { | 
|  403     dictionary_hash_is_plausible_ = false; |  466     dictionary_hash_is_plausible_ = false; | 
 |  467     rv = SDCH_DICTIONARY_HASH_MALFORMED; | 
|  404   } |  468   } | 
|  405  |  469   if (rv != SDCH_OK) { | 
|  406   if (!dictionary_.get()) { |  470     LogSdchProblem(rv); | 
|  407     DCHECK(dictionary_hash_.size() == kServerIdLength); |  | 
|  408     // Since dictionary was not found, check to see if hash was even plausible. |  | 
|  409     for (size_t i = 0; i < kServerIdLength - 1; ++i) { |  | 
|  410       char base64_char = dictionary_hash_[i]; |  | 
|  411       if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) { |  | 
|  412         dictionary_hash_is_plausible_ = false; |  | 
|  413         break; |  | 
|  414       } |  | 
|  415     } |  | 
|  416     if (dictionary_hash_is_plausible_) |  | 
|  417       SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_NOT_FOUND); |  | 
|  418     else |  | 
|  419       SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_MALFORMED); |  | 
|  420     decoding_status_ = DECODING_ERROR; |  471     decoding_status_ = DECODING_ERROR; | 
|  421     return FILTER_ERROR; |  472     return FILTER_ERROR; | 
|  422   } |  473   } | 
 |  474   DCHECK(dictionary_.get()); | 
|  423   vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder); |  475   vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder); | 
|  424   vcdiff_streaming_decoder_->SetAllowVcdTarget(false); |  476   vcdiff_streaming_decoder_->SetAllowVcdTarget(false); | 
|  425   vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(), |  477   vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(), | 
|  426                                            dictionary_->text().size()); |  478                                            dictionary_->text().size()); | 
|  427   decoding_status_ = DECODING_IN_PROGRESS; |  479   decoding_status_ = DECODING_IN_PROGRESS; | 
|  428   return FILTER_OK; |  480   return FILTER_OK; | 
|  429 } |  481 } | 
|  430  |  482  | 
|  431 int SdchFilter::OutputBufferExcess(char* const dest_buffer, |  483 int SdchFilter::OutputBufferExcess(char* const dest_buffer, | 
|  432                                    size_t available_space) { |  484                                    size_t available_space) { | 
|  433   if (dest_buffer_excess_.empty()) |  485   if (dest_buffer_excess_.empty()) | 
|  434     return 0; |  486     return 0; | 
|  435   DCHECK(dest_buffer_excess_.size() > dest_buffer_excess_index_); |  487   DCHECK(dest_buffer_excess_.size() > dest_buffer_excess_index_); | 
|  436   size_t amount = std::min(available_space, |  488   size_t amount = std::min(available_space, | 
|  437       dest_buffer_excess_.size() - dest_buffer_excess_index_); |  489       dest_buffer_excess_.size() - dest_buffer_excess_index_); | 
|  438   memcpy(dest_buffer, dest_buffer_excess_.data() + dest_buffer_excess_index_, |  490   memcpy(dest_buffer, dest_buffer_excess_.data() + dest_buffer_excess_index_, | 
|  439          amount); |  491          amount); | 
|  440   dest_buffer_excess_index_ += amount; |  492   dest_buffer_excess_index_ += amount; | 
|  441   if (dest_buffer_excess_.size() <= dest_buffer_excess_index_) { |  493   if (dest_buffer_excess_.size() <= dest_buffer_excess_index_) { | 
|  442     DCHECK(dest_buffer_excess_.size() == dest_buffer_excess_index_); |  494     DCHECK(dest_buffer_excess_.size() == dest_buffer_excess_index_); | 
|  443     dest_buffer_excess_.clear(); |  495     dest_buffer_excess_.clear(); | 
|  444     dest_buffer_excess_index_ = 0; |  496     dest_buffer_excess_index_ = 0; | 
|  445   } |  497   } | 
|  446   return amount; |  498   return amount; | 
|  447 } |  499 } | 
|  448  |  500  | 
 |  501 void SdchFilter::LogSdchProblem(SdchProblemCode problem) { | 
 |  502   SdchManager::SdchErrorRecovery(problem); | 
 |  503   filter_context_.GetNetLog().AddEvent( | 
 |  504       NetLog::TYPE_SDCH_DECODING_ERROR, | 
 |  505       base::Bind(&NetLogSdchResourceProblemCallback, problem)); | 
 |  506 } | 
 |  507  | 
|  449 }  // namespace net |  508 }  // namespace net | 
| OLD | NEW |