1f5d7753866da424540fbce31ce1a8166d3753ef
[WebKit-https.git] / Source / WebCore / Modules / fetch / FetchBodyOwner.cpp
1 /*
2  * Copyright (C) 2016 Canon Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted, provided that the following conditions
6  * are required to be met:
7  *
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  * 3.  Neither the name of Canon Inc. nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "FetchBodyOwner.h"
31
32 #include "FetchLoader.h"
33 #include "HTTPParsers.h"
34 #include "JSBlob.h"
35 #include "ResourceResponse.h"
36
37 namespace WebCore {
38
39 FetchBodyOwner::FetchBodyOwner(ScriptExecutionContext& context, std::optional<FetchBody>&& body, Ref<FetchHeaders>&& headers)
40     : ActiveDOMObject(&context)
41     , m_body(WTFMove(body))
42     , m_headers(WTFMove(headers))
43 {
44     suspendIfNeeded();
45 }
46
47 void FetchBodyOwner::stop()
48 {
49     if (m_body)
50         m_body->cleanConsumePromise();
51
52     if (m_blobLoader) {
53         bool isUniqueReference = hasOneRef();
54         if (m_blobLoader->loader)
55             m_blobLoader->loader->stop();
56         // After that point, 'this' may be destroyed, since unsetPendingActivity should have been called.
57         ASSERT_UNUSED(isUniqueReference, isUniqueReference || !m_blobLoader);
58     }
59 }
60
61 bool FetchBodyOwner::isDisturbedOrLocked() const
62 {
63     if (m_isDisturbed)
64         return true;
65
66 #if ENABLE(STREAMS_API)
67     if (m_readableStreamSource && m_readableStreamSource->isReadableStreamLocked())
68         return true;
69 #endif
70
71     return false;
72 }
73
74 void FetchBodyOwner::arrayBuffer(Ref<DeferredPromise>&& promise)
75 {
76     if (isBodyNull()) {
77         fulfillPromiseWithArrayBuffer(WTFMove(promise), nullptr, 0);
78         return;
79     }
80     if (isDisturbedOrLocked()) {
81         promise->reject(TypeError);
82         return;
83     }
84     m_isDisturbed = true;
85     m_body->arrayBuffer(*this, WTFMove(promise));
86 }
87
88 void FetchBodyOwner::blob(Ref<DeferredPromise>&& promise)
89 {
90     if (isBodyNull()) {
91         promise->resolve<IDLInterface<Blob>>(Blob::create({ }, Blob::normalizedContentType(extractMIMETypeFromMediaType(m_contentType))).get());
92         return;
93     }
94     if (isDisturbedOrLocked()) {
95         promise->reject(TypeError);
96         return;
97     }
98     m_isDisturbed = true;
99     m_body->blob(*this, WTFMove(promise), m_contentType);
100 }
101
102 void FetchBodyOwner::cloneBody(const FetchBodyOwner& owner)
103 {
104     m_contentType = owner.m_contentType;
105     if (owner.isBodyNull())
106         return;
107     m_body = owner.m_body->clone();
108 }
109
110 void FetchBodyOwner::extractBody(ScriptExecutionContext& context, FetchBody::Init&& value)
111 {
112     m_body = FetchBody::extract(context, WTFMove(value), m_contentType);
113 }
114
115 void FetchBodyOwner::updateContentType()
116 {
117     String contentType = m_headers->fastGet(HTTPHeaderName::ContentType);
118     if (!contentType.isNull()) {
119         m_contentType = WTFMove(contentType);
120         return;
121     }
122     if (!m_contentType.isNull())
123         m_headers->fastSet(HTTPHeaderName::ContentType, m_contentType);
124 }
125
126 void FetchBodyOwner::consumeOnceLoadingFinished(FetchBodyConsumer::Type type, Ref<DeferredPromise>&& promise)
127 {
128     if (isDisturbedOrLocked()) {
129         promise->reject(TypeError);
130         return;
131     }
132     m_isDisturbed = true;
133     m_body->consumeOnceLoadingFinished(type, WTFMove(promise), m_contentType);
134 }
135
136 void FetchBodyOwner::formData(Ref<DeferredPromise>&& promise)
137 {
138     if (isBodyNull()) {
139         promise->reject();
140         return;
141     }
142     if (isDisturbedOrLocked()) {
143         promise->reject(TypeError);
144         return;
145     }
146     m_isDisturbed = true;
147     m_body->formData(*this, WTFMove(promise));
148 }
149
150 void FetchBodyOwner::json(Ref<DeferredPromise>&& promise)
151 {
152     if (isBodyNull()) {
153         promise->reject(SyntaxError);
154         return;
155     }
156     if (isDisturbedOrLocked()) {
157         promise->reject(TypeError);
158         return;
159     }
160     m_isDisturbed = true;
161     m_body->json(*this, WTFMove(promise));
162 }
163
164 void FetchBodyOwner::text(Ref<DeferredPromise>&& promise)
165 {
166     if (isBodyNull()) {
167         promise->resolve<IDLDOMString>({ });
168         return;
169     }
170     if (isDisturbedOrLocked()) {
171         promise->reject(TypeError);
172         return;
173     }
174     m_isDisturbed = true;
175     m_body->text(*this, WTFMove(promise));
176 }
177
178 void FetchBodyOwner::loadBlob(const Blob& blob, FetchBodyConsumer* consumer)
179 {
180     // Can only be called once for a body instance.
181     ASSERT(isDisturbed());
182     ASSERT(!m_blobLoader);
183     ASSERT(!isBodyNull());
184
185     if (!scriptExecutionContext()) {
186         m_body->loadingFailed();
187         return;
188     }
189
190     m_blobLoader.emplace(*this);
191     m_blobLoader->loader = std::make_unique<FetchLoader>(*m_blobLoader, consumer);
192
193     m_blobLoader->loader->start(*scriptExecutionContext(), blob);
194     if (!m_blobLoader->loader->isStarted()) {
195         m_body->loadingFailed();
196         m_blobLoader = std::nullopt;
197         return;
198     }
199     setPendingActivity(this);
200 }
201
202 void FetchBodyOwner::finishBlobLoading()
203 {
204     ASSERT(m_blobLoader);
205
206     m_blobLoader = std::nullopt;
207     unsetPendingActivity(this);
208 }
209
210 void FetchBodyOwner::blobLoadingSucceeded()
211 {
212     ASSERT(!isBodyNull());
213 #if ENABLE(STREAMS_API)
214     if (m_readableStreamSource) {
215         m_readableStreamSource->close();
216         m_readableStreamSource = nullptr;
217     }
218 #endif
219     m_body->loadingSucceeded();
220     finishBlobLoading();
221 }
222
223 void FetchBodyOwner::blobLoadingFailed()
224 {
225     ASSERT(!isBodyNull());
226 #if ENABLE(STREAMS_API)
227     if (m_readableStreamSource) {
228         if (!m_readableStreamSource->isCancelling())
229             m_readableStreamSource->error(ASCIILiteral("Blob loading failed"));
230         m_readableStreamSource = nullptr;
231     } else
232 #endif
233         m_body->loadingFailed();
234
235     finishBlobLoading();
236 }
237
238 void FetchBodyOwner::blobChunk(const char* data, size_t size)
239 {
240     ASSERT(data);
241 #if ENABLE(STREAMS_API)
242     ASSERT(m_readableStreamSource);
243     if (!m_readableStreamSource->enqueue(ArrayBuffer::tryCreate(data, size)))
244         stop();
245 #else
246     UNUSED_PARAM(data);
247     UNUSED_PARAM(size);
248 #endif
249 }
250
251 FetchBodyOwner::BlobLoader::BlobLoader(FetchBodyOwner& owner)
252     : owner(owner)
253 {
254 }
255
256 void FetchBodyOwner::BlobLoader::didReceiveResponse(const ResourceResponse& response)
257 {
258     if (response.httpStatusCode() != 200)
259         didFail();
260 }
261
262 void FetchBodyOwner::BlobLoader::didFail()
263 {
264     // didFail might be called within FetchLoader::start call.
265     if (loader->isStarted())
266         owner.blobLoadingFailed();
267 }
268
269 } // namespace WebCore