blob: f09e25dc8ab3f2d69bfa1e12c68d855e3b6f7615 [file] [log] [blame]
/*
* 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.
*/
#pragma once
#include "FetchBodyOwner.h"
#include "FetchHeaders.h"
#include "ReadableStreamSink.h"
#include "ResourceResponse.h"
#include <JavaScriptCore/TypedArrays.h>
#include <wtf/Span.h>
#include <wtf/WeakPtr.h>
namespace JSC {
class CallFrame;
class JSValue;
};
namespace WebCore {
class AbortSignal;
class FetchRequest;
class ReadableStreamSource;
class FetchResponse final : public FetchBodyOwner {
public:
using Type = ResourceResponse::Type;
struct Init {
unsigned short status { 200 };
AtomString statusText;
std::optional<FetchHeaders::Init> headers;
};
WEBCORE_EXPORT static Ref<FetchResponse> create(ScriptExecutionContext*, std::optional<FetchBody>&&, FetchHeaders::Guard, ResourceResponse&&);
static ExceptionOr<Ref<FetchResponse>> create(ScriptExecutionContext&, std::optional<FetchBody::Init>&&, Init&&);
static Ref<FetchResponse> error(ScriptExecutionContext&);
static ExceptionOr<Ref<FetchResponse>> redirect(ScriptExecutionContext&, const String& url, int status);
using NotificationCallback = Function<void(ExceptionOr<Ref<FetchResponse>>&&)>;
static void fetch(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&, const String& initiator);
static Ref<FetchResponse> createFetchResponse(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&);
void startConsumingStream(unsigned);
void consumeChunk(Ref<JSC::Uint8Array>&&);
void finishConsumingStream(Ref<DeferredPromise>&&);
Type type() const { return filteredResponse().type(); }
const String& url() const;
bool redirected() const { return filteredResponse().isRedirected(); }
int status() const { return filteredResponse().httpStatusCode(); }
bool ok() const { return filteredResponse().isSuccessful(); }
const String& statusText() const { return filteredResponse().httpStatusText(); }
const FetchHeaders& headers() const { return m_headers; }
FetchHeaders& headers() { return m_headers; }
ExceptionOr<Ref<FetchResponse>> clone();
void consumeBodyAsStream() final;
void feedStream() final;
void cancel() final;
using ResponseData = std::variant<std::nullptr_t, Ref<FormData>, Ref<SharedBuffer>>;
ResponseData consumeBody();
void setBodyData(ResponseData&&, uint64_t bodySizeWithPadding);
bool isLoading() const { return !!m_bodyLoader; }
bool isBodyReceivedByChunk() const { return isLoading() || hasReadableStreamBody(); }
bool isBlobBody() const { return !isBodyNull() && body().isBlob(); }
bool isBlobFormData() const { return !isBodyNull() && body().isFormData(); }
using ConsumeDataByChunkCallback = Function<void(ExceptionOr<Span<const uint8_t>*>&&)>;
void consumeBodyReceivedByChunk(ConsumeDataByChunkCallback&&);
void cancelStream();
WEBCORE_EXPORT ResourceResponse resourceResponse() const;
ResourceResponse::Tainting tainting() const { return m_internalResponse.tainting(); }
uint64_t bodySizeWithPadding() const { return m_bodySizeWithPadding; }
void setBodySizeWithPadding(uint64_t size) { m_bodySizeWithPadding = size; }
uint64_t opaqueLoadIdentifier() const { return m_opaqueLoadIdentifier; }
void initializeOpaqueLoadIdentifierForTesting() { m_opaqueLoadIdentifier = 1; }
const HTTPHeaderMap& internalResponseHeaders() const { return m_internalResponse.httpHeaderFields(); }
bool isCORSSameOrigin() const;
bool hasWasmMIMEType() const;
const NetworkLoadMetrics& networkLoadMetrics() const { return m_networkLoadMetrics; }
void setReceivedInternalResponse(const ResourceResponse&, FetchOptions::Credentials);
void startLoader(ScriptExecutionContext&, FetchRequest&, const String& initiator);
void setIsNavigationPreload(bool isNavigationPreload) { m_isNavigationPreload = isNavigationPreload; }
bool isAvailableNavigationPreload() const { return m_isNavigationPreload && m_bodyLoader && !m_bodyLoader->hasLoader() && !hasReadableStreamBody(); }
void markAsDisturbed();
private:
FetchResponse(ScriptExecutionContext*, std::optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceResponse&&);
void stop() final;
const char* activeDOMObjectName() const final;
const ResourceResponse& filteredResponse() const;
void setNetworkLoadMetrics(const NetworkLoadMetrics& metrics) { m_networkLoadMetrics = metrics; }
void closeStream();
void addAbortSteps(Ref<AbortSignal>&&);
class BodyLoader final : public FetchLoaderClient {
WTF_MAKE_FAST_ALLOCATED;
public:
BodyLoader(FetchResponse&, NotificationCallback&&);
~BodyLoader();
bool start(ScriptExecutionContext&, const FetchRequest&, const String& initiator);
void stop();
void consumeDataByChunk(ConsumeDataByChunkCallback&&);
bool hasLoader() const { return !!m_loader; }
RefPtr<FragmentedSharedBuffer> startStreaming();
NotificationCallback takeNotificationCallback() { return WTFMove(m_responseCallback); }
ConsumeDataByChunkCallback takeConsumeDataCallback() { return WTFMove(m_consumeDataCallback); }
private:
// FetchLoaderClient API
void didSucceed(const NetworkLoadMetrics&) final;
void didFail(const ResourceError&) final;
void didReceiveResponse(const ResourceResponse&) final;
void didReceiveData(const SharedBuffer&) final;
FetchResponse& m_response;
NotificationCallback m_responseCallback;
ConsumeDataByChunkCallback m_consumeDataCallback;
std::unique_ptr<FetchLoader> m_loader;
Ref<PendingActivity<FetchResponse>> m_pendingActivity;
FetchOptions::Credentials m_credentials;
bool m_shouldStartStreaming { false };
};
mutable std::optional<ResourceResponse> m_filteredResponse;
ResourceResponse m_internalResponse;
std::unique_ptr<BodyLoader> m_bodyLoader;
mutable String m_responseURL;
// Opaque responses will padd their body size when used with Cache API.
uint64_t m_bodySizeWithPadding { 0 };
uint64_t m_opaqueLoadIdentifier { 0 };
RefPtr<AbortSignal> m_abortSignal;
NetworkLoadMetrics m_networkLoadMetrics;
bool m_hasInitializedInternalResponse { false };
bool m_isNavigationPreload { false };
};
} // namespace WebCore