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

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

Issue 1051933002: Split SdchManager::Dictionary out into separate class/file. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added unit tests. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/base/sdch_manager.h" 5 #include "net/base/sdch_manager.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/time/default_clock.h" 12 #include "base/time/default_clock.h"
13 #include "base/values.h" 13 #include "base/values.h"
14 #include "crypto/sha2.h" 14 #include "crypto/sha2.h"
15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
16 #include "net/base/sdch_observer.h" 15 #include "net/base/sdch_observer.h"
17 #include "net/url_request/url_request_http_job.h" 16 #include "net/url_request/url_request_http_job.h"
18 17
19 namespace { 18 namespace {
20 19
21 void StripTrailingDot(GURL* gurl) { 20 void StripTrailingDot(GURL* gurl) {
22 std::string host(gurl->host()); 21 std::string host(gurl->host());
23 22
24 if (host.empty()) 23 if (host.empty())
25 return; 24 return;
(...skipping 12 matching lines...) Expand all
38 } // namespace 37 } // namespace
39 38
40 namespace net { 39 namespace net {
41 40
42 // static 41 // static
43 bool SdchManager::g_sdch_enabled_ = true; 42 bool SdchManager::g_sdch_enabled_ = true;
44 43
45 // static 44 // static
46 bool SdchManager::g_secure_scheme_supported_ = true; 45 bool SdchManager::g_secure_scheme_supported_ = true;
47 46
48 SdchManager::Dictionary::Dictionary(const std::string& dictionary_text,
49 size_t offset,
50 const std::string& client_hash,
51 const std::string& server_hash,
52 const GURL& gurl,
53 const std::string& domain,
54 const std::string& path,
55 const base::Time& expiration,
56 const std::set<int>& ports)
57 : text_(dictionary_text, offset),
58 client_hash_(client_hash),
59 server_hash_(server_hash),
60 url_(gurl),
61 domain_(domain),
62 path_(path),
63 expiration_(expiration),
64 ports_(ports),
65 clock_(new base::DefaultClock) {
66 }
67
68 SdchManager::Dictionary::Dictionary(const SdchManager::Dictionary& rhs)
69 : text_(rhs.text_),
70 client_hash_(rhs.client_hash_),
71 server_hash_(rhs.server_hash_),
72 url_(rhs.url_),
73 domain_(rhs.domain_),
74 path_(rhs.path_),
75 expiration_(rhs.expiration_),
76 ports_(rhs.ports_),
77 clock_(new base::DefaultClock) {
78 }
79
80 SdchManager::Dictionary::~Dictionary() {}
81
82 // Security functions restricting loads and use of dictionaries.
83
84 // static
85 SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain,
86 const std::string& path,
87 const std::set<int>& ports,
88 const GURL& dictionary_url) {
89 /*
90 A dictionary is invalid and must not be stored if any of the following are
91 true:
92 1. The dictionary has no Domain attribute.
93 2. The effective host name that derives from the referer URL host name does
94 not domain-match the Domain attribute.
95 3. The Domain attribute is a top level domain.
96 4. The referer URL host is a host domain name (not IP address) and has the
97 form HD, where D is the value of the Domain attribute, and H is a string
98 that contains one or more dots.
99 5. If the dictionary has a Port attribute and the referer URL's port was not
100 in the list.
101 */
102
103 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic,
104 // and hence the conservative approach is to not allow any redirects (if there
105 // were any... then don't allow the dictionary to be set).
106
107 if (domain.empty())
108 return SDCH_DICTIONARY_MISSING_DOMAIN_SPECIFIER; // Domain is required.
109
110 if (registry_controlled_domains::GetDomainAndRegistry(
111 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)
112 .empty()) {
113 return SDCH_DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN; // domain was a TLD.
114 }
115
116 if (!Dictionary::DomainMatch(dictionary_url, domain))
117 return SDCH_DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL;
118
119 std::string referrer_url_host = dictionary_url.host();
120 size_t postfix_domain_index = referrer_url_host.rfind(domain);
121 // See if it is indeed a postfix, or just an internal string.
122 if (referrer_url_host.size() == postfix_domain_index + domain.size()) {
123 // It is a postfix... so check to see if there's a dot in the prefix.
124 size_t end_of_host_index = referrer_url_host.find_first_of('.');
125 if (referrer_url_host.npos != end_of_host_index &&
126 end_of_host_index < postfix_domain_index) {
127 return SDCH_DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX;
128 }
129 }
130
131 if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort()))
132 return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL;
133
134 return SDCH_OK;
135 }
136
137 SdchProblemCode SdchManager::Dictionary::CanUse(
138 const GURL& target_url) const {
139 /*
140 1. The request URL's host name domain-matches the Domain attribute of the
141 dictionary.
142 2. If the dictionary has a Port attribute, the request port is one of the
143 ports listed in the Port attribute.
144 3. The request URL path-matches the path attribute of the dictionary.
145 4. The request is not an HTTPS request.
146 We can override (ignore) item (4) only when we have explicitly enabled
147 HTTPS support AND the dictionary acquisition scheme matches the target
148 url scheme.
149 */
150 if (!DomainMatch(target_url, domain_))
151 return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
152
153 if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort()))
154 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
155
156 if (path_.size() && !PathMatch(target_url.path(), path_))
157 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
158
159 if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
160 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
161
162 if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
163 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
164
165 // TODO(jar): Remove overly restrictive failsafe test (added per security
166 // review) when we have a need to be more general.
167 if (!target_url.SchemeIsHTTPOrHTTPS())
168 return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA;
169
170 return SDCH_OK;
171 }
172
173 // static
174 bool SdchManager::Dictionary::PathMatch(const std::string& path,
175 const std::string& restriction) {
176 /* Must be either:
177 1. P2 is equal to P1
178 2. P2 is a prefix of P1 and either the final character in P2 is "/" or the
179 character following P2 in P1 is "/".
180 */
181 if (path == restriction)
182 return true;
183 size_t prefix_length = restriction.size();
184 if (prefix_length > path.size())
185 return false; // Can't be a prefix.
186 if (0 != path.compare(0, prefix_length, restriction))
187 return false;
188 return restriction[prefix_length - 1] == '/' || path[prefix_length] == '/';
189 }
190
191 // static
192 bool SdchManager::Dictionary::DomainMatch(const GURL& gurl,
193 const std::string& restriction) {
194 // TODO(jar): This is not precisely a domain match definition.
195 return gurl.DomainIs(restriction.data(), restriction.size());
196 }
197
198 bool SdchManager::Dictionary::Expired() const {
199 return clock_->Now() > expiration_;
200 }
201
202 void SdchManager::Dictionary::SetClockForTesting(
203 scoped_ptr<base::Clock> clock) {
204 clock_ = clock.Pass();
205 }
206
207 SdchManager::DictionarySet::DictionarySet() {} 47 SdchManager::DictionarySet::DictionarySet() {}
208 48
209 SdchManager::DictionarySet::~DictionarySet() {} 49 SdchManager::DictionarySet::~DictionarySet() {}
210 50
211 std::string SdchManager::DictionarySet::GetDictionaryClientHashList() const { 51 std::string SdchManager::DictionarySet::GetDictionaryClientHashList() const {
212 std::string result; 52 std::string result;
213 bool first = true; 53 bool first = true;
214 for (const auto& entry: dictionaries_) { 54 for (const auto& entry: dictionaries_) {
215 if (!first) 55 if (!first)
216 result.append(","); 56 result.append(",");
217 57
218 result.append(entry.second->data.client_hash()); 58 result.append(entry.second->data.client_hash());
219 first = false; 59 first = false;
220 } 60 }
221 return result; 61 return result;
222 } 62 }
223 63
224 const SdchManager::Dictionary* SdchManager::DictionarySet::GetDictionary( 64 const SdchDictionary* SdchManager::DictionarySet::GetDictionary(
225 const std::string& hash) const { 65 const std::string& hash) const {
226 auto it = dictionaries_.find(hash); 66 auto it = dictionaries_.find(hash);
227 if (it == dictionaries_.end()) 67 if (it == dictionaries_.end())
228 return NULL; 68 return NULL;
229 69
230 return &it->second->data; 70 return &it->second->data;
231 } 71 }
232 72
233 bool SdchManager::DictionarySet::Empty() const { 73 bool SdchManager::DictionarySet::Empty() const {
234 return dictionaries_.empty(); 74 return dictionaries_.empty();
235 } 75 }
236 76
237 void SdchManager::DictionarySet::AddDictionary( 77 void SdchManager::DictionarySet::AddDictionary(
238 const std::string& server_hash, 78 const std::string& server_hash,
239 const scoped_refptr<base::RefCountedData<SdchManager::Dictionary>>& 79 const scoped_refptr<base::RefCountedData<SdchDictionary>>& dictionary) {
240 dictionary) {
241 DCHECK(dictionaries_.end() == dictionaries_.find(server_hash)); 80 DCHECK(dictionaries_.end() == dictionaries_.find(server_hash));
242 81
243 dictionaries_[server_hash] = dictionary; 82 dictionaries_[server_hash] = dictionary;
244 } 83 }
245 84
246 SdchManager::SdchManager() : factory_(this) { 85 SdchManager::SdchManager() : factory_(this) {
247 DCHECK(thread_checker_.CalledOnValidThread()); 86 DCHECK(thread_checker_.CalledOnValidThread());
248 } 87 }
249 88
250 SdchManager::~SdchManager() { 89 SdchManager::~SdchManager() {
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 } 262 }
424 263
425 scoped_ptr<SdchManager::DictionarySet> 264 scoped_ptr<SdchManager::DictionarySet>
426 SdchManager::GetDictionarySet(const GURL& target_url) { 265 SdchManager::GetDictionarySet(const GURL& target_url) {
427 if (IsInSupportedDomain(target_url) != SDCH_OK) 266 if (IsInSupportedDomain(target_url) != SDCH_OK)
428 return NULL; 267 return NULL;
429 268
430 int count = 0; 269 int count = 0;
431 scoped_ptr<SdchManager::DictionarySet> result(new DictionarySet); 270 scoped_ptr<SdchManager::DictionarySet> result(new DictionarySet);
432 for (const auto& entry: dictionaries_) { 271 for (const auto& entry: dictionaries_) {
272 if (!secure_scheme_supported() && target_url.SchemeIsSecure())
Elly Fong-Jones 2015/04/08 16:25:33 Is this an unrelated bugfix?
Randy Smith (Not in Mondays) 2015/04/08 21:06:05 Not really. CanUse() used to use the above test,
273 continue;
433 if (entry.second->data.CanUse(target_url) != SDCH_OK) 274 if (entry.second->data.CanUse(target_url) != SDCH_OK)
434 continue; 275 continue;
435 if (entry.second->data.Expired()) 276 if (entry.second->data.Expired())
436 continue; 277 continue;
437 ++count; 278 ++count;
438 result->AddDictionary(entry.first, entry.second); 279 result->AddDictionary(entry.first, entry.second);
439 } 280 }
440 281
441 if (count == 0) 282 if (count == 0)
442 return NULL; 283 return NULL;
443 284
444 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); 285 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count);
445 286
446 return result.Pass(); 287 return result.Pass();
447 } 288 }
448 289
449 scoped_ptr<SdchManager::DictionarySet> 290 scoped_ptr<SdchManager::DictionarySet>
450 SdchManager::GetDictionarySetByHash( 291 SdchManager::GetDictionarySetByHash(
451 const GURL& target_url, 292 const GURL& target_url,
452 const std::string& server_hash, 293 const std::string& server_hash,
453 SdchProblemCode* problem_code) { 294 SdchProblemCode* problem_code) {
454 scoped_ptr<SdchManager::DictionarySet> result; 295 scoped_ptr<SdchManager::DictionarySet> result;
455 296
456 *problem_code = SDCH_DICTIONARY_HASH_NOT_FOUND; 297 *problem_code = SDCH_DICTIONARY_HASH_NOT_FOUND;
457 const auto& it = dictionaries_.find(server_hash); 298 const auto& it = dictionaries_.find(server_hash);
458 if (it == dictionaries_.end()) 299 if (it == dictionaries_.end())
459 return result.Pass(); 300 return result.Pass();
460 301
302 if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure()) {
303 *problem_code = SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
304 return result.Pass();
305 }
306
461 *problem_code = it->second->data.CanUse(target_url); 307 *problem_code = it->second->data.CanUse(target_url);
462 if (*problem_code != SDCH_OK) 308 if (*problem_code != SDCH_OK)
463 return result.Pass(); 309 return result.Pass();
464 310
465 result.reset(new DictionarySet); 311 result.reset(new DictionarySet);
466 result->AddDictionary(it->first, it->second); 312 result->AddDictionary(it->first, it->second);
467 return result.Pass(); 313 return result.Pass();
468 } 314 }
469 315
470 // static 316 // static
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 } 426 }
581 427
582 // Narrow fix for http://crbug.com/389451. 428 // Narrow fix for http://crbug.com/389451.
583 GURL dictionary_url_normalized(dictionary_url); 429 GURL dictionary_url_normalized(dictionary_url);
584 StripTrailingDot(&dictionary_url_normalized); 430 StripTrailingDot(&dictionary_url_normalized);
585 431
586 SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized); 432 SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized);
587 if (rv != SDCH_OK) 433 if (rv != SDCH_OK)
588 return rv; 434 return rv;
589 435
590 rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized); 436 rv = SdchDictionary::CanSet(domain, path, ports, dictionary_url_normalized);
591 if (rv != SDCH_OK) 437 if (rv != SDCH_OK)
592 return rv; 438 return rv;
593 439
594 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); 440 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
595 DVLOG(1) << "Loaded dictionary with client hash " << client_hash 441 DVLOG(1) << "Loaded dictionary with client hash " << client_hash
596 << " and server hash " << server_hash; 442 << " and server hash " << server_hash;
597 Dictionary dictionary(dictionary_text, header_end + 2, client_hash, 443 SdchDictionary dictionary(dictionary_text, header_end + 2, client_hash,
598 server_hash, dictionary_url_normalized, domain, path, 444 server_hash, dictionary_url_normalized, domain,
599 expiration, ports); 445 path, expiration, ports);
600 dictionaries_[server_hash] = 446 dictionaries_[server_hash] =
601 new base::RefCountedData<Dictionary>(dictionary); 447 new base::RefCountedData<SdchDictionary>(dictionary);
602 if (server_hash_p) 448 if (server_hash_p)
603 *server_hash_p = server_hash; 449 *server_hash_p = server_hash;
604 450
605 return SDCH_OK; 451 return SDCH_OK;
606 } 452 }
607 453
608 SdchProblemCode SdchManager::RemoveSdchDictionary( 454 SdchProblemCode SdchManager::RemoveSdchDictionary(
609 const std::string& server_hash) { 455 const std::string& server_hash) {
610 if (dictionaries_.find(server_hash) == dictionaries_.end()) 456 if (dictionaries_.find(server_hash) == dictionaries_.end())
611 return SDCH_DICTIONARY_HASH_NOT_FOUND; 457 return SDCH_DICTIONARY_HASH_NOT_FOUND;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 entry_dict->SetInteger("tries", it->second.count); 517 entry_dict->SetInteger("tries", it->second.count);
672 entry_dict->SetInteger("reason", it->second.reason); 518 entry_dict->SetInteger("reason", it->second.reason);
673 entry_list->Append(entry_dict); 519 entry_list->Append(entry_dict);
674 } 520 }
675 value->Set("blacklisted", entry_list); 521 value->Set("blacklisted", entry_list);
676 522
677 return value; 523 return value;
678 } 524 }
679 525
680 } // namespace net 526 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698