#pragma once
#include "FetchBodyOwner.h"
#include "FetchHeaders.h"
#include "ReadableStreamSink.h"
#include "ResourceResponse.h"
#include <JavaScriptCore/TypedArrays.h>
namespace JSC {
class ExecState;
class JSValue;
};
namespace WebCore {
class FetchRequest;
struct ReadableStreamChunk;
class ReadableStreamSource;
class FetchResponse final : public FetchBodyOwner {
public:
using Type = ResourceResponse::Type;
struct Init {
unsigned short status { 200 };
String statusText { "OK"_s };
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 = WTF::Function<void(ExceptionOr<FetchResponse&>&&)>;
static void fetch(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&);
#if ENABLE(STREAMS_API)
void startConsumingStream(unsigned);
void consumeChunk(Ref<JSC::Uint8Array>&&);
void finishConsumingStream(Ref<DeferredPromise>&&);
#endif
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(ScriptExecutionContext&);
#if ENABLE(STREAMS_API)
void consumeBodyAsStream() final;
void feedStream() final;
void cancel() final;
#endif
using ResponseData = 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 = WTF::Function<void(ExceptionOr<ReadableStreamChunk*>&&)>;
void consumeBodyReceivedByChunk(ConsumeDataByChunkCallback&&);
WEBCORE_EXPORT ResourceResponse resourceResponse() const;
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 std::optional<ResourceError>& loadingError() const { return m_loadingError; }
const HTTPHeaderMap& internalResponseHeaders() const { return m_internalResponse.httpHeaderFields(); }
private:
FetchResponse(ScriptExecutionContext&, std::optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceResponse&&);
void stop() final;
const char* activeDOMObjectName() const final;
bool canSuspendForDocumentSuspension() const final;
const ResourceResponse& filteredResponse() const;
#if ENABLE(STREAMS_API)
void closeStream();
#endif
class BodyLoader final : public FetchLoaderClient {
public:
BodyLoader(FetchResponse&, NotificationCallback&&);
~BodyLoader();
bool start(ScriptExecutionContext&, const FetchRequest&);
void stop();
void consumeDataByChunk(ConsumeDataByChunkCallback&&);
#if ENABLE(STREAMS_API)
RefPtr<SharedBuffer> startStreaming();
#endif
private:
void didSucceed() final;
void didFail(const ResourceError&) final;
void didReceiveResponse(const ResourceResponse&) final;
void didReceiveData(const char*, size_t) final;
FetchResponse& m_response;
NotificationCallback m_responseCallback;
ConsumeDataByChunkCallback m_consumeDataCallback;
std::unique_ptr<FetchLoader> m_loader;
};
mutable std::optional<ResourceResponse> m_filteredResponse;
ResourceResponse m_internalResponse;
std::optional<BodyLoader> m_bodyLoader;
mutable String m_responseURL;
uint64_t m_bodySizeWithPadding { 0 };
uint64_t m_opaqueLoadIdentifier { 0 };
};
}