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

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: Remove unnecessary include Created 6 years, 1 month 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 { 17 namespace {
17 18
18 void StripTrailingDot(GURL* gurl) { 19 void StripTrailingDot(GURL* gurl) {
19 std::string host(gurl->host()); 20 std::string host(gurl->host());
20 21
21 if (host.empty()) 22 if (host.empty())
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 url_(gurl), 76 url_(gurl),
76 domain_(domain), 77 domain_(domain),
77 path_(path), 78 path_(path),
78 expiration_(expiration), 79 expiration_(expiration),
79 ports_(ports) { 80 ports_(ports) {
80 } 81 }
81 82
82 SdchManager::Dictionary::~Dictionary() { 83 SdchManager::Dictionary::~Dictionary() {
83 } 84 }
84 85
85 bool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) { 86 SdchProblemCode SdchManager::Dictionary::CanAdvertise(
87 const GURL& target_url) const {
86 /* The specific rules of when a dictionary should be advertised in an 88 /* The specific rules of when a dictionary should be advertised in an
87 Avail-Dictionary header are modeled after the rules for cookie scoping. The 89 Avail-Dictionary header are modeled after the rules for cookie scoping. The
88 terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A 90 terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A
89 dictionary may be advertised in the Avail-Dictionaries header exactly when 91 dictionary may be advertised in the Avail-Dictionaries header exactly when
90 all of the following are true: 92 all of the following are true:
91 1. The server's effective host name domain-matches the Domain attribute of 93 1. The server's effective host name domain-matches the Domain attribute of
92 the dictionary. 94 the dictionary.
93 2. If the dictionary has a Port attribute, the request port is one of the 95 2. If the dictionary has a Port attribute, the request port is one of the
94 ports listed in the Port attribute. 96 ports listed in the Port attribute.
95 3. The request URI path-matches the path header of the dictionary. 97 3. The request URI path-matches the path header of the dictionary.
96 4. The request is not an HTTPS request. 98 4. The request is not an HTTPS request.
97 We can override (ignore) item (4) only when we have explicitly enabled 99 We can override (ignore) item (4) only when we have explicitly enabled
98 HTTPS support AND the dictionary acquisition scheme matches the target 100 HTTPS support AND the dictionary acquisition scheme matches the target
99 url scheme. 101 url scheme.
100 */ 102 */
101 if (!DomainMatch(target_url, domain_)) 103 if (!DomainMatch(target_url, domain_))
102 return false; 104 return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
103 if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort())) 105 if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort()))
104 return false; 106 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
105 if (path_.size() && !PathMatch(target_url.path(), path_)) 107 if (path_.size() && !PathMatch(target_url.path(), path_))
106 return false; 108 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
107 if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure()) 109 if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
108 return false; 110 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
109 if (target_url.SchemeIsSecure() != url_.SchemeIsSecure()) 111 if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
110 return false; 112 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
111 if (base::Time::Now() > expiration_) 113 if (base::Time::Now() > expiration_)
112 return false; 114 return SDCH_DICTIONARY_FOUND_EXPIRED;
113 return true; 115 return SDCH_OK;
114 } 116 }
115 117
116 //------------------------------------------------------------------------------ 118 //------------------------------------------------------------------------------
117 // Security functions restricting loads and use of dictionaries. 119 // Security functions restricting loads and use of dictionaries.
118 120
119 // static 121 // static
120 bool SdchManager::Dictionary::CanSet(const std::string& domain, 122 SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain,
121 const std::string& path, 123 const std::string& path,
122 const std::set<int>& ports, 124 const std::set<int>& ports,
123 const GURL& dictionary_url) { 125 const GURL& dictionary_url) {
124 /* 126 /*
125 A dictionary is invalid and must not be stored if any of the following are 127 A dictionary is invalid and must not be stored if any of the following are
126 true: 128 true:
127 1. The dictionary has no Domain attribute. 129 1. The dictionary has no Domain attribute.
128 2. The effective host name that derives from the referer URL host name does 130 2. The effective host name that derives from the referer URL host name does
129 not domain-match the Domain attribute. 131 not domain-match the Domain attribute.
130 3. The Domain attribute is a top level domain. 132 3. The Domain attribute is a top level domain.
131 4. The referer URL host is a host domain name (not IP address) and has the 133 4. The referer URL host is a host domain name (not IP address) and has the
132 form HD, where D is the value of the Domain attribute, and H is a string 134 form HD, where D is the value of the Domain attribute, and H is a string
133 that contains one or more dots. 135 that contains one or more dots.
134 5. If the dictionary has a Port attribute and the referer URL's port was not 136 5. If the dictionary has a Port attribute and the referer URL's port was not
135 in the list. 137 in the list.
136 */ 138 */
137 139
138 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic, 140 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic,
139 // and hence the conservative approach is to not allow any redirects (if there 141 // and hence the conservative approach is to not allow any redirects (if there
140 // were any... then don't allow the dictionary to be set). 142 // were any... then don't allow the dictionary to be set).
141 143
142 if (domain.empty()) { 144 if (domain.empty())
143 SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER); 145 return SDCH_DICTIONARY_MISSING_DOMAIN_SPECIFIER; // Domain is required.
144 return false; // Domain is required. 146
147 if (registry_controlled_domains::GetDomainAndRegistry(
148 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)
149 .empty()) {
150 return SDCH_DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN; // domain was a TLD.
145 } 151 }
146 if (registry_controlled_domains::GetDomainAndRegistry( 152
147 domain, 153 if (!Dictionary::DomainMatch(dictionary_url, domain))
148 registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES).empty()) { 154 return SDCH_DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL;
149 SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN);
150 return false; // domain was a TLD.
151 }
152 if (!Dictionary::DomainMatch(dictionary_url, domain)) {
153 SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL);
154 return false;
155 }
156 155
157 std::string referrer_url_host = dictionary_url.host(); 156 std::string referrer_url_host = dictionary_url.host();
158 size_t postfix_domain_index = referrer_url_host.rfind(domain); 157 size_t postfix_domain_index = referrer_url_host.rfind(domain);
159 // See if it is indeed a postfix, or just an internal string. 158 // See if it is indeed a postfix, or just an internal string.
160 if (referrer_url_host.size() == postfix_domain_index + domain.size()) { 159 if (referrer_url_host.size() == postfix_domain_index + domain.size()) {
161 // It is a postfix... so check to see if there's a dot in the prefix. 160 // It is a postfix... so check to see if there's a dot in the prefix.
162 size_t end_of_host_index = referrer_url_host.find_first_of('.'); 161 size_t end_of_host_index = referrer_url_host.find_first_of('.');
163 if (referrer_url_host.npos != end_of_host_index && 162 if (referrer_url_host.npos != end_of_host_index &&
164 end_of_host_index < postfix_domain_index) { 163 end_of_host_index < postfix_domain_index) {
165 SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX); 164 return SDCH_DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX;
166 return false;
167 } 165 }
168 } 166 }
169 167
170 if (!ports.empty() 168 if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort()))
171 && 0 == ports.count(dictionary_url.EffectiveIntPort())) { 169 return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL;
172 SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); 170
173 return false; 171 return SDCH_OK;
174 }
175 return true;
176 } 172 }
177 173
178 // static 174 SdchProblemCode SdchManager::Dictionary::CanUse(
179 bool SdchManager::Dictionary::CanUse(const GURL& referring_url) { 175 const GURL& referring_url) const {
180 /* 176 /*
181 1. The request URL's host name domain-matches the Domain attribute of the 177 1. The request URL's host name domain-matches the Domain attribute of the
182 dictionary. 178 dictionary.
183 2. If the dictionary has a Port attribute, the request port is one of the 179 2. If the dictionary has a Port attribute, the request port is one of the
184 ports listed in the Port attribute. 180 ports listed in the Port attribute.
185 3. The request URL path-matches the path attribute of the dictionary. 181 3. The request URL path-matches the path attribute of the dictionary.
186 4. The request is not an HTTPS request. 182 4. The request is not an HTTPS request.
187 We can override (ignore) item (4) only when we have explicitly enabled 183 We can override (ignore) item (4) only when we have explicitly enabled
188 HTTPS support AND the dictionary acquisition scheme matches the target 184 HTTPS support AND the dictionary acquisition scheme matches the target
189 url scheme. 185 url scheme.
190 */ 186 */
191 if (!DomainMatch(referring_url, domain_)) { 187 if (!DomainMatch(referring_url, domain_))
192 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN); 188 return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
193 return false; 189
194 } 190 if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort()))
195 if (!ports_.empty() 191 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
196 && 0 == ports_.count(referring_url.EffectiveIntPort())) { 192
197 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST); 193 if (path_.size() && !PathMatch(referring_url.path(), path_))
198 return false; 194 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
199 } 195
200 if (path_.size() && !PathMatch(referring_url.path(), path_)) { 196 if (!SdchManager::secure_scheme_supported() && referring_url.SchemeIsSecure())
201 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH); 197 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
202 return false; 198
203 } 199 if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure())
204 if (!SdchManager::secure_scheme_supported() && 200 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
205 referring_url.SchemeIsSecure()) {
206 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
207 return false;
208 }
209 if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) {
210 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
211 return false;
212 }
213 201
214 // TODO(jar): Remove overly restrictive failsafe test (added per security 202 // TODO(jar): Remove overly restrictive failsafe test (added per security
215 // review) when we have a need to be more general. 203 // review) when we have a need to be more general.
216 if (!referring_url.SchemeIsHTTPOrHTTPS()) { 204 if (!referring_url.SchemeIsHTTPOrHTTPS())
217 SdchErrorRecovery(ATTEMPT_TO_DECODE_NON_HTTP_DATA); 205 return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA;
218 return false;
219 }
220 206
221 return true; 207 return SDCH_OK;
222 } 208 }
223 209
210 // static
224 bool SdchManager::Dictionary::PathMatch(const std::string& path, 211 bool SdchManager::Dictionary::PathMatch(const std::string& path,
225 const std::string& restriction) { 212 const std::string& restriction) {
226 /* Must be either: 213 /* Must be either:
227 1. P2 is equal to P1 214 1. P2 is equal to P1
228 2. P2 is a prefix of P1 and either the final character in P2 is "/" or the 215 2. P2 is a prefix of P1 and either the final character in P2 is "/" or the
229 character following P2 in P1 is "/". 216 character following P2 in P1 is "/".
230 */ 217 */
231 if (path == restriction) 218 if (path == restriction)
232 return true; 219 return true;
233 size_t prefix_length = restriction.size(); 220 size_t prefix_length = restriction.size();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 fetcher_->Cancel(); 253 fetcher_->Cancel();
267 254
268 // Note that this may result in not having dictionaries we've advertised 255 // Note that this may result in not having dictionaries we've advertised
269 // for incoming responses. The window is relatively small (as ClearData() 256 // for incoming responses. The window is relatively small (as ClearData()
270 // is not expected to be called frequently), so we rely on meta-refresh 257 // is not expected to be called frequently), so we rely on meta-refresh
271 // to handle this case. 258 // to handle this case.
272 dictionaries_.clear(); 259 dictionaries_.clear();
273 } 260 }
274 261
275 // static 262 // static
276 void SdchManager::SdchErrorRecovery(ProblemCodes problem) { 263 void SdchManager::SdchErrorRecovery(SdchProblemCode problem) {
277 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE); 264 UMA_HISTOGRAM_ENUMERATION(
265 "Sdch3.ProblemCodes_5", problem, SDCH_MAX_PROBLEM_CODE);
278 } 266 }
279 267
280 void SdchManager::set_sdch_fetcher(scoped_ptr<SdchFetcher> fetcher) { 268 void SdchManager::set_sdch_fetcher(scoped_ptr<SdchFetcher> fetcher) {
281 DCHECK(CalledOnValidThread()); 269 DCHECK(CalledOnValidThread());
282 fetcher_ = fetcher.Pass(); 270 fetcher_ = fetcher.Pass();
283 } 271 }
284 272
285 // static 273 // static
286 void SdchManager::EnableSdchSupport(bool enabled) { 274 void SdchManager::EnableSdchSupport(bool enabled) {
287 g_sdch_enabled_ = enabled; 275 g_sdch_enabled_ = enabled;
288 } 276 }
289 277
290 // static 278 // static
291 void SdchManager::EnableSecureSchemeSupport(bool enabled) { 279 void SdchManager::EnableSecureSchemeSupport(bool enabled) {
292 g_secure_scheme_supported_ = enabled; 280 g_secure_scheme_supported_ = enabled;
293 } 281 }
294 282
295 void SdchManager::BlacklistDomain(const GURL& url, 283 void SdchManager::BlacklistDomain(const GURL& url,
296 ProblemCodes blacklist_reason) { 284 SdchProblemCode blacklist_reason) {
297 SetAllowLatencyExperiment(url, false); 285 SetAllowLatencyExperiment(url, false);
298 286
299 BlacklistInfo* blacklist_info = 287 BlacklistInfo* blacklist_info =
300 &blacklisted_domains_[base::StringToLowerASCII(url.host())]; 288 &blacklisted_domains_[base::StringToLowerASCII(url.host())];
301 289
302 if (blacklist_info->count > 0) 290 if (blacklist_info->count > 0)
303 return; // Domain is already blacklisted. 291 return; // Domain is already blacklisted.
304 292
305 if (blacklist_info->exponential_count > (INT_MAX - 1) / 2) { 293 if (blacklist_info->exponential_count > (INT_MAX - 1) / 2) {
306 blacklist_info->exponential_count = INT_MAX; 294 blacklist_info->exponential_count = INT_MAX;
307 } else { 295 } else {
308 blacklist_info->exponential_count = 296 blacklist_info->exponential_count =
309 blacklist_info->exponential_count * 2 + 1; 297 blacklist_info->exponential_count * 2 + 1;
310 } 298 }
311 299
312 blacklist_info->count = blacklist_info->exponential_count; 300 blacklist_info->count = blacklist_info->exponential_count;
313 blacklist_info->reason = blacklist_reason; 301 blacklist_info->reason = blacklist_reason;
314 } 302 }
315 303
316 void SdchManager::BlacklistDomainForever(const GURL& url, 304 void SdchManager::BlacklistDomainForever(const GURL& url,
317 ProblemCodes blacklist_reason) { 305 SdchProblemCode blacklist_reason) {
318 SetAllowLatencyExperiment(url, false); 306 SetAllowLatencyExperiment(url, false);
319 307
320 BlacklistInfo* blacklist_info = 308 BlacklistInfo* blacklist_info =
321 &blacklisted_domains_[base::StringToLowerASCII(url.host())]; 309 &blacklisted_domains_[base::StringToLowerASCII(url.host())];
322 blacklist_info->count = INT_MAX; 310 blacklist_info->count = INT_MAX;
323 blacklist_info->exponential_count = INT_MAX; 311 blacklist_info->exponential_count = INT_MAX;
324 blacklist_info->reason = blacklist_reason; 312 blacklist_info->reason = blacklist_reason;
325 } 313 }
326 314
327 void SdchManager::ClearBlacklistings() { 315 void SdchManager::ClearBlacklistings() {
328 blacklisted_domains_.clear(); 316 blacklisted_domains_.clear();
329 } 317 }
330 318
331 void SdchManager::ClearDomainBlacklisting(const std::string& domain) { 319 void SdchManager::ClearDomainBlacklisting(const std::string& domain) {
332 BlacklistInfo* blacklist_info = &blacklisted_domains_[ 320 BlacklistInfo* blacklist_info = &blacklisted_domains_[
333 base::StringToLowerASCII(domain)]; 321 base::StringToLowerASCII(domain)];
334 blacklist_info->count = 0; 322 blacklist_info->count = 0;
335 blacklist_info->reason = MIN_PROBLEM_CODE; 323 blacklist_info->reason = SDCH_OK;
336 } 324 }
337 325
338 int SdchManager::BlackListDomainCount(const std::string& domain) { 326 int SdchManager::BlackListDomainCount(const std::string& domain) {
339 std::string domain_lower(base::StringToLowerASCII(domain)); 327 std::string domain_lower(base::StringToLowerASCII(domain));
340 328
341 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain_lower)) 329 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain_lower))
342 return 0; 330 return 0;
343 return blacklisted_domains_[domain_lower].count; 331 return blacklisted_domains_[domain_lower].count;
344 } 332 }
345 333
346 int SdchManager::BlacklistDomainExponential(const std::string& domain) { 334 int SdchManager::BlacklistDomainExponential(const std::string& domain) {
347 std::string domain_lower(base::StringToLowerASCII(domain)); 335 std::string domain_lower(base::StringToLowerASCII(domain));
348 336
349 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain_lower)) 337 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain_lower))
350 return 0; 338 return 0;
351 return blacklisted_domains_[domain_lower].exponential_count; 339 return blacklisted_domains_[domain_lower].exponential_count;
352 } 340 }
353 341
354 bool SdchManager::IsInSupportedDomain(const GURL& url) { 342 SdchProblemCode SdchManager::IsInSupportedDomain(const GURL& url) {
355 DCHECK(CalledOnValidThread()); 343 DCHECK(CalledOnValidThread());
356 if (!g_sdch_enabled_ ) 344 if (!g_sdch_enabled_ )
357 return false; 345 return SDCH_DISABLED;
358 346
359 if (!secure_scheme_supported() && url.SchemeIsSecure()) 347 if (!secure_scheme_supported() && url.SchemeIsSecure())
360 return false; 348 return SDCH_SECURE_SCHEME_NOT_SUPPORTED;
361 349
362 if (blacklisted_domains_.empty()) 350 if (blacklisted_domains_.empty())
363 return true; 351 return SDCH_OK;
364 352
365 DomainBlacklistInfo::iterator it = 353 DomainBlacklistInfo::iterator it =
366 blacklisted_domains_.find(base::StringToLowerASCII(url.host())); 354 blacklisted_domains_.find(base::StringToLowerASCII(url.host()));
367 if (blacklisted_domains_.end() == it || it->second.count == 0) 355 if (blacklisted_domains_.end() == it || it->second.count == 0)
368 return true; 356 return SDCH_OK;
369 357
370 UMA_HISTOGRAM_ENUMERATION("Sdch3.BlacklistReason", it->second.reason, 358 UMA_HISTOGRAM_ENUMERATION(
371 MAX_PROBLEM_CODE); 359 "Sdch3.BlacklistReason", it->second.reason, SDCH_MAX_PROBLEM_CODE);
372 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET);
373 360
374 int count = it->second.count - 1; 361 int count = it->second.count - 1;
375 if (count > 0) { 362 if (count > 0) {
376 it->second.count = count; 363 it->second.count = count;
377 } else { 364 } else {
378 it->second.count = 0; 365 it->second.count = 0;
379 it->second.reason = MIN_PROBLEM_CODE; 366 it->second.reason = SDCH_OK;
380 } 367 }
381 368
382 return false; 369 return SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET;
383 } 370 }
384 371
385 void SdchManager::FetchDictionary(const GURL& request_url, 372 SdchProblemCode SdchManager::FetchDictionary(const GURL& request_url,
386 const GURL& dictionary_url) { 373 const GURL& dictionary_url) {
387 DCHECK(CalledOnValidThread()); 374 DCHECK(CalledOnValidThread());
388 if (CanFetchDictionary(request_url, dictionary_url) && fetcher_.get()) { 375 SdchProblemCode rv = CanFetchDictionary(request_url, dictionary_url);
376 if (rv != SDCH_OK)
377 return rv;
378
379 if (fetcher_.get()) {
389 ++fetches_count_for_testing_; 380 ++fetches_count_for_testing_;
390 fetcher_->Schedule(dictionary_url); 381 if (fetcher_->Schedule(dictionary_url))
382 return SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD;
391 } 383 }
384
385 return SDCH_OK;
392 } 386 }
393 387
394 bool SdchManager::CanFetchDictionary(const GURL& referring_url, 388 SdchProblemCode SdchManager::CanFetchDictionary(
395 const GURL& dictionary_url) const { 389 const GURL& referring_url,
390 const GURL& dictionary_url) const {
396 DCHECK(CalledOnValidThread()); 391 DCHECK(CalledOnValidThread());
397 /* The user agent may retrieve a dictionary from the dictionary URL if all of 392 /* The user agent may retrieve a dictionary from the dictionary URL if all of
398 the following are true: 393 the following are true:
399 1 The dictionary URL host name matches the referrer URL host name and 394 1 The dictionary URL host name matches the referrer URL host name and
400 scheme. 395 scheme.
401 2 The dictionary URL host name domain matches the parent domain of the 396 2 The dictionary URL host name domain matches the parent domain of the
402 referrer URL host name 397 referrer URL host name
403 3 The parent domain of the referrer URL host name is not a top level 398 3 The parent domain of the referrer URL host name is not a top level
404 domain 399 domain
405 4 The dictionary URL is not an HTTPS URL. 400 4 The dictionary URL is not an HTTPS URL.
406 */ 401 */
407 // Item (1) above implies item (2). Spec should be updated. 402 // Item (1) above implies item (2). Spec should be updated.
408 // I take "host name match" to be "is identical to" 403 // I take "host name match" to be "is identical to"
409 if (referring_url.host() != dictionary_url.host() || 404 if (referring_url.host() != dictionary_url.host() ||
410 referring_url.scheme() != dictionary_url.scheme()) { 405 referring_url.scheme() != dictionary_url.scheme())
411 SdchErrorRecovery(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST); 406 return SDCH_DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST;
412 return false; 407
413 } 408 if (!secure_scheme_supported() && referring_url.SchemeIsSecure())
414 if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) { 409 return SDCH_DICTIONARY_SELECTED_FOR_SSL;
415 SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL);
416 return false;
417 }
418 410
419 // TODO(jar): Remove this failsafe conservative hack which is more restrictive 411 // TODO(jar): Remove this failsafe conservative hack which is more restrictive
420 // than current SDCH spec when needed, and justified by security audit. 412 // than current SDCH spec when needed, and justified by security audit.
421 if (!referring_url.SchemeIsHTTPOrHTTPS()) { 413 if (!referring_url.SchemeIsHTTPOrHTTPS())
422 SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP); 414 return SDCH_DICTIONARY_SELECTED_FROM_NON_HTTP;
423 return false;
424 }
425 415
426 return true; 416 return SDCH_OK;
427 } 417 }
428 418
429 void SdchManager::GetVcdiffDictionary( 419 SdchProblemCode SdchManager::GetVcdiffDictionary(
430 const std::string& server_hash, 420 const std::string& server_hash,
431 const GURL& referring_url, 421 const GURL& referring_url,
432 scoped_refptr<Dictionary>* dictionary) { 422 scoped_refptr<Dictionary>* dictionary) {
433 DCHECK(CalledOnValidThread()); 423 DCHECK(CalledOnValidThread());
434 *dictionary = NULL; 424 *dictionary = NULL;
435 DictionaryMap::iterator it = dictionaries_.find(server_hash); 425 DictionaryMap::iterator it = dictionaries_.find(server_hash);
436 if (it == dictionaries_.end()) { 426 if (it == dictionaries_.end())
437 return; 427 return SDCH_DICTIONARY_HASH_NOT_FOUND;
438 } 428
439 scoped_refptr<Dictionary> matching_dictionary = it->second; 429 scoped_refptr<Dictionary> matching_dictionary = it->second;
440 if (!IsInSupportedDomain(referring_url)) 430
441 return; 431 SdchProblemCode rv = IsInSupportedDomain(referring_url);
442 if (!matching_dictionary->CanUse(referring_url)) 432 if (rv != SDCH_OK)
443 return; 433 return rv;
444 *dictionary = matching_dictionary; 434
435 rv = matching_dictionary->CanUse(referring_url);
436 if (rv == SDCH_OK)
437 *dictionary = matching_dictionary;
438 return rv;
445 } 439 }
446 440
447 // TODO(jar): If we have evictions from the dictionaries_, then we need to 441 // TODO(jar): If we have evictions from the dictionaries_, then we need to
448 // change this interface to return a list of reference counted Dictionary 442 // change this interface to return a list of reference counted Dictionary
449 // instances that can be used if/when a server specifies one. 443 // instances that can be used if/when a server specifies one.
450 void SdchManager::GetAvailDictionaryList(const GURL& target_url, 444 void SdchManager::GetAvailDictionaryList(const GURL& target_url,
451 std::string* list) { 445 std::string* list) {
452 DCHECK(CalledOnValidThread()); 446 DCHECK(CalledOnValidThread());
453 int count = 0; 447 int count = 0;
454 for (DictionaryMap::iterator it = dictionaries_.begin(); 448 for (DictionaryMap::iterator it = dictionaries_.begin();
455 it != dictionaries_.end(); ++it) { 449 it != dictionaries_.end(); ++it) {
456 if (!IsInSupportedDomain(target_url)) 450 SdchProblemCode rv = IsInSupportedDomain(target_url);
451 if (rv != SDCH_OK)
457 continue; 452 continue;
458 if (!it->second->CanAdvertise(target_url)) 453
454 if (it->second->CanAdvertise(target_url) != SDCH_OK)
459 continue; 455 continue;
460 ++count; 456 ++count;
461 if (!list->empty()) 457 if (!list->empty())
462 list->append(","); 458 list->append(",");
463 list->append(it->second->client_hash()); 459 list->append(it->second->client_hash());
464 } 460 }
465 // Watch to see if we have corrupt or numerous dictionaries. 461 // Watch to see if we have corrupt or numerous dictionaries.
466 if (count > 0) 462 if (count > 0)
467 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); 463 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count);
468 } 464 }
(...skipping 24 matching lines...) Expand all
493 489
494 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { 490 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) {
495 DCHECK(CalledOnValidThread()); 491 DCHECK(CalledOnValidThread());
496 if (enable) { 492 if (enable) {
497 allow_latency_experiment_.insert(url.host()); 493 allow_latency_experiment_.insert(url.host());
498 return; 494 return;
499 } 495 }
500 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host()); 496 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host());
501 if (allow_latency_experiment_.end() == it) 497 if (allow_latency_experiment_.end() == it)
502 return; // It was already erased, or never allowed. 498 return; // It was already erased, or never allowed.
503 SdchErrorRecovery(LATENCY_TEST_DISALLOWED); 499 SdchErrorRecovery(SDCH_LATENCY_TEST_DISALLOWED);
504 allow_latency_experiment_.erase(it); 500 allow_latency_experiment_.erase(it);
505 } 501 }
506 502
507 void SdchManager::AddSdchDictionary(const std::string& dictionary_text, 503 SdchProblemCode SdchManager::AddSdchDictionary(
504 const std::string& dictionary_text,
508 const GURL& dictionary_url) { 505 const GURL& dictionary_url) {
509 DCHECK(CalledOnValidThread()); 506 DCHECK(CalledOnValidThread());
510 std::string client_hash; 507 std::string client_hash;
511 std::string server_hash; 508 std::string server_hash;
512 GenerateHash(dictionary_text, &client_hash, &server_hash); 509 GenerateHash(dictionary_text, &client_hash, &server_hash);
513 if (dictionaries_.find(server_hash) != dictionaries_.end()) { 510 if (dictionaries_.find(server_hash) != dictionaries_.end())
514 SdchErrorRecovery(DICTIONARY_ALREADY_LOADED); 511 return SDCH_DICTIONARY_ALREADY_LOADED; // Already loaded.
515 return; // Already loaded.
516 }
517 512
518 std::string domain, path; 513 std::string domain, path;
519 std::set<int> ports; 514 std::set<int> ports;
520 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); 515 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30));
521 516
522 if (dictionary_text.empty()) { 517 if (dictionary_text.empty())
523 SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT); 518 return SDCH_DICTIONARY_HAS_NO_TEXT; // Missing header.
524 return; // Missing header.
525 }
526 519
527 size_t header_end = dictionary_text.find("\n\n"); 520 size_t header_end = dictionary_text.find("\n\n");
528 if (std::string::npos == header_end) { 521 if (std::string::npos == header_end)
529 SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER); 522 return SDCH_DICTIONARY_HAS_NO_HEADER; // Missing header.
530 return; // Missing header. 523
531 }
532 size_t line_start = 0; // Start of line being parsed. 524 size_t line_start = 0; // Start of line being parsed.
533 while (1) { 525 while (1) {
534 size_t line_end = dictionary_text.find('\n', line_start); 526 size_t line_end = dictionary_text.find('\n', line_start);
535 DCHECK(std::string::npos != line_end); 527 DCHECK(std::string::npos != line_end);
536 DCHECK_LE(line_end, header_end); 528 DCHECK_LE(line_end, header_end);
537 529
538 size_t colon_index = dictionary_text.find(':', line_start); 530 size_t colon_index = dictionary_text.find(':', line_start);
539 if (std::string::npos == colon_index) { 531 if (std::string::npos == colon_index)
540 SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON); 532 return SDCH_DICTIONARY_HEADER_LINE_MISSING_COLON; // Illegal line missing
541 return; // Illegal line missing a colon. 533 // a colon.
542 }
543 534
544 if (colon_index > line_end) 535 if (colon_index > line_end)
545 break; 536 break;
546 537
547 size_t value_start = dictionary_text.find_first_not_of(" \t", 538 size_t value_start = dictionary_text.find_first_not_of(" \t",
548 colon_index + 1); 539 colon_index + 1);
549 if (std::string::npos != value_start) { 540 if (std::string::npos != value_start) {
550 if (value_start >= line_end) 541 if (value_start >= line_end)
551 break; 542 break;
552 std::string name(dictionary_text, line_start, colon_index - line_start); 543 std::string name(dictionary_text, line_start, colon_index - line_start);
553 std::string value(dictionary_text, value_start, line_end - value_start); 544 std::string value(dictionary_text, value_start, line_end - value_start);
554 name = base::StringToLowerASCII(name); 545 name = base::StringToLowerASCII(name);
555 if (name == "domain") { 546 if (name == "domain") {
556 domain = value; 547 domain = value;
557 } else if (name == "path") { 548 } else if (name == "path") {
558 path = value; 549 path = value;
559 } else if (name == "format-version") { 550 } else if (name == "format-version") {
560 if (value != "1.0") 551 if (value != "1.0")
561 return; 552 return SDCH_DICTIONARY_UNSUPPORTED_VERSION;
562 } else if (name == "max-age") { 553 } else if (name == "max-age") {
563 int64 seconds; 554 int64 seconds;
564 base::StringToInt64(value, &seconds); 555 base::StringToInt64(value, &seconds);
565 expiration = base::Time::Now() + base::TimeDelta::FromSeconds(seconds); 556 expiration = base::Time::Now() + base::TimeDelta::FromSeconds(seconds);
566 } else if (name == "port") { 557 } else if (name == "port") {
567 int port; 558 int port;
568 base::StringToInt(value, &port); 559 base::StringToInt(value, &port);
569 if (port >= 0) 560 if (port >= 0)
570 ports.insert(port); 561 ports.insert(port);
571 } 562 }
572 } 563 }
573 564
574 if (line_end >= header_end) 565 if (line_end >= header_end)
575 break; 566 break;
576 line_start = line_end + 1; 567 line_start = line_end + 1;
577 } 568 }
578 569
579 // Narrow fix for http://crbug.com/389451. 570 // Narrow fix for http://crbug.com/389451.
580 GURL dictionary_url_normalized(dictionary_url); 571 GURL dictionary_url_normalized(dictionary_url);
581 StripTrailingDot(&dictionary_url_normalized); 572 StripTrailingDot(&dictionary_url_normalized);
582 573
583 if (!IsInSupportedDomain(dictionary_url_normalized)) 574 SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized);
584 return; 575 if (rv != SDCH_OK)
576 return rv;
585 577
586 if (!Dictionary::CanSet(domain, path, ports, dictionary_url_normalized)) 578 rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized);
587 return; 579 if (rv != SDCH_OK)
580 return rv;
588 581
589 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of 582 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of
590 // useless dictionaries. We should probably have a cache eviction plan, 583 // useless dictionaries. We should probably have a cache eviction plan,
591 // instead of just blocking additions. For now, with the spec in flux, it 584 // instead of just blocking additions. For now, with the spec in flux, it
592 // is probably not worth doing eviction handling. 585 // is probably not worth doing eviction handling.
593 if (kMaxDictionarySize < dictionary_text.size()) { 586 if (kMaxDictionarySize < dictionary_text.size())
594 SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE); 587 return SDCH_DICTIONARY_IS_TOO_LARGE;
595 return; 588
596 } 589 if (kMaxDictionaryCount <= dictionaries_.size())
597 if (kMaxDictionaryCount <= dictionaries_.size()) { 590 return SDCH_DICTIONARY_COUNT_EXCEEDED;
598 SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED);
599 return;
600 }
601 591
602 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); 592 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
603 DVLOG(1) << "Loaded dictionary with client hash " << client_hash 593 DVLOG(1) << "Loaded dictionary with client hash " << client_hash
604 << " and server hash " << server_hash; 594 << " and server hash " << server_hash;
605 Dictionary* dictionary = 595 Dictionary* dictionary =
606 new Dictionary(dictionary_text, header_end + 2, client_hash, 596 new Dictionary(dictionary_text, header_end + 2, client_hash,
607 dictionary_url_normalized, domain, 597 dictionary_url_normalized, domain,
608 path, expiration, ports); 598 path, expiration, ports);
609 dictionaries_[server_hash] = dictionary; 599 dictionaries_[server_hash] = dictionary;
610 return; 600 return SDCH_OK;
611 } 601 }
612 602
613 // static 603 // static
614 void SdchManager::UrlSafeBase64Encode(const std::string& input, 604 void SdchManager::UrlSafeBase64Encode(const std::string& input,
615 std::string* output) { 605 std::string* output) {
616 // Since this is only done during a dictionary load, and hashes are only 8 606 // Since this is only done during a dictionary load, and hashes are only 8
617 // characters, we just do the simple fixup, rather than rewriting the encoder. 607 // characters, we just do the simple fixup, rather than rewriting the encoder.
618 base::Base64Encode(input, output); 608 base::Base64Encode(input, output);
619 std::replace(output->begin(), output->end(), '+', '-'); 609 std::replace(output->begin(), output->end(), '+', '-');
620 std::replace(output->begin(), output->end(), '/', '_'); 610 std::replace(output->begin(), output->end(), '/', '_');
621 } 611 }
622 612
613 base::Value* SdchManager::SdchInfoToValue() const {
614 base::DictionaryValue* value = new base::DictionaryValue();
615
616 value->SetBoolean("sdch_enabled", sdch_enabled());
617 value->SetBoolean("secure_scheme_support", secure_scheme_supported());
618
619 base::ListValue* entry_list = new base::ListValue();
620 for (DictionaryMap::const_iterator it = dictionaries_.begin();
621 it != dictionaries_.end();
622 ++it) {
623 base::DictionaryValue* entry_dict = new base::DictionaryValue();
624 entry_dict->SetString("url", it->second->url().spec());
625 entry_dict->SetString("client_hash", it->second->client_hash());
626 entry_dict->SetString("domain", it->second->domain());
627 entry_dict->SetString("path", it->second->path());
628 base::ListValue* port_list = new base::ListValue();
629 for (std::set<int>::const_iterator port_it = it->second->ports().begin();
630 port_it != it->second->ports().end();
631 ++port_it) {
632 port_list->AppendInteger(*port_it);
633 }
634 entry_dict->Set("ports", port_list);
635 entry_dict->SetString("server_hash", it->first);
636 entry_list->Append(entry_dict);
637 }
638 value->Set("dictionaries", entry_list);
639
640 entry_list = new base::ListValue();
641 for (DomainBlacklistInfo::const_iterator it = blacklisted_domains_.begin();
642 it != blacklisted_domains_.end();
643 ++it) {
644 if (it->second.count == 0)
645 continue;
646 base::DictionaryValue* entry_dict = new base::DictionaryValue();
647 entry_dict->SetString("domain", it->first);
648 if (it->second.count != INT_MAX)
649 entry_dict->SetInteger("tries", it->second.count);
650 entry_dict->SetInteger("reason", it->second.reason);
651 entry_list->Append(entry_dict);
652 }
653 value->Set("blacklisted", entry_list);
654
655 return value;
656 }
657
623 } // namespace net 658 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698