sdch_manager.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/base64.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/field_trial.h" 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/histogram.h" 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/sha2.h" 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/registry_controlled_domain.h" 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/sdch_manager.h" 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/url_request/url_request_http_job.h" 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottusing base::Time; 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottusing base::TimeDelta; 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------ 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst size_t SdchManager::kMaxDictionarySize = 1000000; 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst size_t SdchManager::kMaxDictionaryCount = 20; 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSdchManager* SdchManager::global_; 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSdchManager* SdchManager::Global() { 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return global_; 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::SdchErrorRecovery(ProblemCodes problem) { 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE); 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::ClearBlacklistings() { 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Global()->blacklisted_domains_.clear(); 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Global()->exponential_blacklist_count.clear(); 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::ClearDomainBlacklisting(const std::string& domain) { 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Global()->blacklisted_domains_.erase(StringToLowerASCII(domain)); 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SdchManager::BlackListDomainCount(const std::string& domain) { 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (Global()->blacklisted_domains_.end() == 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Global()->blacklisted_domains_.find(domain)) 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return Global()->blacklisted_domains_[StringToLowerASCII(domain)]; 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SdchManager::BlacklistDomainExponential(const std::string& domain) { 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (Global()->exponential_blacklist_count.end() == 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Global()->exponential_blacklist_count.find(domain)) 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return 0; 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return Global()->exponential_blacklist_count[StringToLowerASCII(domain)]; 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------ 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSdchManager::SdchManager() : sdch_enabled_(false) { 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!global_); 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_ = this; 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSdchManager::~SdchManager() { 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(global_ == this); 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (!dictionaries_.empty()) { 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DictionaryMap::iterator it = dictionaries_.begin(); 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott it->second->Release(); 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionaries_.erase(it->first); 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_ = NULL; 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::Shutdown() { 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!global_ ) 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->fetcher_.reset(NULL); 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::BlacklistDomain(const GURL& url) { 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!global_ ) 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->SetAllowLatencyExperiment(url, false); 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string domain(StringToLowerASCII(url.host())); 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int count = global_->blacklisted_domains_[domain]; 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (count > 0) 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; // Domain is already blacklisted. 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott count = 1 + 2 * global_->exponential_blacklist_count[domain]; 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (count > 0) 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->exponential_blacklist_count[domain] = count; 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott else 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott count = INT_MAX; 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->blacklisted_domains_[domain] = count; 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::BlacklistDomainForever(const GURL& url) { 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!global_ ) 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->SetAllowLatencyExperiment(url, false); 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string domain(StringToLowerASCII(url.host())); 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->exponential_blacklist_count[domain] = INT_MAX; 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->blacklisted_domains_[domain] = INT_MAX; 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::EnableSdchSupport(const std::string& domain) { 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We presume that there is a SDCH manager instance. 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->supported_domain_ = domain; 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->sdch_enabled_ = true; 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst bool SdchManager::IsInSupportedDomain(const GURL& url) { 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!sdch_enabled_ ) 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!supported_domain_.empty() && 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott !url.DomainIs(supported_domain_.data(), supported_domain_.size())) 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // It is not the singular supported domain. 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (blacklisted_domains_.empty()) 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string domain(StringToLowerASCII(url.host())); 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DomainCounter::iterator it = blacklisted_domains_.find(domain); 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (blacklisted_domains_.end() == it) 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int count = it->second - 1; 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (count > 0) 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott blacklisted_domains_[domain] = count; 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott else 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott blacklisted_domains_.erase(domain); 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET); 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::CanFetchDictionary(const GURL& referring_url, 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& dictionary_url) const { 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott /* The user agent may retrieve a dictionary from the dictionary URL if all of 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott the following are true: 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1 The dictionary URL host name matches the referrer URL host name 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 2 The dictionary URL host name domain matches the parent domain of the 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott referrer URL host name 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 3 The parent domain of the referrer URL host name is not a top level 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott domain 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 4 The dictionary URL is not an HTTPS URL. 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */ 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Item (1) above implies item (2). Spec should be updated. 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // I take "host name match" to be "is identical to" 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (referring_url.host() != dictionary_url.host()) { 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST); 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (referring_url.SchemeIs("https")) { 167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL); 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // TODO(jar): Remove this failsafe conservative hack which is more restrictive 172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // than current SDCH spec when needed, and justified by security audit. 173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!referring_url.SchemeIs("http")) { 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP); 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::FetchDictionary(const GURL& request_url, 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& dictionary_url) { 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (SdchManager::Global()->CanFetchDictionary(request_url, dictionary_url) && 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott fetcher_.get()) 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott fetcher_->Schedule(dictionary_url); 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::AddSdchDictionary(const std::string& dictionary_text, 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& dictionary_url) { 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string client_hash; 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string server_hash; 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott GenerateHash(dictionary_text, &client_hash, &server_hash); 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (dictionaries_.find(server_hash) != dictionaries_.end()) { 194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_ALREADY_LOADED); 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Already loaded. 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string domain, path; 199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::set<int> ports; 200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Time expiration(Time::Now() + TimeDelta::FromDays(30)); 201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (dictionary_text.empty()) { 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT); 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Missing header. 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t header_end = dictionary_text.find("\n\n"); 208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (std::string::npos == header_end) { 209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER); 210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Missing header. 211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t line_start = 0; // Start of line being parsed. 213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (1) { 214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t line_end = dictionary_text.find('\n', line_start); 215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(std::string::npos != line_end); 216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(line_end <= header_end); 217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t colon_index = dictionary_text.find(':', line_start); 219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (std::string::npos == colon_index) { 220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON); 221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Illegal line missing a colon. 222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (colon_index > line_end) 225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t value_start = dictionary_text.find_first_not_of(" \t", 228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott colon_index + 1); 229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (std::string::npos != value_start) { 230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (value_start >= line_end) 231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string name(dictionary_text, line_start, colon_index - line_start); 233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string value(dictionary_text, value_start, line_end - value_start); 234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name = StringToLowerASCII(name); 235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (name == "domain") { 236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott domain = value; 237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (name == "path") { 238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott path = value; 239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (name == "format-version") { 240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (value != "1.0") 241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (name == "max-age") { 243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott expiration = Time::Now() + TimeDelta::FromSeconds(StringToInt64(value)); 244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (name == "port") { 245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int port = StringToInt(value); 246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (port >= 0) 247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ports.insert(port); 248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (line_end >= header_end) 252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott line_start = line_end + 1; 254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!Dictionary::CanSet(domain, path, ports, dictionary_url)) 257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of 260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // useless dictionaries. We should probably have a cache eviction plan, 261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // instead of just blocking additions. For now, with the spec in flux, it 262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // is probably not worth doing eviction handling. 263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (kMaxDictionarySize < dictionary_text.size()) { 264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE); 265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (kMaxDictionaryCount <= dictionaries_.size()) { 268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED); 269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); 273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DLOG(INFO) << "Loaded dictionary with client hash " << client_hash << 274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott " and server hash " << server_hash; 275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Dictionary* dictionary = 276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott new Dictionary(dictionary_text, header_end + 2, client_hash, 277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionary_url, domain, path, expiration, ports); 278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionary->AddRef(); 279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionaries_[server_hash] = dictionary; 280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::GetVcdiffDictionary(const std::string& server_hash, 284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& referring_url, Dictionary** dictionary) { 285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *dictionary = NULL; 286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DictionaryMap::iterator it = dictionaries_.find(server_hash); 287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (it == dictionaries_.end()) { 288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Dictionary* matching_dictionary = it->second; 291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!matching_dictionary->CanUse(referring_url)) 292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *dictionary = matching_dictionary; 294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// TODO(jar): If we have evictions from the dictionaries_, then we need to 297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// change this interface to return a list of reference counted Dictionary 298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// instances that can be used if/when a server specifies one. 299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::GetAvailDictionaryList(const GURL& target_url, 300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string* list) { 301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int count = 0; 302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (DictionaryMap::iterator it = dictionaries_.begin(); 303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott it != dictionaries_.end(); ++it) { 304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!it->second->CanAdvertise(target_url)) 305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++count; 307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!list->empty()) 308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott list->append(","); 309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott list->append(it->second->client_hash()); 310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Watch to see if we have corrupt or numerous dictionaries. 312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (count > 0) 313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); 314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSdchManager::Dictionary::Dictionary(const std::string& dictionary_text, 317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t offset, const std::string& client_hash, const GURL& gurl, 318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string& domain, const std::string& path, const Time& expiration, 319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::set<int> ports) 320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : text_(dictionary_text, offset), 321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott client_hash_(client_hash), 322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott url_(gurl), 323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott domain_(domain), 324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott path_(path), 325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott expiration_(expiration), 326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ports_(ports) { 327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::GenerateHash(const std::string& dictionary_text, 331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string* client_hash, std::string* server_hash) { 332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char binary_hash[32]; 333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash)); 334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string first_48_bits(&binary_hash[0], 6); 336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string second_48_bits(&binary_hash[6], 6); 337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UrlSafeBase64Encode(first_48_bits, client_hash); 338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UrlSafeBase64Encode(second_48_bits, server_hash); 339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_EQ(server_hash->length(), 8u); 341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_EQ(client_hash->length(), 8u); 342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::UrlSafeBase64Encode(const std::string& input, 346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string* output) { 347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Since this is only done during a dictionary load, and hashes are only 8 348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // characters, we just do the simple fixup, rather than rewriting the encoder. 349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::Base64Encode(input, output); 350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (size_t i = 0; i < output->size(); ++i) { 351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott switch (output->data()[i]) { 352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case '+': 353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott (*output)[i] = '-'; 354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case '/': 356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott (*output)[i] = '_'; 357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott default: 359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------ 365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Security functions restricting loads and use of dictionaries. 366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::Dictionary::CanSet(const std::string& domain, 369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string& path, 370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::set<int> ports, 371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& dictionary_url) { 372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!SdchManager::Global()->IsInSupportedDomain(dictionary_url)) 373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott /* 375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott A dictionary is invalid and must not be stored if any of the following are 376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott true: 377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1. The dictionary has no Domain attribute. 378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 2. The effective host name that derives from the referer URL host name does 379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott not domain-match the Domain attribute. 380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 3. The Domain attribute is a top level domain. 381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 4. The referer URL host is a host domain name (not IP address) and has the 382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott form HD, where D is the value of the Domain attribute, and H is a string 383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott that contains one or more dots. 384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5. If the dictionary has a Port attribute and the referer URL's port was not 385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott in the list. 386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */ 387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // TODO(jar): Redirects in dictionary fetches might plausibly be problematic, 389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // and hence the conservative approach is to not allow any redirects (if there 390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // were any... then don't allow the dictionary to be set). 391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (domain.empty()) { 393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER); 394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Domain is required. 395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (net::RegistryControlledDomainService::GetDomainAndRegistry(domain).size() 397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott == 0) { 398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN); 399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // domain was a TLD. 400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!Dictionary::DomainMatch(dictionary_url, domain)) { 402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL); 403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string referrer_url_host = dictionary_url.host(); 407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t postfix_domain_index = referrer_url_host.rfind(domain); 408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // See if it is indeed a postfix, or just an internal string. 409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (referrer_url_host.size() == postfix_domain_index + domain.size()) { 410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // It is a postfix... so check to see if there's a dot in the prefix. 411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t end_of_host_index = referrer_url_host.find_first_of('.'); 412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (referrer_url_host.npos != end_of_host_index && 413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott end_of_host_index < postfix_domain_index) { 414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX); 415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!ports.empty() 420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott && 0 == ports.count(dictionary_url.EffectiveIntPort())) { 421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); 422c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 423c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 424c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 426c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 427c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 428c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::Dictionary::CanUse(const GURL& referring_url) { 429c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!SdchManager::Global()->IsInSupportedDomain(referring_url)) 430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 431c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott /* 432c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1. The request URL's host name domain-matches the Domain attribute of the 433c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionary. 434c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 2. If the dictionary has a Port attribute, the request port is one of the 435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ports listed in the Port attribute. 436c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 3. The request URL path-matches the path attribute of the dictionary. 437c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 4. The request is not an HTTPS request. 438c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott*/ 439c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!DomainMatch(referring_url, domain_)) { 440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN); 441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 442c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 443c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!ports_.empty() 444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott && 0 == ports_.count(referring_url.EffectiveIntPort())) { 445c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST); 446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (path_.size() && !PathMatch(referring_url.path(), path_)) { 449c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH); 450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 451c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 452c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (referring_url.SchemeIsSecure()) { 453c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME); 454c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // TODO(jar): Remove overly restrictive failsafe test (added per security 458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // review) when we have a need to be more general. 459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!referring_url.SchemeIs("http")) { 460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(ATTEMPT_TO_DECODE_NON_HTTP_DATA); 461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) { 468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!SdchManager::Global()->IsInSupportedDomain(target_url)) 469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott /* The specific rules of when a dictionary should be advertised in an 471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Avail-Dictionary header are modeled after the rules for cookie scoping. The 472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A 473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionary may be advertised in the Avail-Dictionaries header exactly when 474c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott all of the following are true: 475c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1. The server's effective host name domain-matches the Domain attribute of 476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott the dictionary. 477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 2. If the dictionary has a Port attribute, the request port is one of the 478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ports listed in the Port attribute. 479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 3. The request URI path-matches the path header of the dictionary. 480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 4. The request is not an HTTPS request. 481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */ 482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!DomainMatch(target_url, domain_)) 483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort())) 485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 486c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (path_.size() && !PathMatch(target_url.path(), path_)) 487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (target_url.SchemeIsSecure()) 489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (Time::Now() > expiration_) 491c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 492c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::Dictionary::PathMatch(const std::string& path, 496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string& restriction) { 497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott /* Must be either: 498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1. P2 is equal to P1 499c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 2. P2 is a prefix of P1 and either the final character in P2 is "/" or the 500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott character following P2 in P1 is "/". 501c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */ 502c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (path == restriction) 503c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 504c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t prefix_length = restriction.size(); 505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (prefix_length > path.size()) 506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Can't be a prefix. 507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (0 != path.compare(0, prefix_length, restriction)) 508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return restriction[prefix_length - 1] == '/' || path[prefix_length] == '/'; 510c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 511c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 513c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::Dictionary::DomainMatch(const GURL& gurl, 514c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string& restriction) { 515c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // TODO(jar): This is not precisely a domain match definition. 516c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return gurl.DomainIs(restriction.data(), restriction.size()); 517c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 519c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------ 520c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Methods for supporting latency experiments. 521c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 522c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::AllowLatencyExperiment(const GURL& url) const { 523c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return allow_latency_experiment_.end() != 524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott allow_latency_experiment_.find(url.host()); 525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 526c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { 528c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (enable) { 529c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott allow_latency_experiment_.insert(url.host()); 530c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 531c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 532c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ExperimentSet::iterator it = allow_latency_experiment_.find(url.host()); 533c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (allow_latency_experiment_.end() == it) 534c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; // It was already erased, or never allowed. 535c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(LATENCY_TEST_DISALLOWED); 536c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott allow_latency_experiment_.erase(it); 537c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 538