OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/base/sdch_dictionary.h" | |
6 | |
7 #include "base/time/clock.h" | |
8 #include "base/time/default_clock.h" | |
9 #include "base/values.h" | |
10 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | |
11 | |
12 namespace { | |
13 | |
14 bool DomainMatch(const GURL& gurl, const std::string& restriction) { | |
15 // TODO(jar): This is not precisely a domain match definition. | |
16 return gurl.DomainIs(restriction.data(), restriction.size()); | |
17 } | |
18 | |
19 } // namespace | |
20 | |
21 namespace net { | |
22 | |
23 SdchDictionary::SdchDictionary(const std::string& dictionary_text, | |
24 size_t offset, | |
25 const std::string& client_hash, | |
26 const std::string& server_hash, | |
27 const GURL& gurl, | |
28 const std::string& domain, | |
29 const std::string& path, | |
30 const base::Time& expiration, | |
31 const std::set<int>& ports) | |
32 : text_(dictionary_text, offset), | |
33 client_hash_(client_hash), | |
34 server_hash_(server_hash), | |
35 url_(gurl), | |
36 domain_(domain), | |
37 path_(path), | |
38 expiration_(expiration), | |
39 ports_(ports), | |
40 clock_(new base::DefaultClock) { | |
41 } | |
42 | |
43 SdchDictionary::SdchDictionary(const SdchDictionary& rhs) | |
44 : text_(rhs.text_), | |
45 client_hash_(rhs.client_hash_), | |
46 server_hash_(rhs.server_hash_), | |
47 url_(rhs.url_), | |
48 domain_(rhs.domain_), | |
49 path_(rhs.path_), | |
50 expiration_(rhs.expiration_), | |
51 ports_(rhs.ports_), | |
52 clock_(new base::DefaultClock) { | |
53 } | |
54 | |
55 SdchDictionary::~SdchDictionary() { | |
56 } | |
57 | |
58 // Security functions restricting loads and use of dictionaries. | |
59 | |
60 // static | |
61 SdchProblemCode SdchDictionary::CanSet(const std::string& domain, | |
62 const std::string& path, | |
63 const std::set<int>& ports, | |
64 const GURL& dictionary_url) { | |
65 /* | |
66 A dictionary is invalid and must not be stored if any of the following are | |
67 true: | |
68 1. The dictionary has no Domain attribute. | |
69 2. The effective host name that derives from the referer URL host name does | |
70 not domain-match the Domain attribute. | |
71 3. The Domain attribute is a top level domain. | |
72 4. The referer URL host is a host domain name (not IP address) and has the | |
73 form HD, where D is the value of the Domain attribute, and H is a string | |
74 that contains one or more dots. | |
75 5. If the dictionary has a Port attribute and the referer URL's port was not | |
76 in the list. | |
77 */ | |
78 | |
79 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic, | |
80 // and hence the conservative approach is to not allow any redirects (if there | |
81 // were any... then don't allow the dictionary to be set). | |
82 | |
83 if (domain.empty()) | |
84 return SDCH_DICTIONARY_MISSING_DOMAIN_SPECIFIER; // Domain is required. | |
85 | |
86 if (registry_controlled_domains::GetDomainAndRegistry( | |
87 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES) | |
88 .empty()) { | |
89 return SDCH_DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN; // domain was a TLD. | |
90 } | |
91 | |
92 if (!DomainMatch(dictionary_url, domain)) | |
93 return SDCH_DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL; | |
94 | |
95 std::string referrer_url_host = dictionary_url.host(); | |
96 size_t postfix_domain_index = referrer_url_host.rfind(domain); | |
97 // See if it is indeed a postfix, or just an internal string. | |
98 if (referrer_url_host.size() == postfix_domain_index + domain.size()) { | |
99 // It is a postfix... so check to see if there's a dot in the prefix. | |
100 size_t end_of_host_index = referrer_url_host.find_first_of('.'); | |
101 if (referrer_url_host.npos != end_of_host_index && | |
102 end_of_host_index < postfix_domain_index) { | |
103 return SDCH_DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX; | |
104 } | |
105 } | |
106 | |
107 if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort())) | |
108 return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL; | |
109 | |
110 return SDCH_OK; | |
111 } | |
112 | |
113 SdchProblemCode SdchDictionary::CanUse(const GURL& target_url) const { | |
114 /* | |
115 1. The request URL's host name domain-matches the Domain attribute of the | |
116 dictionary. | |
117 2. If the dictionary has a Port attribute, the request port is one of the | |
118 ports listed in the Port attribute. | |
119 3. The request URL path-matches the path attribute of the dictionary. | |
120 We can override (ignore) item (4) only when we have explicitly enabled | |
121 HTTPS support AND the dictionary acquisition scheme matches the target | |
122 url scheme. | |
123 */ | |
124 if (!DomainMatch(target_url, domain_)) | |
125 return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN; | |
126 | |
127 if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort())) | |
128 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST; | |
129 | |
130 if (path_.size() && !PathMatch(target_url.path(), path_)) | |
131 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH; | |
132 | |
133 if (target_url.SchemeIsSecure() != url_.SchemeIsSecure()) | |
134 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; | |
135 | |
136 // TODO(jar): Remove overly restrictive failsafe test (added per security | |
137 // review) when we have a need to be more general. | |
138 if (!target_url.SchemeIsHTTPOrHTTPS()) | |
139 return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA; | |
140 | |
141 return SDCH_OK; | |
142 } | |
143 | |
144 // static | |
145 bool SdchDictionary::PathMatch(const std::string& path, | |
146 const std::string& restriction) { | |
147 /* Must be either: | |
148 1. P2 is equal to P1 | |
149 2. P2 is a prefix of P1 and either the final character in P2 is "/" or the | |
150 character following P2 in P1 is "/". | |
151 */ | |
Elly Fong-Jones
2015/04/08 16:25:33
indentation
Randy Smith (Not in Mondays)
2015/04/08 21:06:05
Reformatted to use /*\n*...\n*...\n*/ style. Did
| |
152 if (path == restriction) | |
153 return true; | |
154 size_t prefix_length = restriction.size(); | |
155 if (prefix_length > path.size()) | |
156 return false; // Can't be a prefix. | |
157 if (0 != path.compare(0, prefix_length, restriction)) | |
158 return false; | |
159 return restriction[prefix_length - 1] == '/' || path[prefix_length] == '/'; | |
160 } | |
161 | |
162 bool SdchDictionary::Expired() const { | |
163 return clock_->Now() > expiration_; | |
164 } | |
165 | |
166 void SdchDictionary::SetClockForTesting(scoped_ptr<base::Clock> clock) { | |
167 clock_ = clock.Pass(); | |
168 } | |
169 | |
170 } // namespace net | |
OLD | NEW |