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.
5 #include "net/base/sdch_dictionary.h"
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"
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());
23 SdchDictionary::SdchDictionary(const std::string
& dictionary_text
,
25 const std::string
& client_hash
,
26 const std::string
& server_hash
,
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
),
38 expiration_(expiration
),
42 SdchDictionary::SdchDictionary(const SdchDictionary
& rhs
)
44 client_hash_(rhs
.client_hash_
),
45 server_hash_(rhs
.server_hash_
),
49 expiration_(rhs
.expiration_
),
53 SdchDictionary::~SdchDictionary() {
56 // Security functions restricting loads and use of dictionaries.
59 SdchProblemCode
SdchDictionary::CanSet(const std::string
& domain
,
60 const std::string
& path
,
61 const std::set
<int>& ports
,
62 const GURL
& dictionary_url
) {
64 * A dictionary is invalid and must not be stored if any of the following are
66 * 1. The dictionary has no Domain attribute.
67 * 2. The effective host name that derives from the referer URL host name does
68 * not domain-match the Domain attribute.
69 * 3. The Domain attribute is a top level domain.
70 * 4. The referer URL host is a host domain name (not IP address) and has the
71 * form HD, where D is the value of the Domain attribute, and H is a string
72 * that contains one or more dots.
73 * 5. If the dictionary has a Port attribute and the referer URL's port
74 * was not in the list.
77 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic,
78 // and hence the conservative approach is to not allow any redirects (if there
79 // were any... then don't allow the dictionary to be set).
82 return SDCH_DICTIONARY_MISSING_DOMAIN_SPECIFIER
; // Domain is required.
84 if (registry_controlled_domains::GetDomainAndRegistry(
85 domain
, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES
)
87 return SDCH_DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN
; // domain was a TLD.
90 if (!DomainMatch(dictionary_url
, domain
))
91 return SDCH_DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL
;
93 std::string referrer_url_host
= dictionary_url
.host();
94 size_t postfix_domain_index
= referrer_url_host
.rfind(domain
);
95 // See if it is indeed a postfix, or just an internal string.
96 if (referrer_url_host
.size() == postfix_domain_index
+ domain
.size()) {
97 // It is a postfix... so check to see if there's a dot in the prefix.
98 size_t end_of_host_index
= referrer_url_host
.find_first_of('.');
99 if (referrer_url_host
.npos
!= end_of_host_index
&&
100 end_of_host_index
< postfix_domain_index
) {
101 return SDCH_DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX
;
105 if (!ports
.empty() && 0 == ports
.count(dictionary_url
.EffectiveIntPort()))
106 return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL
;
111 SdchProblemCode
SdchDictionary::CanUse(const GURL
& target_url
) const {
113 * 1. The request URL's host name domain-matches the Domain attribute of the
115 * 2. If the dictionary has a Port attribute, the request port is one of the
116 * ports listed in the Port attribute.
117 * 3. The request URL path-matches the path attribute of the dictionary.
118 * We can override (ignore) item (4) only when we have explicitly enabled
119 * HTTPS support AND the dictionary acquisition scheme matches the target
122 if (!DomainMatch(target_url
, domain_
))
123 return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN
;
125 if (!ports_
.empty() && 0 == ports_
.count(target_url
.EffectiveIntPort()))
126 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST
;
128 if (path_
.size() && !PathMatch(target_url
.path(), path_
))
129 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH
;
131 if (target_url
.SchemeIsCryptographic() != url_
.SchemeIsCryptographic())
132 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME
;
134 // TODO(jar): Remove overly restrictive failsafe test (added per security
135 // review) when we have a need to be more general.
136 if (!target_url
.SchemeIsHTTPOrHTTPS())
137 return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA
;
143 bool SdchDictionary::PathMatch(const std::string
& path
,
144 const std::string
& restriction
) {
146 * 1. P2 is equal to P1
147 * 2. P2 is a prefix of P1 and either the final character in P2 is "/"
148 * or the character following P2 in P1 is "/".
150 if (path
== restriction
)
152 size_t prefix_length
= restriction
.size();
153 if (prefix_length
> path
.size())
154 return false; // Can't be a prefix.
155 if (0 != path
.compare(0, prefix_length
, restriction
))
157 return restriction
[prefix_length
- 1] == '/' || path
[prefix_length
] == '/';
160 bool SdchDictionary::Expired() const {
161 return base::Time::Now() > expiration_
;