172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 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 53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/sdch_manager.h" 63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/base64.h" 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h" 103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/sha2.h" 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/registry_controlled_domain.h" 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/url_request/url_request_http_job.h" 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsennamespace net { 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 283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen//------------------------------------------------------------------------------ 293f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenSdchManager::Dictionary::Dictionary(const std::string& dictionary_text, 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen size_t offset, 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::string& client_hash, 3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const GURL& gurl, 3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::string& domain, 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::string& path, 3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const base::Time& expiration, 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::set<int>& ports) 3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : text_(dictionary_text, offset), 3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen client_hash_(client_hash), 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen url_(gurl), 4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen domain_(domain), 4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen path_(path), 4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen expiration_(expiration), 4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ports_(ports) { 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 463f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenSdchManager::Dictionary::~Dictionary() { 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) { 503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!SdchManager::Global()->IsInSupportedDomain(target_url)) 513f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 523f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen /* The specific rules of when a dictionary should be advertised in an 533f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Avail-Dictionary header are modeled after the rules for cookie scoping. The 543f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A 553f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen dictionary may be advertised in the Avail-Dictionaries header exactly when 563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen all of the following are true: 573f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1. The server's effective host name domain-matches the Domain attribute of 583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen the dictionary. 593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2. If the dictionary has a Port attribute, the request port is one of the 603f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ports listed in the Port attribute. 613f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 3. The request URI path-matches the path header of the dictionary. 623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 4. The request is not an HTTPS request. 633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen */ 643f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!DomainMatch(target_url, domain_)) 653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort())) 673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (path_.size() && !PathMatch(target_url.path(), path_)) 693f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (target_url.SchemeIsSecure()) 713f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 7272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (base::Time::Now() > expiration_) 733f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return true; 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 773f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen//------------------------------------------------------------------------------ 783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Security functions restricting loads and use of dictionaries. 793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 813f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool SdchManager::Dictionary::CanSet(const std::string& domain, 823f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen const std::string& path, 8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::set<int>& ports, 843f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen const GURL& dictionary_url) { 853f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!SdchManager::Global()->IsInSupportedDomain(dictionary_url)) 863f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 873f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen /* 883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen A dictionary is invalid and must not be stored if any of the following are 893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen true: 903f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1. The dictionary has no Domain attribute. 913f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2. The effective host name that derives from the referer URL host name does 923f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen not domain-match the Domain attribute. 933f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 3. The Domain attribute is a top level domain. 943f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 4. The referer URL host is a host domain name (not IP address) and has the 953f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen form HD, where D is the value of the Domain attribute, and H is a string 963f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen that contains one or more dots. 973f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 5. If the dictionary has a Port attribute and the referer URL's port was not 983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen in the list. 993f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen */ 1003f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // TODO(jar): Redirects in dictionary fetches might plausibly be problematic, 1023f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // and hence the conservative approach is to not allow any redirects (if there 1033f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // were any... then don't allow the dictionary to be set). 1043f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1053f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (domain.empty()) { 1063f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER); 1073f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; // Domain is required. 1083f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (RegistryControlledDomainService::GetDomainAndRegistry(domain).size() 1103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen == 0) { 1113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN); 1123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; // domain was a TLD. 1133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!Dictionary::DomainMatch(dictionary_url, domain)) { 1153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL); 1163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1173f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1183f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1193f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen std::string referrer_url_host = dictionary_url.host(); 1203f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen size_t postfix_domain_index = referrer_url_host.rfind(domain); 1213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // See if it is indeed a postfix, or just an internal string. 1223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (referrer_url_host.size() == postfix_domain_index + domain.size()) { 1233f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // It is a postfix... so check to see if there's a dot in the prefix. 1243f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen size_t end_of_host_index = referrer_url_host.find_first_of('.'); 1253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (referrer_url_host.npos != end_of_host_index && 1263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen end_of_host_index < postfix_domain_index) { 1273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX); 1283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!ports.empty() 1333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen && 0 == ports.count(dictionary_url.EffectiveIntPort())) { 1343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); 1353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1363f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return true; 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 1413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool SdchManager::Dictionary::CanUse(const GURL& referring_url) { 1423f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!SdchManager::Global()->IsInSupportedDomain(referring_url)) 1433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1443f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen /* 1453f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1. The request URL's host name domain-matches the Domain attribute of the 1463f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen dictionary. 1473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2. If the dictionary has a Port attribute, the request port is one of the 1483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ports listed in the Port attribute. 1493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 3. The request URL path-matches the path attribute of the dictionary. 1503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 4. The request is not an HTTPS request. 1513f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen*/ 1523f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!DomainMatch(referring_url, domain_)) { 1533f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN); 1543f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1553f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!ports_.empty() 1573f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen && 0 == ports_.count(referring_url.EffectiveIntPort())) { 1583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST); 1593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1603f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1613f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (path_.size() && !PathMatch(referring_url.path(), path_)) { 1623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH); 1633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1643f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (referring_url.SchemeIsSecure()) { 1663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME); 1673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1693f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // TODO(jar): Remove overly restrictive failsafe test (added per security 1713f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // review) when we have a need to be more general. 1723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!referring_url.SchemeIs("http")) { 1733f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SdchErrorRecovery(ATTEMPT_TO_DECODE_NON_HTTP_DATA); 1743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1753f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1763f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1773f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return true; 1783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 1793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1803f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool SdchManager::Dictionary::PathMatch(const std::string& path, 1813f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen const std::string& restriction) { 1823f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen /* Must be either: 1833f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1. P2 is equal to P1 1843f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2. P2 is a prefix of P1 and either the final character in P2 is "/" or the 1853f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen character following P2 in P1 is "/". 1863f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen */ 1873f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (path == restriction) 1883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return true; 1893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen size_t prefix_length = restriction.size(); 1903f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (prefix_length > path.size()) 1913f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; // Can't be a prefix. 1923f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (0 != path.compare(0, prefix_length, restriction)) 1933f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1943f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return restriction[prefix_length - 1] == '/' || path[prefix_length] == '/'; 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 1983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool SdchManager::Dictionary::DomainMatch(const GURL& gurl, 1993f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen const std::string& restriction) { 2003f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // TODO(jar): This is not precisely a domain match definition. 2013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return gurl.DomainIs(restriction.data(), restriction.size()); 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------ 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSdchManager::SdchManager() : sdch_enabled_(false) { 206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!global_); 207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_ = this; 208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSdchManager::~SdchManager() { 211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(global_ == this); 212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (!dictionaries_.empty()) { 213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DictionaryMap::iterator it = dictionaries_.begin(); 214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott it->second->Release(); 215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionaries_.erase(it->first); 216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_ = NULL; 218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::Shutdown() { 222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!global_ ) 223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->fetcher_.reset(NULL); 225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 2283f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenSdchManager* SdchManager::Global() { 2293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return global_; 2303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 2313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// static 2333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid SdchManager::SdchErrorRecovery(ProblemCodes problem) { 2343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE); 2353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 2363f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid SdchManager::EnableSdchSupport(const std::string& domain) { 2383f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // We presume that there is a SDCH manager instance. 2393f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen global_->supported_domain_ = domain; 2403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen global_->sdch_enabled_ = true; 2413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 2423f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// static 244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::BlacklistDomain(const GURL& url) { 245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!global_ ) 246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->SetAllowLatencyExperiment(url, false); 248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string domain(StringToLowerASCII(url.host())); 250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int count = global_->blacklisted_domains_[domain]; 251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (count > 0) 252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; // Domain is already blacklisted. 253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott count = 1 + 2 * global_->exponential_blacklist_count[domain]; 255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (count > 0) 256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->exponential_blacklist_count[domain] = count; 257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott else 258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott count = INT_MAX; 259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->blacklisted_domains_[domain] = count; 261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::BlacklistDomainForever(const GURL& url) { 265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!global_ ) 266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->SetAllowLatencyExperiment(url, false); 268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string domain(StringToLowerASCII(url.host())); 270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->exponential_blacklist_count[domain] = INT_MAX; 271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott global_->blacklisted_domains_[domain] = INT_MAX; 272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 2743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// static 2753f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid SdchManager::ClearBlacklistings() { 2763f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Global()->blacklisted_domains_.clear(); 2773f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Global()->exponential_blacklist_count.clear(); 2783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 2793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2803f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// static 2813f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid SdchManager::ClearDomainBlacklisting(const std::string& domain) { 2823f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Global()->blacklisted_domains_.erase(StringToLowerASCII(domain)); 2833f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 2843f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2853f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// static 2863f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenint SdchManager::BlackListDomainCount(const std::string& domain) { 2873f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (Global()->blacklisted_domains_.end() == 2883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Global()->blacklisted_domains_.find(domain)) 2893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return 0; 2903f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return Global()->blacklisted_domains_[StringToLowerASCII(domain)]; 2913f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 2923f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 2933f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// static 2943f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenint SdchManager::BlacklistDomainExponential(const std::string& domain) { 2953f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (Global()->exponential_blacklist_count.end() == 2963f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Global()->exponential_blacklist_count.find(domain)) 2973f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return 0; 2983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return Global()->exponential_blacklist_count[StringToLowerASCII(domain)]; 299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SdchManager::IsInSupportedDomain(const GURL& url) { 302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!sdch_enabled_ ) 303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!supported_domain_.empty() && 305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott !url.DomainIs(supported_domain_.data(), supported_domain_.size())) 306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // It is not the singular supported domain. 307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (blacklisted_domains_.empty()) 309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string domain(StringToLowerASCII(url.host())); 312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DomainCounter::iterator it = blacklisted_domains_.find(domain); 313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (blacklisted_domains_.end() == it) 314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int count = it->second - 1; 317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (count > 0) 318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott blacklisted_domains_[domain] = count; 319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott else 320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott blacklisted_domains_.erase(domain); 321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET); 322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 3253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid SdchManager::FetchDictionary(const GURL& request_url, 3263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen const GURL& dictionary_url) { 3273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (SdchManager::Global()->CanFetchDictionary(request_url, dictionary_url) && 3283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen fetcher_.get()) 3293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen fetcher_->Schedule(dictionary_url); 3303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 3313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::CanFetchDictionary(const GURL& referring_url, 333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& dictionary_url) const { 334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott /* The user agent may retrieve a dictionary from the dictionary URL if all of 335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott the following are true: 336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1 The dictionary URL host name matches the referrer URL host name 337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 2 The dictionary URL host name domain matches the parent domain of the 338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott referrer URL host name 339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 3 The parent domain of the referrer URL host name is not a top level 340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott domain 341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 4 The dictionary URL is not an HTTPS URL. 342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */ 343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Item (1) above implies item (2). Spec should be updated. 344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // I take "host name match" to be "is identical to" 345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (referring_url.host() != dictionary_url.host()) { 346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST); 347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (referring_url.SchemeIs("https")) { 350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL); 351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // TODO(jar): Remove this failsafe conservative hack which is more restrictive 355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // than current SDCH spec when needed, and justified by security audit. 356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!referring_url.SchemeIs("http")) { 357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP); 358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::AddSdchDictionary(const std::string& dictionary_text, 365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& dictionary_url) { 366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string client_hash; 367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string server_hash; 368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott GenerateHash(dictionary_text, &client_hash, &server_hash); 369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (dictionaries_.find(server_hash) != dictionaries_.end()) { 370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_ALREADY_LOADED); 371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Already loaded. 372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string domain, path; 375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::set<int> ports; 37672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); 377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (dictionary_text.empty()) { 379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT); 380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Missing header. 381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t header_end = dictionary_text.find("\n\n"); 384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (std::string::npos == header_end) { 385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER); 386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Missing header. 387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t line_start = 0; // Start of line being parsed. 389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (1) { 390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t line_end = dictionary_text.find('\n', line_start); 391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(std::string::npos != line_end); 392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(line_end <= header_end); 393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t colon_index = dictionary_text.find(':', line_start); 395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (std::string::npos == colon_index) { 396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON); 397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; // Illegal line missing a colon. 398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (colon_index > line_end) 401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t value_start = dictionary_text.find_first_not_of(" \t", 404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott colon_index + 1); 405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (std::string::npos != value_start) { 406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (value_start >= line_end) 407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string name(dictionary_text, line_start, colon_index - line_start); 409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string value(dictionary_text, value_start, line_end - value_start); 410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name = StringToLowerASCII(name); 411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (name == "domain") { 412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott domain = value; 413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (name == "path") { 414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott path = value; 415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (name == "format-version") { 416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (value != "1.0") 417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (name == "max-age") { 4193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int64 seconds; 4203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::StringToInt64(value, &seconds); 42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen expiration = base::Time::Now() + base::TimeDelta::FromSeconds(seconds); 422c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (name == "port") { 4233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int port; 4243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::StringToInt(value, &port); 425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (port >= 0) 426c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ports.insert(port); 427c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 428c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 429c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (line_end >= header_end) 431c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 432c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott line_start = line_end + 1; 433c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 434c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!Dictionary::CanSet(domain, path, ports, dictionary_url)) 436c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 437c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 438c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of 439c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // useless dictionaries. We should probably have a cache eviction plan, 440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // instead of just blocking additions. For now, with the spec in flux, it 441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // is probably not worth doing eviction handling. 442c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (kMaxDictionarySize < dictionary_text.size()) { 443c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE); 444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 445c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (kMaxDictionaryCount <= dictionaries_.size()) { 447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED); 448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 449c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 4514ceda5254f89dd540c17e037d7ede22b1817f4e2Kristian Monsen UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); 452731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DVLOG(1) << "Loaded dictionary with client hash " << client_hash 453731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick << " and server hash " << server_hash; 454c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Dictionary* dictionary = 455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott new Dictionary(dictionary_text, header_end + 2, client_hash, 456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionary_url, domain, path, expiration, ports); 457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionary->AddRef(); 458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dictionaries_[server_hash] = dictionary; 459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::GetVcdiffDictionary(const std::string& server_hash, 463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const GURL& referring_url, Dictionary** dictionary) { 464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *dictionary = NULL; 465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DictionaryMap::iterator it = dictionaries_.find(server_hash); 466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (it == dictionaries_.end()) { 467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Dictionary* matching_dictionary = it->second; 470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!matching_dictionary->CanUse(referring_url)) 471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *dictionary = matching_dictionary; 473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 474c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 475c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// TODO(jar): If we have evictions from the dictionaries_, then we need to 476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// change this interface to return a list of reference counted Dictionary 477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// instances that can be used if/when a server specifies one. 478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::GetAvailDictionaryList(const GURL& target_url, 479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string* list) { 480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int count = 0; 481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (DictionaryMap::iterator it = dictionaries_.begin(); 482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott it != dictionaries_.end(); ++it) { 483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!it->second->CanAdvertise(target_url)) 484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++count; 486c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!list->empty()) 487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott list->append(","); 488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott list->append(it->second->client_hash()); 489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Watch to see if we have corrupt or numerous dictionaries. 4914ceda5254f89dd540c17e037d7ede22b1817f4e2Kristian Monsen if (count > 0) 4924ceda5254f89dd540c17e037d7ede22b1817f4e2Kristian Monsen UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); 493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::GenerateHash(const std::string& dictionary_text, 497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string* client_hash, std::string* server_hash) { 498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char binary_hash[32]; 499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash)); 500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 501c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string first_48_bits(&binary_hash[0], 6); 502c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string second_48_bits(&binary_hash[6], 6); 503c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UrlSafeBase64Encode(first_48_bits, client_hash); 504c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott UrlSafeBase64Encode(second_48_bits, server_hash); 505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_EQ(server_hash->length(), 8u); 507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_EQ(client_hash->length(), 8u); 508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 510c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------ 511c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Methods for supporting latency experiments. 512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 513c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SdchManager::AllowLatencyExperiment(const GURL& url) const { 514c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return allow_latency_experiment_.end() != 515c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott allow_latency_experiment_.find(url.host()); 516c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 517c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { 519c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (enable) { 520c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott allow_latency_experiment_.insert(url.host()); 521c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 522c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 523c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ExperimentSet::iterator it = allow_latency_experiment_.find(url.host()); 524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (allow_latency_experiment_.end() == it) 525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; // It was already erased, or never allowed. 526c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SdchErrorRecovery(LATENCY_TEST_DISALLOWED); 527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott allow_latency_experiment_.erase(it); 528c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 5293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 5303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// static 5313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid SdchManager::UrlSafeBase64Encode(const std::string& input, 5323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen std::string* output) { 5333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Since this is only done during a dictionary load, and hashes are only 8 5343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // characters, we just do the simple fixup, rather than rewriting the encoder. 5353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen base::Base64Encode(input, output); 5363f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen for (size_t i = 0; i < output->size(); ++i) { 5373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen switch (output->data()[i]) { 5383f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen case '+': 5393f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen (*output)[i] = '-'; 5403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen continue; 5413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen case '/': 5423f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen (*output)[i] = '_'; 5433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen continue; 5443f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen default: 5453f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen continue; 5463f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 5473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 5483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 54972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 55072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} // namespace net 551