Chromium Code Reviews| 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 |