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

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

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

Powered by Google App Engine
This is Rietveld 408576698