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