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 "APIHTTPCookieStore.h"
28
29#include "APIWebsiteDataStore.h"
30#include "WebCookieManagerProxy.h"
31#include "WebProcessPool.h"
32#include <WebCore/Cookie.h>
33#include <WebCore/CookieStorage.h>
34#include <WebCore/NetworkStorageSession.h>
35
36using namespace WebKit;
37
38namespace API {
39
40HTTPCookieStore::HTTPCookieStore(WebKit::WebsiteDataStore& websiteDataStore)
41 : m_owningDataStore(websiteDataStore)
42{
43 if (!m_owningDataStore->processPoolForCookieStorageOperations())
44 registerForNewProcessPoolNotifications();
45}
46
47HTTPCookieStore::~HTTPCookieStore()
48{
49 ASSERT(m_observers.isEmpty());
50 ASSERT(!m_observedCookieManagerProxy);
51 ASSERT(!m_cookieManagerProxyObserver);
52
53 unregisterForNewProcessPoolNotifications();
54}
55
56void HTTPCookieStore::cookies(CompletionHandler<void(const Vector<WebCore::Cookie>&)>&& completionHandler)
57{
58 auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
59 if (!pool) {
60 Vector<WebCore::Cookie> allCookies;
61 if (m_owningDataStore->sessionID() == PAL::SessionID::defaultSessionID())
62 allCookies = getAllDefaultUIProcessCookieStoreCookies();
63 allCookies.appendVector(m_owningDataStore->pendingCookies());
64
65 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), allCookies] () mutable {
66 completionHandler(allCookies);
67 });
68 return;
69 }
70
71 auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
72 cookieManager->getAllCookies(m_owningDataStore->sessionID(), [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] (const Vector<WebCore::Cookie>& cookies, CallbackBase::Error error) mutable {
73 completionHandler(cookies);
74 });
75}
76
77void HTTPCookieStore::setCookies(const Vector<WebCore::Cookie>& cookies, CompletionHandler<void()>&& completionHandler)
78{
79 auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
80 if (!pool) {
81 for (auto& cookie : cookies) {
82 // FIXME: pendingCookies used for defaultSession because session cookies cannot be propagated to Network Process with uiProcessCookieStorageIdentifier.
83 if (m_owningDataStore->sessionID() == PAL::SessionID::defaultSessionID() && !cookie.session)
84 setCookieInDefaultUIProcessCookieStore(cookie);
85 else
86 m_owningDataStore->addPendingCookie(cookie);
87 }
88
89 RunLoop::main().dispatch(WTFMove(completionHandler));
90 return;
91 }
92
93 auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
94 cookieManager->setCookies(m_owningDataStore->sessionID(), cookies, [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] (CallbackBase::Error error) mutable {
95 completionHandler();
96 });
97}
98
99void HTTPCookieStore::deleteCookie(const WebCore::Cookie& cookie, CompletionHandler<void()>&& completionHandler)
100{
101 auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
102 if (!pool) {
103 if (m_owningDataStore->sessionID() == PAL::SessionID::defaultSessionID() && !cookie.session)
104 deleteCookieFromDefaultUIProcessCookieStore(cookie);
105 else
106 m_owningDataStore->removePendingCookie(cookie);
107
108 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] () mutable {
109 completionHandler();
110 });
111 return;
112 }
113
114 auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
115 cookieManager->deleteCookie(m_owningDataStore->sessionID(), cookie, [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)](CallbackBase::Error error) mutable {
116 completionHandler();
117 });
118}
119
120class APIWebCookieManagerProxyObserver : public WebCookieManagerProxy::Observer {
121 WTF_MAKE_FAST_ALLOCATED;
122public:
123 explicit APIWebCookieManagerProxyObserver(API::HTTPCookieStore& cookieStore)
124 : m_cookieStore(cookieStore)
125 {
126 }
127
128private:
129 void cookiesDidChange() final
130 {
131 m_cookieStore.cookiesDidChange();
132 }
133
134 void managerDestroyed() final
135 {
136 m_cookieStore.cookieManagerDestroyed();
137 }
138
139 API::HTTPCookieStore& m_cookieStore;
140};
141
142void HTTPCookieStore::registerObserver(Observer& observer)
143{
144 m_observers.add(&observer);
145
146 if (m_cookieManagerProxyObserver)
147 return;
148
149 ASSERT(!m_observedCookieManagerProxy);
150
151 m_cookieManagerProxyObserver = std::make_unique<APIWebCookieManagerProxyObserver>(*this);
152
153 auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
154
155 if (!pool) {
156 ASSERT(!m_observingUIProcessCookies);
157
158 // Listen for cookie notifications in the UIProcess in the meantime.
159 startObservingChangesToDefaultUIProcessCookieStore([this] () {
160 cookiesDidChange();
161 });
162
163 m_observingUIProcessCookies = true;
164 return;
165 }
166
167 m_observedCookieManagerProxy = pool->supplement<WebKit::WebCookieManagerProxy>();
168 m_observedCookieManagerProxy->registerObserver(m_owningDataStore->sessionID(), *m_cookieManagerProxyObserver);
169}
170
171void HTTPCookieStore::unregisterObserver(Observer& observer)
172{
173 m_observers.remove(&observer);
174
175 if (!m_observers.isEmpty())
176 return;
177
178 if (m_observedCookieManagerProxy)
179 m_observedCookieManagerProxy->unregisterObserver(m_owningDataStore->sessionID(), *m_cookieManagerProxyObserver);
180
181 if (m_observingUIProcessCookies)
182 stopObservingChangesToDefaultUIProcessCookieStore();
183
184 if (m_processPoolCreationListenerIdentifier)
185 WebProcessPool::unregisterProcessPoolCreationListener(m_processPoolCreationListenerIdentifier);
186
187 m_processPoolCreationListenerIdentifier = 0;
188 m_observedCookieManagerProxy = nullptr;
189 m_cookieManagerProxyObserver = nullptr;
190 m_observingUIProcessCookies = false;
191}
192
193void HTTPCookieStore::cookiesDidChange()
194{
195 for (auto* observer : m_observers)
196 observer->cookiesDidChange(*this);
197}
198
199void HTTPCookieStore::cookieManagerDestroyed()
200{
201 m_observedCookieManagerProxy->unregisterObserver(m_owningDataStore->sessionID(), *m_cookieManagerProxyObserver);
202 m_observedCookieManagerProxy = nullptr;
203
204 auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
205
206 if (!pool)
207 return;
208
209 m_observedCookieManagerProxy = pool->supplement<WebKit::WebCookieManagerProxy>();
210 m_observedCookieManagerProxy->registerObserver(m_owningDataStore->sessionID(), *m_cookieManagerProxyObserver);
211}
212
213void HTTPCookieStore::registerForNewProcessPoolNotifications()
214{
215 ASSERT(!m_processPoolCreationListenerIdentifier);
216
217 m_processPoolCreationListenerIdentifier = WebProcessPool::registerProcessPoolCreationListener([this](WebProcessPool& newProcessPool) {
218 if (!m_owningDataStore->isAssociatedProcessPool(newProcessPool))
219 return;
220
221 // Now that an associated process pool exists, we need to flush the UI process cookie store
222 // to make sure any changes are reflected within the new process pool.
223 flushDefaultUIProcessCookieStore();
224 newProcessPool.ensureNetworkProcess();
225
226 if (m_cookieManagerProxyObserver) {
227 m_observedCookieManagerProxy = newProcessPool.supplement<WebKit::WebCookieManagerProxy>();
228 m_observedCookieManagerProxy->registerObserver(m_owningDataStore->sessionID(), *m_cookieManagerProxyObserver);
229 }
230 unregisterForNewProcessPoolNotifications();
231 });
232}
233
234void HTTPCookieStore::unregisterForNewProcessPoolNotifications()
235{
236 if (m_processPoolCreationListenerIdentifier)
237 WebProcessPool::unregisterProcessPoolCreationListener(m_processPoolCreationListenerIdentifier);
238
239 m_processPoolCreationListenerIdentifier = 0;
240}
241
242#if !PLATFORM(COCOA)
243void HTTPCookieStore::flushDefaultUIProcessCookieStore() { }
244Vector<WebCore::Cookie> HTTPCookieStore::getAllDefaultUIProcessCookieStoreCookies() { return { }; }
245void HTTPCookieStore::setCookieInDefaultUIProcessCookieStore(const WebCore::Cookie&) { }
246void HTTPCookieStore::deleteCookieFromDefaultUIProcessCookieStore(const WebCore::Cookie&) { }
247void HTTPCookieStore::startObservingChangesToDefaultUIProcessCookieStore(Function<void()>&&) { }
248void HTTPCookieStore::stopObservingChangesToDefaultUIProcessCookieStore() { }
249#endif
250
251} // namespace API
252