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

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: Create Dictionary JSON directly in SdchManager::SdchInfoToValue 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
18 //------------------------------------------------------------------------------ 19 //------------------------------------------------------------------------------
19 // static 20 // static
20 21
21 // Adjust SDCH limits downwards for mobile. 22 // Adjust SDCH limits downwards for mobile.
(...skipping 27 matching lines...) Expand all
49 url_(gurl), 50 url_(gurl),
50 domain_(domain), 51 domain_(domain),
51 path_(path), 52 path_(path),
52 expiration_(expiration), 53 expiration_(expiration),
53 ports_(ports) { 54 ports_(ports) {
54 } 55 }
55 56
56 SdchManager::Dictionary::~Dictionary() { 57 SdchManager::Dictionary::~Dictionary() {
57 } 58 }
58 59
59 bool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) { 60 bool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) const {
60 /* The specific rules of when a dictionary should be advertised in an 61 /* The specific rules of when a dictionary should be advertised in an
61 Avail-Dictionary header are modeled after the rules for cookie scoping. The 62 Avail-Dictionary header are modeled after the rules for cookie scoping. The
62 terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A 63 terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A
63 dictionary may be advertised in the Avail-Dictionaries header exactly when 64 dictionary may be advertised in the Avail-Dictionaries header exactly when
64 all of the following are true: 65 all of the following are true:
65 1. The server's effective host name domain-matches the Domain attribute of 66 1. The server's effective host name domain-matches the Domain attribute of
66 the dictionary. 67 the dictionary.
67 2. If the dictionary has a Port attribute, the request port is one of the 68 2. If the dictionary has a Port attribute, the request port is one of the
68 ports listed in the Port attribute. 69 ports listed in the Port attribute.
69 3. The request URI path-matches the path header of the dictionary. 70 3. The request URI path-matches the path header of the dictionary.
(...skipping 14 matching lines...) Expand all
84 return false; 85 return false;
85 if (base::Time::Now() > expiration_) 86 if (base::Time::Now() > expiration_)
86 return false; 87 return false;
87 return true; 88 return true;
88 } 89 }
89 90
90 //------------------------------------------------------------------------------ 91 //------------------------------------------------------------------------------
91 // Security functions restricting loads and use of dictionaries. 92 // Security functions restricting loads and use of dictionaries.
92 93
93 // static 94 // static
94 bool SdchManager::Dictionary::CanSet(const std::string& domain, 95 SdchManager::ProblemCodes SdchManager::Dictionary::CanSet(
95 const std::string& path, 96 const std::string& domain,
96 const std::set<int>& ports, 97 const std::string& path,
97 const GURL& dictionary_url) { 98 const std::set<int>& ports,
99 const GURL& dictionary_url) {
98 /* 100 /*
99 A dictionary is invalid and must not be stored if any of the following are 101 A dictionary is invalid and must not be stored if any of the following are
100 true: 102 true:
101 1. The dictionary has no Domain attribute. 103 1. The dictionary has no Domain attribute.
102 2. The effective host name that derives from the referer URL host name does 104 2. The effective host name that derives from the referer URL host name does
103 not domain-match the Domain attribute. 105 not domain-match the Domain attribute.
104 3. The Domain attribute is a top level domain. 106 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 107 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 108 form HD, where D is the value of the Domain attribute, and H is a string
107 that contains one or more dots. 109 that contains one or more dots.
108 5. If the dictionary has a Port attribute and the referer URL's port was not 110 5. If the dictionary has a Port attribute and the referer URL's port was not
109 in the list. 111 in the list.
110 */ 112 */
111 113
112 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic, 114 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic,
113 // and hence the conservative approach is to not allow any redirects (if there 115 // 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). 116 // were any... then don't allow the dictionary to be set).
115 117
116 if (domain.empty()) { 118 if (domain.empty())
117 SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER); 119 return DICTIONARY_MISSING_DOMAIN_SPECIFIER; // Domain is required.
118 return false; // Domain is required. 120
119 }
120 if (registry_controlled_domains::GetDomainAndRegistry( 121 if (registry_controlled_domains::GetDomainAndRegistry(
121 domain, 122 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)
122 registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES).empty()) { 123 .empty())
123 SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN); 124 return DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN; // domain was a TLD.
124 return false; // domain was a TLD. 125
125 } 126 if (!Dictionary::DomainMatch(dictionary_url, domain))
126 if (!Dictionary::DomainMatch(dictionary_url, domain)) { 127 return DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL;
127 SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL);
128 return false;
129 }
130 128
131 std::string referrer_url_host = dictionary_url.host(); 129 std::string referrer_url_host = dictionary_url.host();
132 size_t postfix_domain_index = referrer_url_host.rfind(domain); 130 size_t postfix_domain_index = referrer_url_host.rfind(domain);
133 // See if it is indeed a postfix, or just an internal string. 131 // See if it is indeed a postfix, or just an internal string.
134 if (referrer_url_host.size() == postfix_domain_index + domain.size()) { 132 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. 133 // 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('.'); 134 size_t end_of_host_index = referrer_url_host.find_first_of('.');
137 if (referrer_url_host.npos != end_of_host_index && 135 if (referrer_url_host.npos != end_of_host_index &&
138 end_of_host_index < postfix_domain_index) { 136 end_of_host_index < postfix_domain_index)
139 SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX); 137 return DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX;
140 return false;
141 }
142 } 138 }
143 139
144 if (!ports.empty() 140 if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort()))
145 && 0 == ports.count(dictionary_url.EffectiveIntPort())) { 141 return DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL;
146 SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); 142
147 return false; 143 return PROBLEM_CODE_OK;
148 }
149 return true;
150 } 144 }
151 145
152 // static 146 SdchManager::ProblemCodes SdchManager::Dictionary::CanUse(
153 bool SdchManager::Dictionary::CanUse(const GURL& referring_url) { 147 const GURL& referring_url) const {
154 /* 148 /*
155 1. The request URL's host name domain-matches the Domain attribute of the 149 1. The request URL's host name domain-matches the Domain attribute of the
156 dictionary. 150 dictionary.
157 2. If the dictionary has a Port attribute, the request port is one of the 151 2. If the dictionary has a Port attribute, the request port is one of the
158 ports listed in the Port attribute. 152 ports listed in the Port attribute.
159 3. The request URL path-matches the path attribute of the dictionary. 153 3. The request URL path-matches the path attribute of the dictionary.
160 4. The request is not an HTTPS request. 154 4. The request is not an HTTPS request.
161 We can override (ignore) item (4) only when we have explicitly enabled 155 We can override (ignore) item (4) only when we have explicitly enabled
162 HTTPS support AND the dictionary acquisition scheme matches the target 156 HTTPS support AND the dictionary acquisition scheme matches the target
163 url scheme. 157 url scheme.
164 */ 158 */
165 if (!DomainMatch(referring_url, domain_)) { 159 if (!DomainMatch(referring_url, domain_))
166 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN); 160 return DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
167 return false; 161
168 } 162 if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort()))
169 if (!ports_.empty() 163 return DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
170 && 0 == ports_.count(referring_url.EffectiveIntPort())) { 164
171 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST); 165 if (path_.size() && !PathMatch(referring_url.path(), path_))
172 return false; 166 return DICTIONARY_FOUND_HAS_WRONG_PATH;
173 } 167
174 if (path_.size() && !PathMatch(referring_url.path(), path_)) { 168 if (!SdchManager::secure_scheme_supported() && referring_url.SchemeIsSecure())
175 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH); 169 return DICTIONARY_FOUND_HAS_WRONG_SCHEME;
176 return false; 170
177 } 171 if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure())
178 if (!SdchManager::secure_scheme_supported() && 172 return DICTIONARY_FOUND_HAS_WRONG_SCHEME;
179 referring_url.SchemeIsSecure()) {
180 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
181 return false;
182 }
183 if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) {
184 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
185 return false;
186 }
187 173
188 // TODO(jar): Remove overly restrictive failsafe test (added per security 174 // TODO(jar): Remove overly restrictive failsafe test (added per security
189 // review) when we have a need to be more general. 175 // review) when we have a need to be more general.
190 if (!referring_url.SchemeIsHTTPOrHTTPS()) { 176 if (!referring_url.SchemeIsHTTPOrHTTPS())
191 SdchErrorRecovery(ATTEMPT_TO_DECODE_NON_HTTP_DATA); 177 return ATTEMPT_TO_DECODE_NON_HTTP_DATA;
192 return false;
193 }
194 178
195 return true; 179 return PROBLEM_CODE_OK;
196 } 180 }
197 181
182 // static
198 bool SdchManager::Dictionary::PathMatch(const std::string& path, 183 bool SdchManager::Dictionary::PathMatch(const std::string& path,
199 const std::string& restriction) { 184 const std::string& restriction) {
200 /* Must be either: 185 /* Must be either:
201 1. P2 is equal to P1 186 1. P2 is equal to P1
202 2. P2 is a prefix of P1 and either the final character in P2 is "/" or the 187 2. P2 is a prefix of P1 and either the final character in P2 is "/" or the
203 character following P2 in P1 is "/". 188 character following P2 in P1 is "/".
204 */ 189 */
205 if (path == restriction) 190 if (path == restriction)
206 return true; 191 return true;
207 size_t prefix_length = restriction.size(); 192 size_t prefix_length = restriction.size();
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 293
309 int SdchManager::BlacklistDomainExponential(const std::string& domain) { 294 int SdchManager::BlacklistDomainExponential(const std::string& domain) {
310 if (exponential_blacklist_count_.end() == 295 if (exponential_blacklist_count_.end() ==
311 exponential_blacklist_count_.find(domain)) 296 exponential_blacklist_count_.find(domain))
312 return 0; 297 return 0;
313 return exponential_blacklist_count_[base::StringToLowerASCII(domain)]; 298 return exponential_blacklist_count_[base::StringToLowerASCII(domain)];
314 } 299 }
315 300
316 bool SdchManager::IsInSupportedDomain(const GURL& url) { 301 bool SdchManager::IsInSupportedDomain(const GURL& url) {
317 DCHECK(CalledOnValidThread()); 302 DCHECK(CalledOnValidThread());
303 if (!IsSdchEnabledForUrl(url))
304 return false;
305
306 if (IsInBlacklistedDomain(url)) {
307 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET);
308 return false;
309 }
310 return true;
311 }
312
313 // static
314 bool SdchManager::IsSdchEnabledForUrl(const GURL& url) {
318 if (!g_sdch_enabled_ ) 315 if (!g_sdch_enabled_ )
319 return false; 316 return false;
320 317
321 if (!secure_scheme_supported() && url.SchemeIsSecure()) 318 if (!secure_scheme_supported() && url.SchemeIsSecure())
322 return false; 319 return false;
323 320
321 return true;
322 }
323
324 bool SdchManager::IsInBlacklistedDomain(const GURL& url) {
324 if (blacklisted_domains_.empty()) 325 if (blacklisted_domains_.empty())
325 return true; 326 return false;
326 327
327 std::string domain(base::StringToLowerASCII(url.host())); 328 std::string domain(base::StringToLowerASCII(url.host()));
328 DomainCounter::iterator it = blacklisted_domains_.find(domain); 329 DomainCounter::iterator it = blacklisted_domains_.find(domain);
329 if (blacklisted_domains_.end() == it) 330 if (blacklisted_domains_.end() == it)
330 return true; 331 return false;
331 332
332 int count = it->second - 1; 333 int count = it->second - 1;
333 if (count > 0) 334 if (count > 0)
334 blacklisted_domains_[domain] = count; 335 blacklisted_domains_[domain] = count;
335 else 336 else
336 blacklisted_domains_.erase(domain); 337 blacklisted_domains_.erase(domain);
337 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET); 338
338 return false; 339 return true;
339 } 340 }
340 341
341 void SdchManager::FetchDictionary(const GURL& request_url, 342 SdchManager::ProblemCodes SdchManager::FetchDictionary(
342 const GURL& dictionary_url) { 343 const GURL& request_url,
344 const GURL& dictionary_url) {
343 DCHECK(CalledOnValidThread()); 345 DCHECK(CalledOnValidThread());
344 if (CanFetchDictionary(request_url, dictionary_url) && fetcher_.get()) 346 ProblemCodes rv = CanFetchDictionary(request_url, dictionary_url);
347 if (rv != PROBLEM_CODE_OK)
348 return rv;
349
350 if (fetcher_.get())
345 fetcher_->Schedule(dictionary_url); 351 fetcher_->Schedule(dictionary_url);
352
353 return PROBLEM_CODE_OK;
346 } 354 }
347 355
348 bool SdchManager::CanFetchDictionary(const GURL& referring_url, 356 SdchManager::ProblemCodes SdchManager::CanFetchDictionary(
349 const GURL& dictionary_url) const { 357 const GURL& referring_url,
358 const GURL& dictionary_url) const {
350 DCHECK(CalledOnValidThread()); 359 DCHECK(CalledOnValidThread());
351 /* The user agent may retrieve a dictionary from the dictionary URL if all of 360 /* The user agent may retrieve a dictionary from the dictionary URL if all of
352 the following are true: 361 the following are true:
353 1 The dictionary URL host name matches the referrer URL host name and 362 1 The dictionary URL host name matches the referrer URL host name and
354 scheme. 363 scheme.
355 2 The dictionary URL host name domain matches the parent domain of the 364 2 The dictionary URL host name domain matches the parent domain of the
356 referrer URL host name 365 referrer URL host name
357 3 The parent domain of the referrer URL host name is not a top level 366 3 The parent domain of the referrer URL host name is not a top level
358 domain 367 domain
359 4 The dictionary URL is not an HTTPS URL. 368 4 The dictionary URL is not an HTTPS URL.
360 */ 369 */
361 // Item (1) above implies item (2). Spec should be updated. 370 // Item (1) above implies item (2). Spec should be updated.
362 // I take "host name match" to be "is identical to" 371 // I take "host name match" to be "is identical to"
363 if (referring_url.host() != dictionary_url.host() || 372 if (referring_url.host() != dictionary_url.host() ||
364 referring_url.scheme() != dictionary_url.scheme()) { 373 referring_url.scheme() != dictionary_url.scheme())
365 SdchErrorRecovery(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST); 374 return DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST;
366 return false; 375
367 } 376 if (!secure_scheme_supported() && referring_url.SchemeIsSecure())
368 if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) { 377 return DICTIONARY_SELECTED_FOR_SSL;
369 SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL); 378
379 // TODO(jar): Remove this failsafe conservative hack which is more restrictive
380 // than current SDCH spec when needed, and justified by security audit.
381 if (!referring_url.SchemeIsHTTPOrHTTPS())
382 return DICTIONARY_SELECTED_FROM_NON_HTTP;
383
384 return PROBLEM_CODE_OK;
385 }
386
387 bool SdchManager::AddSdchDictionary(const std::string& dictionary_text,
388 const GURL& dictionary_url,
389 ProblemCodes* problem) {
390 DCHECK(CalledOnValidThread());
391 DCHECK(problem);
392 std::string client_hash;
393 std::string server_hash;
394 GenerateHash(dictionary_text, &client_hash, &server_hash);
395 *problem = PROBLEM_CODE_OK;
396 if (dictionaries_.find(server_hash) != dictionaries_.end()) {
397 *problem = DICTIONARY_ALREADY_LOADED; // Already loaded.
370 return false; 398 return false;
371 } 399 }
372 400
373 // TODO(jar): Remove this failsafe conservative hack which is more restrictive
374 // than current SDCH spec when needed, and justified by security audit.
375 if (!referring_url.SchemeIsHTTPOrHTTPS()) {
376 SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP);
377 return false;
378 }
379
380 return true;
381 }
382
383 bool SdchManager::AddSdchDictionary(const std::string& dictionary_text,
384 const GURL& dictionary_url) {
385 DCHECK(CalledOnValidThread());
386 std::string client_hash;
387 std::string server_hash;
388 GenerateHash(dictionary_text, &client_hash, &server_hash);
389 if (dictionaries_.find(server_hash) != dictionaries_.end()) {
390 SdchErrorRecovery(DICTIONARY_ALREADY_LOADED);
391 return false; // Already loaded.
392 }
393
394 std::string domain, path; 401 std::string domain, path;
395 std::set<int> ports; 402 std::set<int> ports;
396 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); 403 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30));
397 404
398 if (dictionary_text.empty()) { 405 if (dictionary_text.empty()) {
399 SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT); 406 *problem = DICTIONARY_HAS_NO_TEXT; // Empty response.
400 return false; // Missing header. 407 return false;
401 } 408 }
402 409
403 size_t header_end = dictionary_text.find("\n\n"); 410 size_t header_end = dictionary_text.find("\n\n");
404 if (std::string::npos == header_end) { 411 if (std::string::npos == header_end) {
405 SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER); 412 *problem = DICTIONARY_HAS_NO_HEADER; // Missing header.
406 return false; // Missing header. 413 return false;
407 } 414 }
415
408 size_t line_start = 0; // Start of line being parsed. 416 size_t line_start = 0; // Start of line being parsed.
409 while (1) { 417 while (1) {
410 size_t line_end = dictionary_text.find('\n', line_start); 418 size_t line_end = dictionary_text.find('\n', line_start);
411 DCHECK(std::string::npos != line_end); 419 DCHECK(std::string::npos != line_end);
412 DCHECK_LE(line_end, header_end); 420 DCHECK_LE(line_end, header_end);
413 421
414 size_t colon_index = dictionary_text.find(':', line_start); 422 size_t colon_index = dictionary_text.find(':', line_start);
415 if (std::string::npos == colon_index) { 423 if (std::string::npos == colon_index) {
416 SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON); 424 // Illegal line missing a colon.
417 return false; // Illegal line missing a colon. 425 *problem = DICTIONARY_HEADER_LINE_MISSING_COLON;
426 return false;
418 } 427 }
419 428
420 if (colon_index > line_end) 429 if (colon_index > line_end)
421 break; 430 break;
422 431
423 size_t value_start = dictionary_text.find_first_not_of(" \t", 432 size_t value_start = dictionary_text.find_first_not_of(" \t",
424 colon_index + 1); 433 colon_index + 1);
425 if (std::string::npos != value_start) { 434 if (std::string::npos != value_start) {
426 if (value_start >= line_end) 435 if (value_start >= line_end)
427 break; 436 break;
428 std::string name(dictionary_text, line_start, colon_index - line_start); 437 std::string name(dictionary_text, line_start, colon_index - line_start);
429 std::string value(dictionary_text, value_start, line_end - value_start); 438 std::string value(dictionary_text, value_start, line_end - value_start);
430 name = base::StringToLowerASCII(name); 439 name = base::StringToLowerASCII(name);
431 if (name == "domain") { 440 if (name == "domain") {
432 domain = value; 441 domain = value;
433 } else if (name == "path") { 442 } else if (name == "path") {
434 path = value; 443 path = value;
435 } else if (name == "format-version") { 444 } else if (name == "format-version") {
436 if (value != "1.0") 445 if (value != "1.0") {
437 return false; 446 return false;
447 }
Randy Smith (Not in Mondays) 2014/08/13 17:35:45 The extra braces aren't necessary by the chrome st
baranovich 2014/08/13 19:13:48 Done.
438 } else if (name == "max-age") { 448 } else if (name == "max-age") {
439 int64 seconds; 449 int64 seconds;
440 base::StringToInt64(value, &seconds); 450 base::StringToInt64(value, &seconds);
441 expiration = base::Time::Now() + base::TimeDelta::FromSeconds(seconds); 451 expiration = base::Time::Now() + base::TimeDelta::FromSeconds(seconds);
442 } else if (name == "port") { 452 } else if (name == "port") {
443 int port; 453 int port;
444 base::StringToInt(value, &port); 454 base::StringToInt(value, &port);
445 if (port >= 0) 455 if (port >= 0)
446 ports.insert(port); 456 ports.insert(port);
447 } 457 }
448 } 458 }
449 459
450 if (line_end >= header_end) 460 if (line_end >= header_end)
451 break; 461 break;
452 line_start = line_end + 1; 462 line_start = line_end + 1;
453 } 463 }
454 464
455 if (!IsInSupportedDomain(dictionary_url)) 465 if (!IsSdchEnabledForUrl(dictionary_url))
456 return false; 466 return false;
457 467
458 if (!Dictionary::CanSet(domain, path, ports, dictionary_url)) 468 if (IsInBlacklistedDomain(dictionary_url)) {
469 *problem = DOMAIN_BLACKLIST_INCLUDES_TARGET;
459 return false; 470 return false;
471 }
472
473 ProblemCodes err = Dictionary::CanSet(domain, path, ports, dictionary_url);
474 if (err != PROBLEM_CODE_OK) {
475 *problem = err;
476 return false;
477 }
460 478
461 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of 479 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of
462 // useless dictionaries. We should probably have a cache eviction plan, 480 // useless dictionaries. We should probably have a cache eviction plan,
463 // instead of just blocking additions. For now, with the spec in flux, it 481 // instead of just blocking additions. For now, with the spec in flux, it
464 // is probably not worth doing eviction handling. 482 // is probably not worth doing eviction handling.
465 if (kMaxDictionarySize < dictionary_text.size()) { 483 if (kMaxDictionarySize < dictionary_text.size()) {
466 SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE); 484 *problem = DICTIONARY_IS_TOO_LARGE;
467 return false; 485 return false;
468 } 486 }
469 if (kMaxDictionaryCount <= dictionaries_.size()) { 487 if (kMaxDictionaryCount <= dictionaries_.size()) {
470 SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED); 488 *problem = DICTIONARY_COUNT_EXCEEDED;
471 return false; 489 return false;
472 } 490 }
473 491
474 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); 492 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
475 DVLOG(1) << "Loaded dictionary with client hash " << client_hash 493 DVLOG(1) << "Loaded dictionary with client hash " << client_hash
476 << " and server hash " << server_hash; 494 << " and server hash " << server_hash;
477 Dictionary* dictionary = 495 Dictionary* dictionary =
478 new Dictionary(dictionary_text, header_end + 2, client_hash, 496 new Dictionary(dictionary_text, header_end + 2, client_hash,
479 dictionary_url, domain, path, expiration, ports); 497 dictionary_url, domain, path, expiration, ports);
480 dictionaries_[server_hash] = dictionary; 498 dictionaries_[server_hash] = dictionary;
499
481 return true; 500 return true;
482 } 501 }
483 502
484 void SdchManager::GetVcdiffDictionary( 503 SdchManager::ProblemCodes SdchManager::GetVcdiffDictionary(
485 const std::string& server_hash, 504 const std::string& server_hash,
486 const GURL& referring_url, 505 const GURL& referring_url,
487 scoped_refptr<Dictionary>* dictionary) { 506 scoped_refptr<Dictionary>* dictionary) {
488 DCHECK(CalledOnValidThread()); 507 DCHECK(CalledOnValidThread());
489 *dictionary = NULL; 508 *dictionary = NULL;
490 DictionaryMap::iterator it = dictionaries_.find(server_hash); 509 DictionaryMap::iterator it = dictionaries_.find(server_hash);
491 if (it == dictionaries_.end()) { 510 if (it == dictionaries_.end())
492 return; 511 return PROBLEM_CODE_OK; // not a problem. Just no dictionary.
493 } 512
494 scoped_refptr<Dictionary> matching_dictionary = it->second; 513 scoped_refptr<Dictionary> matching_dictionary = it->second;
495 if (!IsInSupportedDomain(referring_url)) 514 if (!IsSdchEnabledForUrl(referring_url))
496 return; 515 return PROBLEM_CODE_OK; // not a problem. SDCH is disabled.
Randy Smith (Not in Mondays) 2014/08/13 17:35:45 Hmmm. Wouldn't we want to see this in net-interna
baranovich 2014/08/13 19:13:48 Then we need some new enum values (smth like SDCH_
497 if (!matching_dictionary->CanUse(referring_url)) 516
498 return; 517 if (IsInBlacklistedDomain(referring_url))
499 *dictionary = matching_dictionary; 518 return DOMAIN_BLACKLIST_INCLUDES_TARGET;
519
520 ProblemCodes rv = matching_dictionary->CanUse(referring_url);
521 if (rv == PROBLEM_CODE_OK)
522 *dictionary = matching_dictionary;
523 return rv;
500 } 524 }
501 525
502 // TODO(jar): If we have evictions from the dictionaries_, then we need to 526 // 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 527 // change this interface to return a list of reference counted Dictionary
504 // instances that can be used if/when a server specifies one. 528 // instances that can be used if/when a server specifies one.
505 void SdchManager::GetAvailDictionaryList(const GURL& target_url, 529 void SdchManager::GetAvailDictionaryList(const GURL& target_url,
506 std::string* list) { 530 std::string* list) {
507 DCHECK(CalledOnValidThread()); 531 DCHECK(CalledOnValidThread());
508 int count = 0; 532 int count = 0;
509 for (DictionaryMap::iterator it = dictionaries_.begin(); 533 for (DictionaryMap::iterator it = dictionaries_.begin();
510 it != dictionaries_.end(); ++it) { 534 it != dictionaries_.end(); ++it) {
511 if (!IsInSupportedDomain(target_url)) 535 if (!IsInSupportedDomain(target_url)) {
Randy Smith (Not in Mondays) 2014/08/13 17:35:45 I think it makes sense to avoid unnecessary change
baranovich 2014/08/13 19:13:48 Done.
512 continue; 536 continue;
537 }
513 if (!it->second->CanAdvertise(target_url)) 538 if (!it->second->CanAdvertise(target_url))
514 continue; 539 continue;
515 ++count; 540 ++count;
516 if (!list->empty()) 541 if (!list->empty())
517 list->append(","); 542 list->append(",");
518 list->append(it->second->client_hash()); 543 list->append(it->second->client_hash());
519 } 544 }
520 // Watch to see if we have corrupt or numerous dictionaries. 545 // Watch to see if we have corrupt or numerous dictionaries.
521 if (count > 0) 546 if (count > 0)
522 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); 547 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count);
523 } 548 }
524 549
525 // static 550 // static
526 void SdchManager::GenerateHash(const std::string& dictionary_text, 551 void SdchManager::GenerateHash(const std::string& dictionary_text,
527 std::string* client_hash, std::string* server_hash) { 552 std::string* client_hash, std::string* server_hash) {
528 char binary_hash[32]; 553 char binary_hash[32];
529 crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash)); 554 crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash));
530 555
531 std::string first_48_bits(&binary_hash[0], 6); 556 std::string first_48_bits(&binary_hash[0], 6);
532 std::string second_48_bits(&binary_hash[6], 6); 557 std::string second_48_bits(&binary_hash[6], 6);
533 UrlSafeBase64Encode(first_48_bits, client_hash); 558 UrlSafeBase64Encode(first_48_bits, client_hash);
534 UrlSafeBase64Encode(second_48_bits, server_hash); 559 UrlSafeBase64Encode(second_48_bits, server_hash);
535 560
536 DCHECK_EQ(server_hash->length(), 8u); 561 DCHECK_EQ(server_hash->length(), 8u);
537 DCHECK_EQ(client_hash->length(), 8u); 562 DCHECK_EQ(client_hash->length(), 8u);
538 } 563 }
539 564
565 base::Value* SdchManager::SdchInfoToValue() const {
566 base::DictionaryValue* value = new base::DictionaryValue();
567
568 value->SetBoolean("sdch_enabled", sdch_enabled());
569 value->SetBoolean("secure_scheme_support", secure_scheme_supported());
570
571 base::ListValue* entry_list = new base::ListValue();
572 for (DictionaryMap::const_iterator it = dictionaries_.begin();
573 it != dictionaries_.end();
574 ++it) {
575 base::DictionaryValue* entry_dict = new base::DictionaryValue();
576 entry_dict->SetString("url", it->second->url().spec());
577 entry_dict->SetString("client_hash", it->second->client_hash());
578 entry_dict->SetString("domain", it->second->domain());
579 entry_dict->SetString("path", it->second->path());
580 entry_dict->SetString("expiration",
581 base::Int64ToString(it->second->expiration().ToInternalValue()));
582 base::ListValue* port_list = new base::ListValue();
583 for (std::set<int>::const_iterator port_it = it->second->ports().begin();
584 port_it != it->second->ports().end(); ++port_it) {
585 port_list->AppendInteger(*port_it);
586 }
587 entry_dict->Set("ports", port_list);
588 entry_dict->SetString("server_hash", it->first);
589 entry_list->Append(entry_dict);
590 }
591 value->Set("dictionaries", entry_list);
592
593 entry_list = new base::ListValue();
594 for (DomainCounter::const_iterator it = blacklisted_domains_.begin();
595 it != blacklisted_domains_.end();
596 ++it) {
597 base::DictionaryValue* entry_dict = new base::DictionaryValue();
598 entry_dict->SetString("domain", it->first);
599 if (it->second != INT_MAX)
600 entry_dict->SetInteger("tries", it->second);
601 entry_list->Append(entry_dict);
602 }
603 value->Set("blacklisted", entry_list);
604
605 return value;
606 }
607
540 //------------------------------------------------------------------------------ 608 //------------------------------------------------------------------------------
541 // Methods for supporting latency experiments. 609 // Methods for supporting latency experiments.
542 610
543 bool SdchManager::AllowLatencyExperiment(const GURL& url) const { 611 bool SdchManager::AllowLatencyExperiment(const GURL& url) const {
544 DCHECK(CalledOnValidThread()); 612 DCHECK(CalledOnValidThread());
545 return allow_latency_experiment_.end() != 613 return allow_latency_experiment_.end() !=
546 allow_latency_experiment_.find(url.host()); 614 allow_latency_experiment_.find(url.host());
547 } 615 }
548 616
549 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { 617 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) {
550 DCHECK(CalledOnValidThread()); 618 DCHECK(CalledOnValidThread());
551 if (enable) { 619 if (enable) {
552 allow_latency_experiment_.insert(url.host()); 620 allow_latency_experiment_.insert(url.host());
553 return; 621 return;
554 } 622 }
555 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host()); 623 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host());
556 if (allow_latency_experiment_.end() == it) 624 if (allow_latency_experiment_.end() == it)
557 return; // It was already erased, or never allowed. 625 return; // It was already erased, or never allowed.
626
627 // Do not send error up. It's internal stuff, I guess.
Randy Smith (Not in Mondays) 2014/08/13 17:35:45 "I guess" doesn't seem like the right phrasing for
baranovich 2014/08/13 19:13:47 Done.
558 SdchErrorRecovery(LATENCY_TEST_DISALLOWED); 628 SdchErrorRecovery(LATENCY_TEST_DISALLOWED);
559 allow_latency_experiment_.erase(it); 629 allow_latency_experiment_.erase(it);
560 } 630 }
561 631
562 // static 632 // static
563 void SdchManager::UrlSafeBase64Encode(const std::string& input, 633 void SdchManager::UrlSafeBase64Encode(const std::string& input,
564 std::string* output) { 634 std::string* output) {
565 // Since this is only done during a dictionary load, and hashes are only 8 635 // 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. 636 // characters, we just do the simple fixup, rather than rewriting the encoder.
567 base::Base64Encode(input, output); 637 base::Base64Encode(input, output);
568 for (size_t i = 0; i < output->size(); ++i) { 638 for (size_t i = 0; i < output->size(); ++i) {
569 switch (output->data()[i]) { 639 switch (output->data()[i]) {
570 case '+': 640 case '+':
571 (*output)[i] = '-'; 641 (*output)[i] = '-';
572 continue; 642 continue;
573 case '/': 643 case '/':
574 (*output)[i] = '_'; 644 (*output)[i] = '_';
575 continue; 645 continue;
576 default: 646 default:
577 continue; 647 continue;
578 } 648 }
579 } 649 }
580 } 650 }
581 651
582 } // namespace net 652 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698