1 | /* |
2 | * Copyright (C) 2017 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "ServiceWorkerRegistrationKey.h" |
28 | |
29 | #if ENABLE(SERVICE_WORKER) |
30 | |
31 | #include "SecurityOrigin.h" |
32 | #include <wtf/URLHash.h> |
33 | |
34 | namespace WebCore { |
35 | |
36 | ServiceWorkerRegistrationKey::ServiceWorkerRegistrationKey(SecurityOriginData&& topOrigin, URL&& scope) |
37 | : m_topOrigin(WTFMove(topOrigin)) |
38 | , m_scope(WTFMove(scope)) |
39 | { |
40 | ASSERT(!m_scope.hasFragment()); |
41 | } |
42 | |
43 | ServiceWorkerRegistrationKey ServiceWorkerRegistrationKey::emptyKey() |
44 | { |
45 | return { }; |
46 | } |
47 | |
48 | unsigned ServiceWorkerRegistrationKey::hash() const |
49 | { |
50 | unsigned hashes[2]; |
51 | hashes[0] = SecurityOriginDataHash::hash(m_topOrigin); |
52 | hashes[1] = StringHash::hash(m_scope); |
53 | |
54 | return StringHasher::hashMemory(hashes, sizeof(hashes)); |
55 | } |
56 | |
57 | bool ServiceWorkerRegistrationKey::operator==(const ServiceWorkerRegistrationKey& other) const |
58 | { |
59 | return m_topOrigin == other.m_topOrigin && m_scope == other.m_scope; |
60 | } |
61 | |
62 | ServiceWorkerRegistrationKey ServiceWorkerRegistrationKey::isolatedCopy() const |
63 | { |
64 | return { m_topOrigin.isolatedCopy(), m_scope.isolatedCopy() }; |
65 | } |
66 | |
67 | bool ServiceWorkerRegistrationKey::isMatching(const SecurityOriginData& topOrigin, const URL& clientURL) const |
68 | { |
69 | return originIsMatching(topOrigin, clientURL) && clientURL.string().startsWith(m_scope); |
70 | } |
71 | |
72 | bool ServiceWorkerRegistrationKey::originIsMatching(const SecurityOriginData& topOrigin, const URL& clientURL) const |
73 | { |
74 | if (topOrigin != m_topOrigin) |
75 | return false; |
76 | |
77 | return protocolHostAndPortAreEqual(clientURL, m_scope); |
78 | } |
79 | |
80 | bool ServiceWorkerRegistrationKey::relatesToOrigin(const SecurityOriginData& securityOrigin) const |
81 | { |
82 | if (m_topOrigin == securityOrigin) |
83 | return true; |
84 | |
85 | return SecurityOriginData::fromURL(m_scope) == securityOrigin; |
86 | } |
87 | |
88 | static const char separatorCharacter = '_'; |
89 | |
90 | String ServiceWorkerRegistrationKey::toDatabaseKey() const |
91 | { |
92 | if (m_topOrigin.port) |
93 | return makeString(m_topOrigin.protocol, separatorCharacter, m_topOrigin.host, separatorCharacter, String::number(m_topOrigin.port.value()), separatorCharacter, m_scope.string()); |
94 | return makeString(m_topOrigin.protocol, separatorCharacter, m_topOrigin.host, separatorCharacter, separatorCharacter, m_scope.string()); |
95 | } |
96 | |
97 | Optional<ServiceWorkerRegistrationKey> ServiceWorkerRegistrationKey::fromDatabaseKey(const String& key) |
98 | { |
99 | auto first = key.find(separatorCharacter, 0); |
100 | auto second = key.find(separatorCharacter, first + 1); |
101 | auto third = key.find(separatorCharacter, second + 1); |
102 | |
103 | if (first == second || second == third) |
104 | return WTF::nullopt; |
105 | |
106 | Optional<uint16_t> shortPort; |
107 | |
108 | // If there's a gap between third and second, we expect to have a port to decode |
109 | if (third - second > 1) { |
110 | bool ok; |
111 | unsigned port; |
112 | if (key.is8Bit()) |
113 | port = charactersToUIntStrict(key.characters8() + second + 1, third - second - 1 , &ok); |
114 | else |
115 | port = charactersToUIntStrict(key.characters16() + second + 1, third - second - 1, &ok); |
116 | |
117 | if (!ok) |
118 | return WTF::nullopt; |
119 | |
120 | if (port > std::numeric_limits<uint16_t>::max()) |
121 | return WTF::nullopt; |
122 | |
123 | shortPort = static_cast<uint16_t>(port); |
124 | } |
125 | |
126 | auto scope = URL { URL(), key.substring(third + 1) }; |
127 | if (!scope.isValid()) |
128 | return WTF::nullopt; |
129 | |
130 | return ServiceWorkerRegistrationKey { { key.substring(0, first), key.substring(first + 1, second - first - 1), shortPort }, WTFMove(scope) }; |
131 | } |
132 | |
133 | #if !LOG_DISABLED |
134 | String ServiceWorkerRegistrationKey::loggingString() const |
135 | { |
136 | return makeString(m_topOrigin.debugString(), "-" , m_scope.string()); |
137 | } |
138 | #endif |
139 | |
140 | } // namespace WebCore |
141 | |
142 | #endif // ENABLE(SERVICE_WORKER) |
143 | |