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

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

Powered by Google App Engine
This is Rietveld 408576698