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

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

Powered by Google App Engine
This is Rietveld 408576698