FetchBodyOwner.cpp [plain text]
#include "config.h"
#include "FetchBodyOwner.h"
#if ENABLE(FETCH_API)
#include "FetchLoader.h"
#include "HTTPParsers.h"
#include "JSBlob.h"
#include "ResourceResponse.h"
namespace WebCore {
FetchBodyOwner::FetchBodyOwner(ScriptExecutionContext& context, std::optional<FetchBody>&& body, Ref<FetchHeaders>&& headers)
: ActiveDOMObject(&context)
, m_body(WTFMove(body))
, m_headers(WTFMove(headers))
{
suspendIfNeeded();
}
void FetchBodyOwner::stop()
{
if (m_body)
m_body->cleanConsumePromise();
if (m_blobLoader) {
bool isUniqueReference = hasOneRef();
if (m_blobLoader->loader)
m_blobLoader->loader->stop();
ASSERT_UNUSED(isUniqueReference, isUniqueReference || !m_blobLoader);
}
}
bool FetchBodyOwner::isDisturbedOrLocked() const
{
if (m_isDisturbed)
return true;
#if ENABLE(STREAMS_API)
if (m_readableStreamSource && m_readableStreamSource->isReadableStreamLocked())
return true;
#endif
return false;
}
void FetchBodyOwner::arrayBuffer(Ref<DeferredPromise>&& promise)
{
if (isBodyNull()) {
fulfillPromiseWithArrayBuffer(WTFMove(promise), nullptr, 0);
return;
}
if (isDisturbedOrLocked()) {
promise->reject(TypeError);
return;
}
m_isDisturbed = true;
m_body->arrayBuffer(*this, WTFMove(promise));
}
void FetchBodyOwner::blob(Ref<DeferredPromise>&& promise)
{
if (isBodyNull()) {
promise->resolve<IDLInterface<Blob>>(Blob::create({ }, Blob::normalizedContentType(extractMIMETypeFromMediaType(m_contentType))).get());
return;
}
if (isDisturbedOrLocked()) {
promise->reject(TypeError);
return;
}
m_isDisturbed = true;
m_body->blob(*this, WTFMove(promise), m_contentType);
}
void FetchBodyOwner::cloneBody(const FetchBodyOwner& owner)
{
m_contentType = owner.m_contentType;
if (owner.isBodyNull())
return;
m_body = owner.m_body->clone();
}
void FetchBodyOwner::extractBody(ScriptExecutionContext& context, FetchBody::BindingDataType&& value)
{
m_body = FetchBody::extract(context, WTFMove(value), m_contentType);
}
void FetchBodyOwner::updateContentType()
{
String contentType = m_headers->fastGet(HTTPHeaderName::ContentType);
if (!contentType.isNull()) {
m_contentType = WTFMove(contentType);
return;
}
if (!m_contentType.isNull())
m_headers->fastSet(HTTPHeaderName::ContentType, m_contentType);
}
void FetchBodyOwner::consumeOnceLoadingFinished(FetchBodyConsumer::Type type, Ref<DeferredPromise>&& promise)
{
if (isDisturbedOrLocked()) {
promise->reject(TypeError);
return;
}
m_isDisturbed = true;
m_body->consumeOnceLoadingFinished(type, WTFMove(promise), m_contentType);
}
void FetchBodyOwner::formData(Ref<DeferredPromise>&& promise)
{
if (isBodyNull()) {
promise->reject();
return;
}
if (isDisturbedOrLocked()) {
promise->reject(TypeError);
return;
}
m_isDisturbed = true;
m_body->formData(*this, WTFMove(promise));
}
void FetchBodyOwner::json(Ref<DeferredPromise>&& promise)
{
if (isBodyNull()) {
promise->reject(SYNTAX_ERR);
return;
}
if (isDisturbedOrLocked()) {
promise->reject(TypeError);
return;
}
m_isDisturbed = true;
m_body->json(*this, WTFMove(promise));
}
void FetchBodyOwner::text(Ref<DeferredPromise>&& promise)
{
if (isBodyNull()) {
promise->resolve<IDLDOMString>({ });
return;
}
if (isDisturbedOrLocked()) {
promise->reject(TypeError);
return;
}
m_isDisturbed = true;
m_body->text(*this, WTFMove(promise));
}
void FetchBodyOwner::loadBlob(const Blob& blob, FetchBodyConsumer* consumer)
{
ASSERT(isDisturbed());
ASSERT(!m_blobLoader);
ASSERT(!isBodyNull());
if (!scriptExecutionContext()) {
m_body->loadingFailed();
return;
}
m_blobLoader.emplace(*this);
m_blobLoader->loader = std::make_unique<FetchLoader>(*m_blobLoader, consumer);
m_blobLoader->loader->start(*scriptExecutionContext(), blob);
if (!m_blobLoader->loader->isStarted()) {
m_body->loadingFailed();
m_blobLoader = std::nullopt;
return;
}
setPendingActivity(this);
}
void FetchBodyOwner::finishBlobLoading()
{
ASSERT(m_blobLoader);
m_blobLoader = std::nullopt;
unsetPendingActivity(this);
}
void FetchBodyOwner::blobLoadingSucceeded()
{
ASSERT(!isBodyNull());
#if ENABLE(STREAMS_API)
if (m_readableStreamSource) {
m_readableStreamSource->close();
m_readableStreamSource = nullptr;
}
#endif
m_body->loadingSucceeded();
finishBlobLoading();
}
void FetchBodyOwner::blobLoadingFailed()
{
ASSERT(!isBodyNull());
#if ENABLE(STREAMS_API)
if (m_readableStreamSource) {
if (!m_readableStreamSource->isCancelling())
m_readableStreamSource->error(ASCIILiteral("Blob loading failed"));
m_readableStreamSource = nullptr;
} else
#endif
m_body->loadingFailed();
finishBlobLoading();
}
void FetchBodyOwner::blobChunk(const char* data, size_t size)
{
ASSERT(data);
#if ENABLE(STREAMS_API)
ASSERT(m_readableStreamSource);
if (!m_readableStreamSource->enqueue(ArrayBuffer::tryCreate(data, size)))
stop();
#else
UNUSED_PARAM(data);
UNUSED_PARAM(size);
#endif
}
FetchBodyOwner::BlobLoader::BlobLoader(FetchBodyOwner& owner)
: owner(owner)
{
}
void FetchBodyOwner::BlobLoader::didReceiveResponse(const ResourceResponse& response)
{
if (response.httpStatusCode() != 200)
didFail();
}
void FetchBodyOwner::BlobLoader::didFail()
{
if (loader->isStarted())
owner.blobLoadingFailed();
}
}
#endif // ENABLE(FETCH_API)