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

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