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

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

Issue 423813002: Sdch view for net-internals (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 4 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/values.h"
12 #include "crypto/sha2.h" 13 #include "crypto/sha2.h"
13 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 14 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
14 #include "net/url_request/url_request_http_job.h" 15 #include "net/url_request/url_request_http_job.h"
15 16
16 namespace net { 17 namespace net {
17 18
19 namespace {
20
21 bool IsDictionaryProblem(SdchManager::ProblemCodes code) {
22 return code >= SdchManager::DICTIONARY_HAS_NO_HEADER &&
23 code <= SdchManager::DICTIONARY_ALREADY_TRIED_TO_DOWNLOAD;
24 }
25
26 }
27
18 //------------------------------------------------------------------------------ 28 //------------------------------------------------------------------------------
19 // static 29 // static
20 30
21 // Adjust SDCH limits downwards for mobile. 31 // Adjust SDCH limits downwards for mobile.
22 #if defined(OS_ANDROID) || defined(OS_IOS) 32 #if defined(OS_ANDROID) || defined(OS_IOS)
23 // static 33 // static
24 const size_t SdchManager::kMaxDictionaryCount = 1; 34 const size_t SdchManager::kMaxDictionaryCount = 1;
25 const size_t SdchManager::kMaxDictionarySize = 150 * 1000; 35 const size_t SdchManager::kMaxDictionarySize = 150 * 1000;
26 #else 36 #else
27 // static 37 // static
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 return false; 90 return false;
81 if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure()) 91 if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
82 return false; 92 return false;
83 if (target_url.SchemeIsSecure() != url_.SchemeIsSecure()) 93 if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
84 return false; 94 return false;
85 if (base::Time::Now() > expiration_) 95 if (base::Time::Now() > expiration_)
86 return false; 96 return false;
87 return true; 97 return true;
88 } 98 }
89 99
100 base::DictionaryValue*
101 SdchManager::Dictionary::DictionaryInfoToValue() const {
102 base::DictionaryValue* value = new base::DictionaryValue();
103 value->SetString("url", url_.spec());
104 value->SetString("client_hash", client_hash_);
105 value->SetString("domain", domain_);
106 value->SetString("path", path_);
107 value->SetString("expiration",
108 base::Int64ToString(expiration_.ToInternalValue()));
109 base::ListValue* port_list = new base::ListValue();
110 for (std::set<int>::const_iterator it = ports_.begin();
111 it != ports_.end(); ++it) {
112 port_list->AppendInteger(*it);
113 }
114 value->Set("ports", port_list);
115 return value;
116 }
117
90 //------------------------------------------------------------------------------ 118 //------------------------------------------------------------------------------
91 // Security functions restricting loads and use of dictionaries. 119 // Security functions restricting loads and use of dictionaries.
92 120
93 // static 121 // static
94 bool SdchManager::Dictionary::CanSet(const std::string& domain, 122 bool SdchManager::Dictionary::CanSet(const std::string& domain,
95 const std::string& path, 123 const std::string& path,
96 const std::set<int>& ports, 124 const std::set<int>& ports,
97 const GURL& dictionary_url) { 125 const GURL& dictionary_url,
126 SdchManager* sdch_manager) {
98 /* 127 /*
99 A dictionary is invalid and must not be stored if any of the following are 128 A dictionary is invalid and must not be stored if any of the following are
100 true: 129 true:
101 1. The dictionary has no Domain attribute. 130 1. The dictionary has no Domain attribute.
102 2. The effective host name that derives from the referer URL host name does 131 2. The effective host name that derives from the referer URL host name does
103 not domain-match the Domain attribute. 132 not domain-match the Domain attribute.
104 3. The Domain attribute is a top level domain. 133 3. The Domain attribute is a top level domain.
105 4. The referer URL host is a host domain name (not IP address) and has the 134 4. The referer URL host is a host domain name (not IP address) and has the
106 form HD, where D is the value of the Domain attribute, and H is a string 135 form HD, where D is the value of the Domain attribute, and H is a string
107 that contains one or more dots. 136 that contains one or more dots.
108 5. If the dictionary has a Port attribute and the referer URL's port was not 137 5. If the dictionary has a Port attribute and the referer URL's port was not
109 in the list. 138 in the list.
110 */ 139 */
111 140
112 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic, 141 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic,
113 // and hence the conservative approach is to not allow any redirects (if there 142 // and hence the conservative approach is to not allow any redirects (if there
114 // were any... then don't allow the dictionary to be set). 143 // were any... then don't allow the dictionary to be set).
115 144
116 if (domain.empty()) { 145 if (domain.empty()) {
117 SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER); 146 sdch_manager->SdchErrorRecovery(
147 DICTIONARY_MISSING_DOMAIN_SPECIFIER, dictionary_url);
118 return false; // Domain is required. 148 return false; // Domain is required.
119 } 149 }
120 if (registry_controlled_domains::GetDomainAndRegistry( 150 if (registry_controlled_domains::GetDomainAndRegistry(
121 domain, 151 domain,
122 registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES).empty()) { 152 registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES).empty()) {
123 SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN); 153 sdch_manager->SdchErrorRecovery(
154 DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN, dictionary_url);
124 return false; // domain was a TLD. 155 return false; // domain was a TLD.
125 } 156 }
126 if (!Dictionary::DomainMatch(dictionary_url, domain)) { 157 if (!Dictionary::DomainMatch(dictionary_url, domain)) {
127 SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL); 158 sdch_manager->SdchErrorRecovery(
159 DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL, dictionary_url);
128 return false; 160 return false;
129 } 161 }
130 162
131 std::string referrer_url_host = dictionary_url.host(); 163 std::string referrer_url_host = dictionary_url.host();
132 size_t postfix_domain_index = referrer_url_host.rfind(domain); 164 size_t postfix_domain_index = referrer_url_host.rfind(domain);
133 // See if it is indeed a postfix, or just an internal string. 165 // See if it is indeed a postfix, or just an internal string.
134 if (referrer_url_host.size() == postfix_domain_index + domain.size()) { 166 if (referrer_url_host.size() == postfix_domain_index + domain.size()) {
135 // It is a postfix... so check to see if there's a dot in the prefix. 167 // It is a postfix... so check to see if there's a dot in the prefix.
136 size_t end_of_host_index = referrer_url_host.find_first_of('.'); 168 size_t end_of_host_index = referrer_url_host.find_first_of('.');
137 if (referrer_url_host.npos != end_of_host_index && 169 if (referrer_url_host.npos != end_of_host_index &&
138 end_of_host_index < postfix_domain_index) { 170 end_of_host_index < postfix_domain_index) {
139 SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX); 171 sdch_manager->SdchErrorRecovery(
172 DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX, dictionary_url);
140 return false; 173 return false;
141 } 174 }
142 } 175 }
143 176
144 if (!ports.empty() 177 if (!ports.empty()
145 && 0 == ports.count(dictionary_url.EffectiveIntPort())) { 178 && 0 == ports.count(dictionary_url.EffectiveIntPort())) {
146 SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); 179 sdch_manager->SdchErrorRecovery(
180 DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL, dictionary_url);
147 return false; 181 return false;
148 } 182 }
149 return true; 183 return true;
150 } 184 }
151 185
152 // static 186 bool SdchManager::Dictionary::CanUse(
153 bool SdchManager::Dictionary::CanUse(const GURL& referring_url) { 187 const GURL& referring_url, SdchManager* sdch_manager) {
154 /* 188 /*
155 1. The request URL's host name domain-matches the Domain attribute of the 189 1. The request URL's host name domain-matches the Domain attribute of the
156 dictionary. 190 dictionary.
157 2. If the dictionary has a Port attribute, the request port is one of the 191 2. If the dictionary has a Port attribute, the request port is one of the
158 ports listed in the Port attribute. 192 ports listed in the Port attribute.
159 3. The request URL path-matches the path attribute of the dictionary. 193 3. The request URL path-matches the path attribute of the dictionary.
160 4. The request is not an HTTPS request. 194 4. The request is not an HTTPS request.
161 We can override (ignore) item (4) only when we have explicitly enabled 195 We can override (ignore) item (4) only when we have explicitly enabled
162 HTTPS support AND the dictionary acquisition scheme matches the target 196 HTTPS support AND the dictionary acquisition scheme matches the target
163 url scheme. 197 url scheme.
164 */ 198 */
165 if (!DomainMatch(referring_url, domain_)) { 199 if (!DomainMatch(referring_url, domain_)) {
166 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN); 200 sdch_manager->SdchErrorRecovery(
201 DICTIONARY_FOUND_HAS_WRONG_DOMAIN, referring_url);
167 return false; 202 return false;
168 } 203 }
169 if (!ports_.empty() 204 if (!ports_.empty()
170 && 0 == ports_.count(referring_url.EffectiveIntPort())) { 205 && 0 == ports_.count(referring_url.EffectiveIntPort())) {
171 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST); 206 sdch_manager->SdchErrorRecovery(
207 DICTIONARY_FOUND_HAS_WRONG_PORT_LIST, referring_url);
172 return false; 208 return false;
173 } 209 }
174 if (path_.size() && !PathMatch(referring_url.path(), path_)) { 210 if (path_.size() && !PathMatch(referring_url.path(), path_)) {
175 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH); 211 sdch_manager->SdchErrorRecovery(
212 DICTIONARY_FOUND_HAS_WRONG_PATH, referring_url);
176 return false; 213 return false;
177 } 214 }
178 if (!SdchManager::secure_scheme_supported() && 215 if (!SdchManager::secure_scheme_supported() &&
179 referring_url.SchemeIsSecure()) { 216 referring_url.SchemeIsSecure()) {
180 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME); 217 sdch_manager->SdchErrorRecovery(
218 DICTIONARY_FOUND_HAS_WRONG_SCHEME, referring_url);
181 return false; 219 return false;
182 } 220 }
183 if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) { 221 if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) {
184 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME); 222 sdch_manager->SdchErrorRecovery(
223 DICTIONARY_FOUND_HAS_WRONG_SCHEME, referring_url);
185 return false; 224 return false;
186 } 225 }
187 226
188 // TODO(jar): Remove overly restrictive failsafe test (added per security 227 // TODO(jar): Remove overly restrictive failsafe test (added per security
189 // review) when we have a need to be more general. 228 // review) when we have a need to be more general.
190 if (!referring_url.SchemeIsHTTPOrHTTPS()) { 229 if (!referring_url.SchemeIsHTTPOrHTTPS()) {
191 SdchErrorRecovery(ATTEMPT_TO_DECODE_NON_HTTP_DATA); 230 sdch_manager->SdchErrorRecovery(
231 ATTEMPT_TO_DECODE_NON_HTTP_DATA, referring_url);
192 return false; 232 return false;
193 } 233 }
194 234
195 return true; 235 return true;
196 } 236 }
197 237
198 bool SdchManager::Dictionary::PathMatch(const std::string& path, 238 bool SdchManager::Dictionary::PathMatch(const std::string& path,
199 const std::string& restriction) { 239 const std::string& restriction) {
200 /* Must be either: 240 /* Must be either:
201 1. P2 is equal to P1 241 1. P2 is equal to P1
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 fetcher_->Cancel(); 280 fetcher_->Cancel();
241 281
242 // Note that this may result in not having dictionaries we've advertised 282 // Note that this may result in not having dictionaries we've advertised
243 // for incoming responses. The window is relatively small (as ClearData() 283 // for incoming responses. The window is relatively small (as ClearData()
244 // is not expected to be called frequently), so we rely on meta-refresh 284 // is not expected to be called frequently), so we rely on meta-refresh
245 // to handle this case. 285 // to handle this case.
246 dictionaries_.clear(); 286 dictionaries_.clear();
247 } 287 }
248 288
249 // static 289 // static
250 void SdchManager::SdchErrorRecovery(ProblemCodes problem) { 290 void SdchManager::SdchErrorRecovery(
291 ProblemCodes problem, const GURL& url) const {
251 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE); 292 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE);
293 problems_.push_back(std::make_pair(url.spec(), problem));
252 } 294 }
253 295
254 void SdchManager::set_sdch_fetcher(SdchFetcher* fetcher) { 296 void SdchManager::set_sdch_fetcher(SdchFetcher* fetcher) {
255 DCHECK(CalledOnValidThread()); 297 DCHECK(CalledOnValidThread());
256 fetcher_.reset(fetcher); 298 fetcher_.reset(fetcher);
257 } 299 }
258 300
259 // static 301 // static
260 void SdchManager::EnableSdchSupport(bool enabled) { 302 void SdchManager::EnableSdchSupport(bool enabled) {
261 g_sdch_enabled_ = enabled; 303 g_sdch_enabled_ = enabled;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 std::string domain(StringToLowerASCII(url.host())); 369 std::string domain(StringToLowerASCII(url.host()));
328 DomainCounter::iterator it = blacklisted_domains_.find(domain); 370 DomainCounter::iterator it = blacklisted_domains_.find(domain);
329 if (blacklisted_domains_.end() == it) 371 if (blacklisted_domains_.end() == it)
330 return true; 372 return true;
331 373
332 int count = it->second - 1; 374 int count = it->second - 1;
333 if (count > 0) 375 if (count > 0)
334 blacklisted_domains_[domain] = count; 376 blacklisted_domains_[domain] = count;
335 else 377 else
336 blacklisted_domains_.erase(domain); 378 blacklisted_domains_.erase(domain);
337 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET); 379 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET, url);
338 return false; 380 return false;
339 } 381 }
340 382
341 void SdchManager::FetchDictionary(const GURL& request_url, 383 void SdchManager::FetchDictionary(const GURL& request_url,
342 const GURL& dictionary_url) { 384 const GURL& dictionary_url) {
343 DCHECK(CalledOnValidThread()); 385 DCHECK(CalledOnValidThread());
344 if (CanFetchDictionary(request_url, dictionary_url) && fetcher_.get()) 386 if (CanFetchDictionary(request_url, dictionary_url) && fetcher_.get())
345 fetcher_->Schedule(dictionary_url); 387 fetcher_->Schedule(dictionary_url);
346 } 388 }
347 389
348 bool SdchManager::CanFetchDictionary(const GURL& referring_url, 390 bool SdchManager::CanFetchDictionary(const GURL& referring_url,
349 const GURL& dictionary_url) const { 391 const GURL& dictionary_url) const {
350 DCHECK(CalledOnValidThread()); 392 DCHECK(CalledOnValidThread());
351 /* The user agent may retrieve a dictionary from the dictionary URL if all of 393 /* The user agent may retrieve a dictionary from the dictionary URL if all of
352 the following are true: 394 the following are true:
353 1 The dictionary URL host name matches the referrer URL host name and 395 1 The dictionary URL host name matches the referrer URL host name and
354 scheme. 396 scheme.
355 2 The dictionary URL host name domain matches the parent domain of the 397 2 The dictionary URL host name domain matches the parent domain of the
356 referrer URL host name 398 referrer URL host name
357 3 The parent domain of the referrer URL host name is not a top level 399 3 The parent domain of the referrer URL host name is not a top level
358 domain 400 domain
359 4 The dictionary URL is not an HTTPS URL. 401 4 The dictionary URL is not an HTTPS URL.
360 */ 402 */
361 // Item (1) above implies item (2). Spec should be updated. 403 // Item (1) above implies item (2). Spec should be updated.
362 // I take "host name match" to be "is identical to" 404 // I take "host name match" to be "is identical to"
363 if (referring_url.host() != dictionary_url.host() || 405 if (referring_url.host() != dictionary_url.host() ||
364 referring_url.scheme() != dictionary_url.scheme()) { 406 referring_url.scheme() != dictionary_url.scheme()) {
365 SdchErrorRecovery(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST); 407 SdchErrorRecovery(
408 DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST, dictionary_url);
366 return false; 409 return false;
367 } 410 }
368 if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) { 411 if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) {
369 SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL); 412 SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL, dictionary_url);
370 return false; 413 return false;
371 } 414 }
372 415
373 // TODO(jar): Remove this failsafe conservative hack which is more restrictive 416 // TODO(jar): Remove this failsafe conservative hack which is more restrictive
374 // than current SDCH spec when needed, and justified by security audit. 417 // than current SDCH spec when needed, and justified by security audit.
375 if (!referring_url.SchemeIsHTTPOrHTTPS()) { 418 if (!referring_url.SchemeIsHTTPOrHTTPS()) {
376 SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP); 419 SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP, dictionary_url);
377 return false; 420 return false;
378 } 421 }
379 422
380 return true; 423 return true;
381 } 424 }
382 425
383 bool SdchManager::AddSdchDictionary(const std::string& dictionary_text, 426 bool SdchManager::AddSdchDictionary(const std::string& dictionary_text,
384 const GURL& dictionary_url) { 427 const GURL& dictionary_url) {
385 DCHECK(CalledOnValidThread()); 428 DCHECK(CalledOnValidThread());
386 std::string client_hash; 429 std::string client_hash;
387 std::string server_hash; 430 std::string server_hash;
388 GenerateHash(dictionary_text, &client_hash, &server_hash); 431 GenerateHash(dictionary_text, &client_hash, &server_hash);
389 if (dictionaries_.find(server_hash) != dictionaries_.end()) { 432 if (dictionaries_.find(server_hash) != dictionaries_.end()) {
390 SdchErrorRecovery(DICTIONARY_ALREADY_LOADED); 433 SdchErrorRecovery(DICTIONARY_ALREADY_LOADED, dictionary_url);
391 return false; // Already loaded. 434 return false; // Already loaded.
392 } 435 }
393 436
394 std::string domain, path; 437 std::string domain, path;
395 std::set<int> ports; 438 std::set<int> ports;
396 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); 439 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30));
397 440
398 if (dictionary_text.empty()) { 441 if (dictionary_text.empty()) {
399 SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT); 442 SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT, dictionary_url);
400 return false; // Missing header. 443 return false; // Missing header.
401 } 444 }
402 445
403 size_t header_end = dictionary_text.find("\n\n"); 446 size_t header_end = dictionary_text.find("\n\n");
404 if (std::string::npos == header_end) { 447 if (std::string::npos == header_end) {
405 SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER); 448 SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER, dictionary_url);
406 return false; // Missing header. 449 return false; // Missing header.
407 } 450 }
408 size_t line_start = 0; // Start of line being parsed. 451 size_t line_start = 0; // Start of line being parsed.
409 while (1) { 452 while (1) {
410 size_t line_end = dictionary_text.find('\n', line_start); 453 size_t line_end = dictionary_text.find('\n', line_start);
411 DCHECK(std::string::npos != line_end); 454 DCHECK(std::string::npos != line_end);
412 DCHECK_LE(line_end, header_end); 455 DCHECK_LE(line_end, header_end);
413 456
414 size_t colon_index = dictionary_text.find(':', line_start); 457 size_t colon_index = dictionary_text.find(':', line_start);
415 if (std::string::npos == colon_index) { 458 if (std::string::npos == colon_index) {
416 SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON); 459 SdchErrorRecovery(
460 DICTIONARY_HEADER_LINE_MISSING_COLON, dictionary_url);
417 return false; // Illegal line missing a colon. 461 return false; // Illegal line missing a colon.
418 } 462 }
419 463
420 if (colon_index > line_end) 464 if (colon_index > line_end)
421 break; 465 break;
422 466
423 size_t value_start = dictionary_text.find_first_not_of(" \t", 467 size_t value_start = dictionary_text.find_first_not_of(" \t",
424 colon_index + 1); 468 colon_index + 1);
425 if (std::string::npos != value_start) { 469 if (std::string::npos != value_start) {
426 if (value_start >= line_end) 470 if (value_start >= line_end)
(...skipping 21 matching lines...) Expand all
448 } 492 }
449 493
450 if (line_end >= header_end) 494 if (line_end >= header_end)
451 break; 495 break;
452 line_start = line_end + 1; 496 line_start = line_end + 1;
453 } 497 }
454 498
455 if (!IsInSupportedDomain(dictionary_url)) 499 if (!IsInSupportedDomain(dictionary_url))
456 return false; 500 return false;
457 501
458 if (!Dictionary::CanSet(domain, path, ports, dictionary_url)) 502 if (!Dictionary::CanSet(domain, path, ports, dictionary_url, this))
459 return false; 503 return false;
460 504
461 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of 505 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of
462 // useless dictionaries. We should probably have a cache eviction plan, 506 // useless dictionaries. We should probably have a cache eviction plan,
463 // instead of just blocking additions. For now, with the spec in flux, it 507 // instead of just blocking additions. For now, with the spec in flux, it
464 // is probably not worth doing eviction handling. 508 // is probably not worth doing eviction handling.
465 if (kMaxDictionarySize < dictionary_text.size()) { 509 if (kMaxDictionarySize < dictionary_text.size()) {
466 SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE); 510 SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE, dictionary_url);
467 return false; 511 return false;
468 } 512 }
469 if (kMaxDictionaryCount <= dictionaries_.size()) { 513 if (kMaxDictionaryCount <= dictionaries_.size()) {
470 SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED); 514 SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED, dictionary_url);
471 return false; 515 return false;
472 } 516 }
473 517
474 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); 518 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
475 DVLOG(1) << "Loaded dictionary with client hash " << client_hash 519 DVLOG(1) << "Loaded dictionary with client hash " << client_hash
476 << " and server hash " << server_hash; 520 << " and server hash " << server_hash;
477 Dictionary* dictionary = 521 Dictionary* dictionary =
478 new Dictionary(dictionary_text, header_end + 2, client_hash, 522 new Dictionary(dictionary_text, header_end + 2, client_hash,
479 dictionary_url, domain, path, expiration, ports); 523 dictionary_url, domain, path, expiration, ports);
480 dictionaries_[server_hash] = dictionary; 524 dictionaries_[server_hash] = dictionary;
481 return true; 525 return true;
482 } 526 }
483 527
484 void SdchManager::GetVcdiffDictionary( 528 void SdchManager::GetVcdiffDictionary(
485 const std::string& server_hash, 529 const std::string& server_hash,
486 const GURL& referring_url, 530 const GURL& referring_url,
487 scoped_refptr<Dictionary>* dictionary) { 531 scoped_refptr<Dictionary>* dictionary) {
488 DCHECK(CalledOnValidThread()); 532 DCHECK(CalledOnValidThread());
489 *dictionary = NULL; 533 *dictionary = NULL;
490 DictionaryMap::iterator it = dictionaries_.find(server_hash); 534 DictionaryMap::iterator it = dictionaries_.find(server_hash);
491 if (it == dictionaries_.end()) { 535 if (it == dictionaries_.end()) {
492 return; 536 return;
493 } 537 }
494 scoped_refptr<Dictionary> matching_dictionary = it->second; 538 scoped_refptr<Dictionary> matching_dictionary = it->second;
495 if (!IsInSupportedDomain(referring_url)) 539 if (!IsInSupportedDomain(referring_url))
496 return; 540 return;
497 if (!matching_dictionary->CanUse(referring_url)) 541 if (!matching_dictionary->CanUse(referring_url, this))
498 return; 542 return;
499 *dictionary = matching_dictionary; 543 *dictionary = matching_dictionary;
500 } 544 }
501 545
502 // TODO(jar): If we have evictions from the dictionaries_, then we need to 546 // TODO(jar): If we have evictions from the dictionaries_, then we need to
503 // change this interface to return a list of reference counted Dictionary 547 // change this interface to return a list of reference counted Dictionary
504 // instances that can be used if/when a server specifies one. 548 // instances that can be used if/when a server specifies one.
505 void SdchManager::GetAvailDictionaryList(const GURL& target_url, 549 void SdchManager::GetAvailDictionaryList(const GURL& target_url,
506 std::string* list) { 550 std::string* list) {
507 DCHECK(CalledOnValidThread()); 551 DCHECK(CalledOnValidThread());
(...skipping 22 matching lines...) Expand all
530 574
531 std::string first_48_bits(&binary_hash[0], 6); 575 std::string first_48_bits(&binary_hash[0], 6);
532 std::string second_48_bits(&binary_hash[6], 6); 576 std::string second_48_bits(&binary_hash[6], 6);
533 UrlSafeBase64Encode(first_48_bits, client_hash); 577 UrlSafeBase64Encode(first_48_bits, client_hash);
534 UrlSafeBase64Encode(second_48_bits, server_hash); 578 UrlSafeBase64Encode(second_48_bits, server_hash);
535 579
536 DCHECK_EQ(server_hash->length(), 8u); 580 DCHECK_EQ(server_hash->length(), 8u);
537 DCHECK_EQ(client_hash->length(), 8u); 581 DCHECK_EQ(client_hash->length(), 8u);
538 } 582 }
539 583
584 base::Value* SdchManager::SdchInfoToValue() const {
585 base::DictionaryValue* value = new base::DictionaryValue();
586
587 value->SetBoolean("sdch_enabled", sdch_enabled());
588 value->SetBoolean("secure_scheme_support", secure_scheme_supported());
589
590 base::ListValue* entry_list = new base::ListValue();
591 for (DictionaryMap::const_iterator it = dictionaries_.begin();
592 it != dictionaries_.end(); ++it) {
593 base::DictionaryValue* entry_dict = it->second->DictionaryInfoToValue();
594 entry_dict->SetString("server_hash", it->first);
595 entry_list->Append(entry_dict);
596 }
597 value->Set("dictionaries", entry_list);
598
599 entry_list = new base::ListValue();
600 for (DomainCounter::const_iterator it = blacklisted_domains_.begin();
601 it != blacklisted_domains_.end(); ++it) {
602 base::DictionaryValue* entry_dict = new base::DictionaryValue();
603 entry_dict->SetString("domain", it->first);
604 if (it->second != INT_MAX)
605 entry_dict->SetInteger("tries", it->second);
606 entry_list->Append(entry_dict);
607 }
608 value->Set("blacklisted", entry_list);
609
610
611 base::ListValue* dict_problems_list = new base::ListValue();
612 base::ListValue* usage_problems_list = new base::ListValue();
613 for (size_t i = 0; i < problems_.size(); ++i) {
614 base::DictionaryValue* entry = new base::DictionaryValue();
615 entry->SetString("url", problems_[i].first);
616 entry->SetInteger("error", problems_[i].second);
617 if (IsDictionaryProblem(problems_[i].second)) {
618 dict_problems_list->Append(entry);
619 } else {
620 usage_problems_list->Append(entry);
621 }
622 }
623 value->Set("dict_errors", dict_problems_list);
624 value->Set("usage_errors", usage_problems_list);
625
626 return value;
627 }
628
540 //------------------------------------------------------------------------------ 629 //------------------------------------------------------------------------------
541 // Methods for supporting latency experiments. 630 // Methods for supporting latency experiments.
542 631
543 bool SdchManager::AllowLatencyExperiment(const GURL& url) const { 632 bool SdchManager::AllowLatencyExperiment(const GURL& url) const {
544 DCHECK(CalledOnValidThread()); 633 DCHECK(CalledOnValidThread());
545 return allow_latency_experiment_.end() != 634 return allow_latency_experiment_.end() !=
546 allow_latency_experiment_.find(url.host()); 635 allow_latency_experiment_.find(url.host());
547 } 636 }
548 637
549 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { 638 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) {
550 DCHECK(CalledOnValidThread()); 639 DCHECK(CalledOnValidThread());
551 if (enable) { 640 if (enable) {
552 allow_latency_experiment_.insert(url.host()); 641 allow_latency_experiment_.insert(url.host());
553 return; 642 return;
554 } 643 }
555 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host()); 644 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host());
556 if (allow_latency_experiment_.end() == it) 645 if (allow_latency_experiment_.end() == it)
557 return; // It was already erased, or never allowed. 646 return; // It was already erased, or never allowed.
558 SdchErrorRecovery(LATENCY_TEST_DISALLOWED); 647 SdchErrorRecovery(LATENCY_TEST_DISALLOWED, url);
559 allow_latency_experiment_.erase(it); 648 allow_latency_experiment_.erase(it);
560 } 649 }
561 650
562 // static 651 // static
563 void SdchManager::UrlSafeBase64Encode(const std::string& input, 652 void SdchManager::UrlSafeBase64Encode(const std::string& input,
564 std::string* output) { 653 std::string* output) {
565 // Since this is only done during a dictionary load, and hashes are only 8 654 // Since this is only done during a dictionary load, and hashes are only 8
566 // characters, we just do the simple fixup, rather than rewriting the encoder. 655 // characters, we just do the simple fixup, rather than rewriting the encoder.
567 base::Base64Encode(input, output); 656 base::Base64Encode(input, output);
568 for (size_t i = 0; i < output->size(); ++i) { 657 for (size_t i = 0; i < output->size(); ++i) {
569 switch (output->data()[i]) { 658 switch (output->data()[i]) {
570 case '+': 659 case '+':
571 (*output)[i] = '-'; 660 (*output)[i] = '-';
572 continue; 661 continue;
573 case '/': 662 case '/':
574 (*output)[i] = '_'; 663 (*output)[i] = '_';
575 continue; 664 continue;
576 default: 665 default:
577 continue; 666 continue;
578 } 667 }
579 } 668 }
580 } 669 }
581 670
582 } // namespace net 671 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698