1/*
2 * Copyright (C) 2011 Google, Inc. All rights reserved.
3 * Copyright (C) 2016 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "ContentSecurityPolicySource.h"
29
30#include "ContentSecurityPolicy.h"
31#include "SecurityOriginData.h"
32#include "TextEncoding.h"
33#include <wtf/URL.h>
34
35namespace WebCore {
36
37ContentSecurityPolicySource::ContentSecurityPolicySource(const ContentSecurityPolicy& policy, const String& scheme, const String& host, Optional<uint16_t> port, const String& path, bool hostHasWildcard, bool portHasWildcard)
38 : m_policy(policy)
39 , m_scheme(scheme)
40 , m_host(host)
41 , m_path(path)
42 , m_port(port)
43 , m_hostHasWildcard(hostHasWildcard)
44 , m_portHasWildcard(portHasWildcard)
45{
46}
47
48bool ContentSecurityPolicySource::matches(const URL& url, bool didReceiveRedirectResponse) const
49{
50 if (!schemeMatches(url))
51 return false;
52 if (isSchemeOnly())
53 return true;
54 return hostMatches(url) && portMatches(url) && (didReceiveRedirectResponse || pathMatches(url));
55}
56
57bool ContentSecurityPolicySource::schemeMatches(const URL& url) const
58{
59 if (m_scheme.isEmpty())
60 return m_policy.protocolMatchesSelf(url);
61 if (equalLettersIgnoringASCIICase(m_scheme, "http"))
62 return url.protocolIsInHTTPFamily();
63 return equalIgnoringASCIICase(url.protocol(), m_scheme);
64}
65
66static bool wildcardMatches(StringView host, const String& hostWithWildcard)
67{
68 auto hostLength = host.length();
69 auto hostWithWildcardLength = hostWithWildcard.length();
70 return host.endsWithIgnoringASCIICase(hostWithWildcard)
71 && hostLength > hostWithWildcardLength
72 && host[hostLength - hostWithWildcardLength - 1] == '.';
73}
74
75bool ContentSecurityPolicySource::hostMatches(const URL& url) const
76{
77 auto host = url.host();
78 return equalIgnoringASCIICase(host, m_host) || (m_hostHasWildcard && wildcardMatches(host, m_host));
79}
80
81bool ContentSecurityPolicySource::pathMatches(const URL& url) const
82{
83 if (m_path.isEmpty())
84 return true;
85
86 String path = decodeURLEscapeSequences(url.path());
87
88 if (m_path.endsWith("/"))
89 return path.startsWith(m_path);
90
91 return path == m_path;
92}
93
94bool ContentSecurityPolicySource::portMatches(const URL& url) const
95{
96 if (m_portHasWildcard)
97 return true;
98
99 Optional<uint16_t> port = url.port();
100
101 if (port == m_port)
102 return true;
103
104 if ((m_port && WTF::isDefaultPortForProtocol(m_port.value(), "http")) && ((!port && url.protocolIs("https")) || (port && WTF::isDefaultPortForProtocol(port.value(), "https"))))
105 return true;
106
107 if (!port)
108 return WTF::isDefaultPortForProtocol(m_port.value(), url.protocol());
109
110 if (!m_port)
111 return WTF::isDefaultPortForProtocol(port.value(), url.protocol());
112
113 return false;
114}
115
116bool ContentSecurityPolicySource::isSchemeOnly() const
117{
118 return m_host.isEmpty();
119}
120
121ContentSecurityPolicySource::operator SecurityOriginData() const
122{
123 return { m_scheme, m_host, m_port };
124}
125
126} // namespace WebCore
127