Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(802)

Side by Side Diff: net/base/sdch_manager.cc

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

Powered by Google App Engine
This is Rietveld 408576698