blob: 97ad7273e6c060b85f298c2a2e7969e5efdcda5d [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/WeakPtr.h>
namespace JSC {
class CallFrame;
class JSValue;
};
namespace WebCore {
class AbortSignal;
class FetchRequest;
struct ReadableStreamChunk;
class ReadableStreamSource;
class FetchResponse final : public FetchBodyOwner, public CanMakeWeakPtr<FetchResponse> {
public:
using Type = ResourceResponse::Type;
struct Init {
unsigned short status { 200 };
String statusText;
Optional<FetchHeaders::Init> headers;
};
WEBCORE_EXPORT static Ref<FetchResponse> create(ScriptExecutionContext&, Optional<FetchBody>&&, FetchHeaders::Guard, ResourceResponse&&);
static ExceptionOr<Ref<FetchResponse>> create(ScriptExecutionContext&, 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;
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(); }
private:
FetchResponse(ScriptExecutionContext&, Optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceResponse&&);
void stop() final;
const char* activeDOMObjectName() const final;
const ResourceResponse& filteredResponse() const;
#if ENABLE(STREAMS_API)
void closeStream();
#endif
void addAbortSteps(Ref<AbortSignal>&&);
class BodyLoader final : public FetchLoaderClient {
WTF_MAKE_FAST_ALLOCATED;
public:
BodyLoader(FetchResponse&, NotificationCallback&&);
~BodyLoader();
bool start(ScriptExecutionContext&, const FetchRequest&);
void stop();
void consumeDataByChunk(ConsumeDataByChunkCallback&&);
#if ENABLE(STREAMS_API)
RefPtr<SharedBuffer> startStreaming();
#endif
NotificationCallback takeNotificationCallback() { return WTFMove(m_responseCallback); }
ConsumeDataByChunkCallback takeConsumeDataCallback() { return WTFMove(m_consumeDataCallback); }
private:
// FetchLoaderClient API
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;
Ref<PendingActivity<FetchResponse>> m_pendingActivity;
};
mutable 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;
};
} // namespace WebCore