summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/fetch/FetchBody.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/Modules/fetch/FetchBody.cpp')
-rw-r--r--Source/WebCore/Modules/fetch/FetchBody.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/fetch/FetchBody.cpp b/Source/WebCore/Modules/fetch/FetchBody.cpp
new file mode 100644
index 000000000..8eb878cf0
--- /dev/null
+++ b/Source/WebCore/Modules/fetch/FetchBody.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2016 Canon Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions
+ * are required to be met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Canon Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FetchBody.h"
+
+#if ENABLE(FETCH_API)
+
+#include "Document.h"
+#include "FetchBodyOwner.h"
+#include "FetchHeaders.h"
+#include "FetchResponseSource.h"
+#include "HTTPHeaderValues.h"
+#include "HTTPParsers.h"
+#include "JSBlob.h"
+#include "JSDOMFormData.h"
+#include "JSReadableStream.h"
+#include "JSURLSearchParams.h"
+#include "ReadableStreamSource.h"
+#include <runtime/ArrayBufferView.h>
+
+namespace WebCore {
+
+std::optional<FetchBody> FetchBody::extract(ScriptExecutionContext& context, JSC::ExecState& state, JSC::JSValue value, String& contentType)
+{
+ JSC::VM& vm = state.vm();
+ if (value.inherits(vm, JSBlob::info())) {
+ auto& blob = *JSBlob::toWrapped(vm, value);
+ contentType = blob.type();
+ return FetchBody(blob);
+ }
+ if (value.inherits(vm, JSDOMFormData::info())) {
+ ASSERT(!context.isWorkerGlobalScope());
+ auto& domFormData = *JSDOMFormData::toWrapped(vm, value);
+ auto formData = FormData::createMultiPart(domFormData, domFormData.encoding(), &static_cast<Document&>(context));
+ contentType = makeString("multipart/form-data; boundary=", formData->boundary().data());
+ return FetchBody(WTFMove(formData));
+ }
+ if (value.isString()) {
+ contentType = HTTPHeaderValues::textPlainContentType();
+ return FetchBody(String { asString(value)->value(&state) });
+ }
+ if (value.inherits(vm, JSURLSearchParams::info())) {
+ contentType = HTTPHeaderValues::formURLEncodedContentType();
+ return FetchBody(*JSURLSearchParams::toWrapped(vm, value));
+ }
+ if (value.inherits(vm, JSReadableStream::info())) {
+ FetchBody body;
+ body.m_isReadableStream = true;
+ return WTFMove(body);
+ }
+ if (value.inherits(vm, JSC::JSArrayBuffer::info())) {
+ ArrayBuffer* data = toUnsharedArrayBuffer(vm, value);
+ ASSERT(data);
+ return FetchBody(*data);
+ }
+ if (value.inherits(vm, JSC::JSArrayBufferView::info()))
+ return FetchBody(toUnsharedArrayBufferView(vm, value).releaseConstNonNull());
+
+ return std::nullopt;
+}
+
+void FetchBody::arrayBuffer(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
+{
+ m_consumer.setType(FetchBodyConsumer::Type::ArrayBuffer);
+ consume(owner, WTFMove(promise));
+}
+
+void FetchBody::blob(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise, const String& contentType)
+{
+ m_consumer.setType(FetchBodyConsumer::Type::Blob);
+ m_consumer.setContentType(Blob::normalizedContentType(extractMIMETypeFromMediaType(contentType)));
+ consume(owner, WTFMove(promise));
+}
+
+void FetchBody::json(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
+{
+ if (isText()) {
+ fulfillPromiseWithJSON(WTFMove(promise), textBody());
+ return;
+ }
+ m_consumer.setType(FetchBodyConsumer::Type::JSON);
+ consume(owner, WTFMove(promise));
+}
+
+void FetchBody::text(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
+{
+ if (isText()) {
+ promise->resolve<IDLDOMString>(textBody());
+ return;
+ }
+ m_consumer.setType(FetchBodyConsumer::Type::Text);
+ consume(owner, WTFMove(promise));
+}
+
+void FetchBody::consumeOnceLoadingFinished(FetchBodyConsumer::Type type, Ref<DeferredPromise>&& promise)
+{
+ m_consumer.setType(type);
+ m_consumePromise = WTFMove(promise);
+}
+
+void FetchBody::consume(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
+{
+ if (isArrayBuffer()) {
+ consumeArrayBuffer(WTFMove(promise));
+ return;
+ }
+ if (isArrayBufferView()) {
+ consumeArrayBufferView(WTFMove(promise));
+ return;
+ }
+ if (isText()) {
+ consumeText(WTFMove(promise), textBody());
+ return;
+ }
+ if (isURLSearchParams()) {
+ consumeText(WTFMove(promise), urlSearchParamsBody().toString());
+ return;
+ }
+ if (isBlob()) {
+ consumeBlob(owner, WTFMove(promise));
+ return;
+ }
+ if (isFormData()) {
+ // FIXME: Support consuming FormData.
+ promise->reject();
+ return;
+ }
+ m_consumer.resolve(WTFMove(promise));
+}
+
+#if ENABLE(READABLE_STREAM_API)
+void FetchBody::consumeAsStream(FetchBodyOwner& owner, FetchResponseSource& source)
+{
+ bool closeStream = false;
+ if (isArrayBuffer()) {
+ closeStream = source.enqueue(ArrayBuffer::tryCreate(arrayBufferBody().data(), arrayBufferBody().byteLength()));
+ m_data = nullptr;
+ } else if (isArrayBufferView()) {
+ closeStream = source.enqueue(ArrayBuffer::tryCreate(arrayBufferViewBody().baseAddress(), arrayBufferViewBody().byteLength()));
+ m_data = nullptr;
+ } else if (isText()) {
+ auto data = UTF8Encoding().encode(textBody(), EntitiesForUnencodables);
+ closeStream = source.enqueue(ArrayBuffer::tryCreate(data.data(), data.length()));
+ m_data = nullptr;
+ } else if (isURLSearchParams()) {
+ auto data = UTF8Encoding().encode(urlSearchParamsBody().toString(), EntitiesForUnencodables);
+ closeStream = source.enqueue(ArrayBuffer::tryCreate(data.data(), data.length()));
+ m_data = nullptr;
+ } else if (isBlob()) {
+ owner.loadBlob(blobBody(), nullptr);
+ m_data = nullptr;
+ } else if (isFormData())
+ source.error(ASCIILiteral("not implemented"));
+ else if (m_consumer.hasData())
+ closeStream = source.enqueue(m_consumer.takeAsArrayBuffer());
+ else
+ closeStream = true;
+
+ if (closeStream)
+ source.close();
+}
+#endif
+
+void FetchBody::consumeArrayBuffer(Ref<DeferredPromise>&& promise)
+{
+ m_consumer.resolveWithData(WTFMove(promise), static_cast<const uint8_t*>(arrayBufferBody().data()), arrayBufferBody().byteLength());
+ m_data = nullptr;
+}
+
+void FetchBody::consumeArrayBufferView(Ref<DeferredPromise>&& promise)
+{
+ m_consumer.resolveWithData(WTFMove(promise), static_cast<const uint8_t*>(arrayBufferViewBody().baseAddress()), arrayBufferViewBody().byteLength());
+ m_data = nullptr;
+}
+
+void FetchBody::consumeText(Ref<DeferredPromise>&& promise, const String& text)
+{
+ auto data = UTF8Encoding().encode(text, EntitiesForUnencodables);
+ m_consumer.resolveWithData(WTFMove(promise), reinterpret_cast<const uint8_t*>(data.data()), data.length());
+ m_data = nullptr;
+}
+
+void FetchBody::consumeBlob(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
+{
+ m_consumePromise = WTFMove(promise);
+ owner.loadBlob(blobBody(), &m_consumer);
+ m_data = nullptr;
+}
+
+void FetchBody::loadingFailed()
+{
+ if (m_consumePromise) {
+ m_consumePromise->reject();
+ m_consumePromise = nullptr;
+ }
+}
+
+void FetchBody::loadingSucceeded()
+{
+ if (m_consumePromise)
+ m_consumer.resolve(m_consumePromise.releaseNonNull());
+}
+
+RefPtr<FormData> FetchBody::bodyForInternalRequest(ScriptExecutionContext& context) const
+{
+ if (isText())
+ return FormData::create(UTF8Encoding().encode(textBody(), EntitiesForUnencodables));
+ if (isURLSearchParams())
+ return FormData::create(UTF8Encoding().encode(urlSearchParamsBody().toString(), EntitiesForUnencodables));
+ if (isBlob()) {
+ RefPtr<FormData> body = FormData::create();
+ body->appendBlob(blobBody().url());
+ return body;
+ }
+ if (isArrayBuffer())
+ return FormData::create(arrayBufferBody().data(), arrayBufferBody().byteLength());
+ if (isArrayBufferView())
+ return FormData::create(arrayBufferViewBody().baseAddress(), arrayBufferViewBody().byteLength());
+ if (isFormData()) {
+ ASSERT(!context.isWorkerGlobalScope());
+ RefPtr<FormData> body = const_cast<FormData*>(&formDataBody());
+ body->generateFiles(static_cast<Document*>(&context));
+ return body;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+FetchBody FetchBody::clone() const
+{
+ ASSERT(!m_consumePromise);
+ FetchBody clone(m_consumer);
+
+ if (isArrayBuffer())
+ clone.m_data = arrayBufferBody();
+ else if (isArrayBufferView())
+ clone.m_data = arrayBufferViewBody();
+ else if (isBlob())
+ clone.m_data = blobBody();
+ else if (isFormData())
+ clone.m_data = const_cast<FormData&>(formDataBody());
+ else if (isText())
+ clone.m_data = textBody();
+ else if (isURLSearchParams())
+ clone.m_data = urlSearchParamsBody();
+ return clone;
+}
+
+}
+
+#endif // ENABLE(FETCH_API)