OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "core/frame/csp/CSPSource.h" | 5 #include "core/frame/csp/CSPSource.h" |
6 | 6 |
7 #include "core/frame/UseCounter.h" | 7 #include "core/frame/UseCounter.h" |
8 #include "core/frame/csp/ContentSecurityPolicy.h" | 8 #include "core/frame/csp/ContentSecurityPolicy.h" |
9 #include "platform/weborigin/KURL.h" | 9 #include "platform/weborigin/KURL.h" |
10 #include "platform/weborigin/KnownPorts.h" | 10 #include "platform/weborigin/KnownPorts.h" |
(...skipping 24 matching lines...) Expand all Loading... | |
35 if (isSchemeOnly()) | 35 if (isSchemeOnly()) |
36 return true; | 36 return true; |
37 bool pathsMatch = | 37 bool pathsMatch = |
38 (redirectStatus == RedirectStatus::FollowedRedirect) || pathMatches(url); | 38 (redirectStatus == RedirectStatus::FollowedRedirect) || pathMatches(url); |
39 return hostMatches(url) && portMatches(url) && pathsMatch; | 39 return hostMatches(url) && portMatches(url) && pathsMatch; |
40 } | 40 } |
41 | 41 |
42 bool CSPSource::schemeMatches(const KURL& url) const { | 42 bool CSPSource::schemeMatches(const KURL& url) const { |
43 if (m_scheme.isEmpty()) | 43 if (m_scheme.isEmpty()) |
44 return m_policy->protocolMatchesSelf(url); | 44 return m_policy->protocolMatchesSelf(url); |
45 if (equalIgnoringCase(m_scheme, "http")) | 45 return schemeMatches(url.protocol()); |
46 return equalIgnoringCase(url.protocol(), "http") || | 46 } |
47 equalIgnoringCase(url.protocol(), "https"); | 47 |
48 if (equalIgnoringCase(m_scheme, "ws")) | 48 bool CSPSource::schemeMatches(const String& protocol) const { |
49 return equalIgnoringCase(url.protocol(), "ws") || | 49 // TODO(amalika): DCHECK schemes are lower case & remove calls to |
50 equalIgnoringCase(url.protocol(), "wss"); | 50 // equalIgnoringCase |
51 return equalIgnoringCase(url.protocol(), m_scheme); | 51 if (equalIgnoringCase(m_scheme, "http")) { |
52 return equalIgnoringCase(protocol, "http") || | |
53 equalIgnoringCase(protocol, "https"); | |
54 } | |
55 if (equalIgnoringCase(m_scheme, "ws")) { | |
56 return equalIgnoringCase(protocol, "ws") || | |
57 equalIgnoringCase(protocol, "wss"); | |
58 } | |
59 return equalIgnoringCase(protocol, m_scheme); | |
52 } | 60 } |
53 | 61 |
54 bool CSPSource::hostMatches(const KURL& url) const { | 62 bool CSPSource::hostMatches(const KURL& url) const { |
55 const String& host = url.host(); | 63 return hostMatches(url.host()); |
64 } | |
65 | |
66 bool CSPSource::hostMatches(const String& host) const { | |
56 Document* document = m_policy->document(); | 67 Document* document = m_policy->document(); |
57 bool match; | 68 bool match; |
58 | 69 |
59 bool equalHosts = equalIgnoringCase(host, m_host); | 70 bool equalHosts = equalIgnoringCase(host, m_host); |
60 if (m_hostWildcard == HasWildcard) { | 71 if (m_hostWildcard == HasWildcard) { |
61 match = host.endsWith(String("." + m_host), TextCaseInsensitive); | 72 match = host.endsWith(String("." + m_host), TextCaseInsensitive); |
62 | 73 |
63 // Chrome used to, incorrectly, match *.x.y to x.y. This was fixed, but | 74 // Chrome used to, incorrectly, match *.x.y to x.y. This was fixed, but |
64 // the following count measures when a match fails that would have | 75 // the following count measures when a match fails that would have |
65 // passed the old, incorrect style, in case a lot of sites were | 76 // passed the old, incorrect style, in case a lot of sites were |
66 // relying on that behavior. | 77 // relying on that behavior. |
67 if (document && equalHosts) | 78 if (document && equalHosts) |
68 UseCounter::count(*document, | 79 UseCounter::count(*document, |
69 UseCounter::CSPSourceWildcardWouldMatchExactHost); | 80 UseCounter::CSPSourceWildcardWouldMatchExactHost); |
70 } else { | 81 } else { |
71 match = equalHosts; | 82 match = equalHosts; |
72 } | 83 } |
73 | 84 |
74 return match; | 85 return match; |
75 } | 86 } |
76 | 87 |
77 bool CSPSource::pathMatches(const KURL& url) const { | 88 bool CSPSource::pathMatches(const KURL& url) const { |
89 return pathMatches(url.path()); | |
90 } | |
91 | |
92 bool CSPSource::pathMatches(const String& urlPath) const { | |
78 if (m_path.isEmpty()) | 93 if (m_path.isEmpty()) |
79 return true; | 94 return true; |
80 | 95 |
81 String path = decodeURLEscapeSequences(url.path()); | 96 String path = decodeURLEscapeSequences(urlPath); |
82 | 97 |
83 if (m_path.endsWith("/")) | 98 if (m_path.endsWith("/")) |
84 return path.startsWith(m_path); | 99 return path.startsWith(m_path); |
85 | 100 |
86 return path == m_path; | 101 return path == m_path; |
87 } | 102 } |
88 | 103 |
89 bool CSPSource::portMatches(const KURL& url) const { | 104 bool CSPSource::portMatches(const KURL& url) const { |
105 return portMatches(url.port(), url.protocol()); | |
106 } | |
107 | |
108 bool CSPSource::portMatches(int port, const String& protocol) const { | |
90 if (m_portWildcard == HasWildcard) | 109 if (m_portWildcard == HasWildcard) |
91 return true; | 110 return true; |
92 | 111 |
93 int port = url.port(); | |
94 | |
95 if (port == m_port) | 112 if (port == m_port) |
96 return true; | 113 return true; |
97 | 114 |
98 if (m_port == 80 && | 115 if (m_port == 80 && |
99 (port == 443 || | 116 (port == 443 || (port == 0 && defaultPortForProtocol(protocol) == 443))) |
100 (port == 0 && defaultPortForProtocol(url.protocol()) == 443))) | |
101 return true; | 117 return true; |
102 | 118 |
103 if (!port) | 119 if (!port) |
104 return isDefaultPortForProtocol(m_port, url.protocol()); | 120 return isDefaultPortForProtocol(m_port, protocol); |
105 | 121 |
106 if (!m_port) | 122 if (!m_port) |
107 return isDefaultPortForProtocol(port, url.protocol()); | 123 return isDefaultPortForProtocol(port, protocol); |
108 | 124 |
109 return false; | 125 return false; |
110 } | 126 } |
111 | 127 |
128 bool CSPSource::isSimilar(CSPSource* other) { | |
129 bool schemesMatch = schemeMatches(other->m_scheme) || | |
130 (equalIgnoringCase(m_scheme, "https") && | |
Mike West
2016/10/26 11:40:29
Nit: DCHECK_EQ(m_scheme, m_scheme.lower()), and re
| |
131 equalIgnoringCase(other->m_scheme, "http")) || | |
132 (equalIgnoringCase(m_scheme, "wss") && | |
133 equalIgnoringCase(other->m_scheme, "ws")); | |
134 bool schemesOnly = isSchemeOnly() || other->isSchemeOnly(); | |
135 bool hostsMatch = | |
136 schemesOnly || equalIgnoringCase(m_host, other->m_host) || | |
137 (m_hostWildcard == HasWildcard && hostMatches(other->m_host)) || | |
138 (other->m_hostWildcard == HasWildcard && other->hostMatches(m_host)); | |
Mike West
2016/10/26 11:40:29
Isn't the wildcard work done in `hostMatches()`? C
amalika
2016/10/27 09:50:47
Unfortunately, this does not work when both hosts
| |
139 bool portsMatch = schemesOnly || m_portWildcard == HasWildcard || | |
140 other->m_portWildcard == HasWildcard || | |
141 portMatches(other->m_port, other->m_scheme); | |
Mike West
2016/10/26 11:40:29
Isn't the wildcard work done in `portMatches()`?
amalika
2016/10/27 09:50:48
It does not work for when there are wildcards in b
| |
142 bool pathsMatch = other->m_path.isEmpty() || other->m_path == "/" || | |
Mike West
2016/10/26 11:40:29
Nit: This matches if `schemesOnly` too, right? If
| |
143 pathMatches(other->m_path); | |
144 if (schemesMatch && hostsMatch && portsMatch && pathsMatch) | |
145 return true; | |
146 | |
147 return false; | |
148 } | |
149 | |
150 CSPSource* CSPSource::getCommon(CSPSource* other) { | |
151 if (!isSimilar(other)) | |
152 return nullptr; | |
153 | |
154 bool preferABasedOnScheme = false; | |
155 // If the schemes match but their lengths are not equal, that means one of the | |
156 // schemes is 'https' or 'wss' | |
157 if (m_scheme.length() != other->m_scheme.length()) { | |
158 String aScheme = m_scheme.lower(); | |
159 preferABasedOnScheme = | |
160 aScheme.length() > 3 ? (aScheme == "https") : (aScheme == "wss"); | |
161 } | |
162 | |
163 bool preferABasedOnPort = (m_port && !other->m_port); | |
164 bool preferABasedOnPath = (!(m_path.isEmpty() || m_path == "/") && | |
165 (other->m_path.isEmpty() || other->m_path == "/")); | |
166 | |
167 String scheme = preferABasedOnScheme ? m_scheme : other->m_scheme; | |
168 String host = (m_hostWildcard == HasWildcard) ? other->m_host : m_host; | |
169 String path = preferABasedOnPath ? m_path : other->m_path; | |
170 int port = preferABasedOnPort ? m_port : other->m_port; | |
171 WildcardDisposition hostWildcard = | |
172 (m_hostWildcard == HasWildcard) ? other->m_hostWildcard : m_hostWildcard; | |
173 WildcardDisposition portWildcard = | |
174 (m_portWildcard == HasWildcard) ? other->m_portWildcard : m_portWildcard; | |
175 return new CSPSource(m_policy, scheme, host, port, path, hostWildcard, | |
176 portWildcard); | |
177 } | |
178 | |
179 bool CSPSource::isSubsumed(CSPSource* other) { | |
180 if (!isSimilar(other)) | |
181 return false; | |
182 | |
183 if (other->isSchemeOnly()) { | |
184 if (other->m_scheme.length() == m_scheme.length()) | |
185 return true; | |
186 return m_scheme.length() == 3 || m_scheme.length() == 5 ? true : false; | |
187 } | |
188 | |
189 if (isSchemeOnly()) | |
190 return false; | |
191 | |
192 if ((m_hostWildcard == HasWildcard && other->m_hostWildcard == NoWildcard) || | |
193 (m_portWildcard == HasWildcard && other->m_portWildcard == NoWildcard)) { | |
194 return false; | |
195 } | |
196 | |
197 bool preferABasedOnScheme = false, preferBBasedOnScheme = false; | |
198 // If the schemes match but their lengths are not equal, that means one of the | |
199 // schemes is 'https' or 'wss' | |
200 if (m_scheme.length() != other->m_scheme.length()) { | |
201 String aScheme = m_scheme.lower(); | |
202 preferABasedOnScheme = | |
203 aScheme.length() > 3 ? (aScheme == "https") : (aScheme == "wss"); | |
204 preferBBasedOnScheme = !preferABasedOnScheme; | |
205 } | |
206 | |
207 bool preferABasedOnPort = (m_port && !other->m_port), | |
208 preferBBasedOnPort = (!m_port && other->m_port); | |
209 bool preferABasedOnPath = (!(m_path.isEmpty() || m_path == "/") && | |
210 (other->m_path.isEmpty() || other->m_path == "/")), | |
211 preferBBasedOnPath = | |
212 ((m_path.isEmpty() || m_path == "/") && | |
213 !(other->m_path.isEmpty() || other->m_path == "/")); | |
214 | |
215 bool preferA = | |
216 preferABasedOnPort || preferABasedOnPath || preferABasedOnScheme; | |
217 bool preferB = | |
218 preferBBasedOnPort || preferBBasedOnPath || preferBBasedOnScheme; | |
219 | |
220 if (preferA & preferB) | |
221 return false; | |
222 | |
223 if (preferA || preferB) | |
224 return preferA ? true : false; | |
225 | |
226 return true; | |
227 } | |
228 | |
112 bool CSPSource::isSchemeOnly() const { | 229 bool CSPSource::isSchemeOnly() const { |
113 return m_host.isEmpty(); | 230 return m_host.isEmpty(); |
114 } | 231 } |
115 | 232 |
116 DEFINE_TRACE(CSPSource) { | 233 DEFINE_TRACE(CSPSource) { |
117 visitor->trace(m_policy); | 234 visitor->trace(m_policy); |
118 } | 235 } |
119 | 236 |
120 } // namespace blink | 237 } // namespace blink |
OLD | NEW |