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 "WebServiceWorkerFetchTaskClient.h"
28
29#if ENABLE(SERVICE_WORKER)
30
31#include "DataReference.h"
32#include "FormDataReference.h"
33#include "ServiceWorkerFetchTaskMessages.h"
34#include "SharedBufferDataReference.h"
35#include "WebCoreArgumentCoders.h"
36#include "WebErrors.h"
37#include <WebCore/ResourceError.h>
38#include <WebCore/ResourceResponse.h>
39#include <WebCore/SWContextManager.h>
40#include <wtf/RunLoop.h>
41
42namespace WebKit {
43using namespace WebCore;
44
45WebServiceWorkerFetchTaskClient::WebServiceWorkerFetchTaskClient(Ref<IPC::Connection>&& connection, WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, WebCore::SWServerConnectionIdentifier serverConnectionIdentifier, FetchIdentifier fetchIdentifier, bool needsContinueDidReceiveResponseMessage)
46 : m_connection(WTFMove(connection))
47 , m_serverConnectionIdentifier(serverConnectionIdentifier)
48 , m_serviceWorkerIdentifier(serviceWorkerIdentifier)
49 , m_fetchIdentifier(fetchIdentifier)
50 , m_needsContinueDidReceiveResponseMessage(needsContinueDidReceiveResponseMessage)
51{
52}
53
54void WebServiceWorkerFetchTaskClient::didReceiveRedirection(const WebCore::ResourceResponse& response)
55{
56 if (!m_connection)
57 return;
58 m_connection->send(Messages::ServiceWorkerFetchTask::DidReceiveRedirectResponse { response }, m_fetchIdentifier);
59
60 cleanup();
61}
62
63void WebServiceWorkerFetchTaskClient::didReceiveResponse(const ResourceResponse& response)
64{
65 if (!m_connection)
66 return;
67
68 if (m_needsContinueDidReceiveResponseMessage)
69 m_waitingForContinueDidReceiveResponseMessage = true;
70
71 m_connection->send(Messages::ServiceWorkerFetchTask::DidReceiveResponse { response, m_needsContinueDidReceiveResponseMessage }, m_fetchIdentifier);
72}
73
74void WebServiceWorkerFetchTaskClient::didReceiveData(Ref<SharedBuffer>&& buffer)
75{
76 if (!m_connection)
77 return;
78
79 if (m_waitingForContinueDidReceiveResponseMessage) {
80 if (!WTF::holds_alternative<Ref<SharedBuffer>>(m_responseData))
81 m_responseData = buffer->copy();
82 else
83 WTF::get<Ref<SharedBuffer>>(m_responseData)->append(WTFMove(buffer));
84 return;
85 }
86
87 m_connection->send(Messages::ServiceWorkerFetchTask::DidReceiveData { { buffer }, static_cast<int64_t>(buffer->size()) }, m_fetchIdentifier);
88}
89
90void WebServiceWorkerFetchTaskClient::didReceiveFormDataAndFinish(Ref<FormData>&& formData)
91{
92 if (!m_connection)
93 return;
94
95 if (m_waitingForContinueDidReceiveResponseMessage) {
96 m_responseData = formData->isolatedCopy();
97 return;
98 }
99
100 // FIXME: We should send this form data to the other process and consume it there.
101 // For now and for the case of blobs, we read it there and send the data through IPC.
102 URL blobURL = formData->asBlobURL();
103 if (blobURL.isNull()) {
104 m_connection->send(Messages::ServiceWorkerFetchTask::DidReceiveFormData { IPC::FormDataReference { WTFMove(formData) } }, m_fetchIdentifier);
105 return;
106 }
107
108 callOnMainThread([this, protectedThis = makeRef(*this), blobURL = blobURL.isolatedCopy()] () {
109 auto* serviceWorkerThreadProxy = SWContextManager::singleton().serviceWorkerThreadProxy(m_serviceWorkerIdentifier);
110 if (!serviceWorkerThreadProxy) {
111 didFail(internalError(blobURL));
112 return;
113 }
114
115 m_blobLoader.emplace(*this);
116 auto loader = serviceWorkerThreadProxy->createBlobLoader(*m_blobLoader, blobURL);
117 if (!loader) {
118 m_blobLoader = WTF::nullopt;
119 didFail(internalError(blobURL));
120 return;
121 }
122
123 m_blobLoader->loader = WTFMove(loader);
124 });
125}
126
127void WebServiceWorkerFetchTaskClient::didReceiveBlobChunk(const char* data, size_t size)
128{
129 if (!m_connection)
130 return;
131
132 m_connection->send(Messages::ServiceWorkerFetchTask::DidReceiveData { { reinterpret_cast<const uint8_t*>(data), size }, static_cast<int64_t>(size) }, m_fetchIdentifier);
133}
134
135void WebServiceWorkerFetchTaskClient::didFinishBlobLoading()
136{
137 didFinish();
138
139 std::exchange(m_blobLoader, WTF::nullopt);
140}
141
142void WebServiceWorkerFetchTaskClient::didFail(const ResourceError& error)
143{
144 if (!m_connection)
145 return;
146
147 if (m_waitingForContinueDidReceiveResponseMessage) {
148 m_responseData = makeUniqueRef<ResourceError>(error.isolatedCopy());
149 return;
150 }
151
152 m_connection->send(Messages::ServiceWorkerFetchTask::DidFail { error }, m_fetchIdentifier);
153
154 cleanup();
155}
156
157void WebServiceWorkerFetchTaskClient::didFinish()
158{
159 if (!m_connection)
160 return;
161
162 if (m_waitingForContinueDidReceiveResponseMessage) {
163 m_didFinish = true;
164 return;
165 }
166
167 m_connection->send(Messages::ServiceWorkerFetchTask::DidFinish { }, m_fetchIdentifier);
168
169 cleanup();
170}
171
172void WebServiceWorkerFetchTaskClient::didNotHandle()
173{
174 if (!m_connection)
175 return;
176
177 m_connection->send(Messages::ServiceWorkerFetchTask::DidNotHandle { }, m_fetchIdentifier);
178
179 cleanup();
180}
181
182void WebServiceWorkerFetchTaskClient::cancel()
183{
184 m_connection = nullptr;
185}
186
187void WebServiceWorkerFetchTaskClient::continueDidReceiveResponse()
188{
189 if (!m_connection)
190 return;
191
192 m_waitingForContinueDidReceiveResponseMessage = false;
193
194 switchOn(m_responseData, [this](std::nullptr_t&) {
195 if (m_didFinish)
196 didFinish();
197 }, [this](Ref<SharedBuffer>& buffer) {
198 didReceiveData(WTFMove(buffer));
199 if (m_didFinish)
200 didFinish();
201 }, [this](Ref<FormData>& formData) {
202 didReceiveFormDataAndFinish(WTFMove(formData));
203 }, [this](UniqueRef<ResourceError>& error) {
204 didFail(error.get());
205 });
206 m_responseData = nullptr;
207}
208
209void WebServiceWorkerFetchTaskClient::cleanup()
210{
211 m_connection = nullptr;
212
213 if (!isMainThread()) {
214 callOnMainThread([protectedThis = makeRef(*this)] () {
215 protectedThis->cleanup();
216 });
217 return;
218 }
219 if (auto* serviceWorkerThreadProxy = SWContextManager::singleton().serviceWorkerThreadProxy(m_serviceWorkerIdentifier))
220 serviceWorkerThreadProxy->removeFetch(m_serverConnectionIdentifier, m_fetchIdentifier);
221}
222
223} // namespace WebKit
224
225#endif // ENABLE(SERVICE_WORKER)
226