1/*
2 * Copyright (C) 2016 Canon Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted, provided that the following conditions
6 * are required to be met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Canon Inc. nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#pragma once
30
31#include "FetchBodyOwner.h"
32#include "FetchHeaders.h"
33#include "ReadableStreamSink.h"
34#include "ResourceResponse.h"
35#include <JavaScriptCore/TypedArrays.h>
36#include <wtf/WeakPtr.h>
37
38namespace JSC {
39class ExecState;
40class JSValue;
41};
42
43namespace WebCore {
44
45class AbortSignal;
46class FetchRequest;
47struct ReadableStreamChunk;
48class ReadableStreamSource;
49
50class FetchResponse final : public FetchBodyOwner, public CanMakeWeakPtr<FetchResponse> {
51public:
52 using Type = ResourceResponse::Type;
53
54 struct Init {
55 unsigned short status { 200 };
56 String statusText { "OK"_s };
57 Optional<FetchHeaders::Init> headers;
58 };
59
60 WEBCORE_EXPORT static Ref<FetchResponse> create(ScriptExecutionContext&, Optional<FetchBody>&&, FetchHeaders::Guard, ResourceResponse&&);
61
62 static ExceptionOr<Ref<FetchResponse>> create(ScriptExecutionContext&, Optional<FetchBody::Init>&&, Init&&);
63 static Ref<FetchResponse> error(ScriptExecutionContext&);
64 static ExceptionOr<Ref<FetchResponse>> redirect(ScriptExecutionContext&, const String& url, int status);
65
66 using NotificationCallback = WTF::Function<void(ExceptionOr<FetchResponse&>&&)>;
67 static void fetch(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&);
68
69#if ENABLE(STREAMS_API)
70 void startConsumingStream(unsigned);
71 void consumeChunk(Ref<JSC::Uint8Array>&&);
72 void finishConsumingStream(Ref<DeferredPromise>&&);
73#endif
74
75 Type type() const { return filteredResponse().type(); }
76 const String& url() const;
77 bool redirected() const { return filteredResponse().isRedirected(); }
78 int status() const { return filteredResponse().httpStatusCode(); }
79 bool ok() const { return filteredResponse().isSuccessful(); }
80 const String& statusText() const { return filteredResponse().httpStatusText(); }
81
82 const FetchHeaders& headers() const { return m_headers; }
83 FetchHeaders& headers() { return m_headers; }
84 ExceptionOr<Ref<FetchResponse>> clone(ScriptExecutionContext&);
85
86#if ENABLE(STREAMS_API)
87 void consumeBodyAsStream() final;
88 void feedStream() final;
89 void cancel() final;
90#endif
91
92 using ResponseData = Variant<std::nullptr_t, Ref<FormData>, Ref<SharedBuffer>>;
93 ResponseData consumeBody();
94 void setBodyData(ResponseData&&, uint64_t bodySizeWithPadding);
95
96 bool isLoading() const { return !!m_bodyLoader; }
97 bool isBodyReceivedByChunk() const { return isLoading() || hasReadableStreamBody(); }
98 bool isBlobBody() const { return !isBodyNull() && body().isBlob(); }
99 bool isBlobFormData() const { return !isBodyNull() && body().isFormData(); }
100
101 using ConsumeDataByChunkCallback = WTF::Function<void(ExceptionOr<ReadableStreamChunk*>&&)>;
102 void consumeBodyReceivedByChunk(ConsumeDataByChunkCallback&&);
103
104 WEBCORE_EXPORT ResourceResponse resourceResponse() const;
105 ResourceResponse::Tainting tainting() const { return m_internalResponse.tainting(); }
106
107 uint64_t bodySizeWithPadding() const { return m_bodySizeWithPadding; }
108 void setBodySizeWithPadding(uint64_t size) { m_bodySizeWithPadding = size; }
109 uint64_t opaqueLoadIdentifier() const { return m_opaqueLoadIdentifier; }
110
111 void initializeOpaqueLoadIdentifierForTesting() { m_opaqueLoadIdentifier = 1; }
112
113 const HTTPHeaderMap& internalResponseHeaders() const { return m_internalResponse.httpHeaderFields(); }
114
115private:
116 FetchResponse(ScriptExecutionContext&, Optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceResponse&&);
117
118 void stop() final;
119 const char* activeDOMObjectName() const final;
120 bool canSuspendForDocumentSuspension() const final;
121
122 const ResourceResponse& filteredResponse() const;
123
124#if ENABLE(STREAMS_API)
125 void closeStream();
126#endif
127
128 void addAbortSteps(Ref<AbortSignal>&&);
129
130 class BodyLoader final : public FetchLoaderClient {
131 public:
132 BodyLoader(FetchResponse&, NotificationCallback&&);
133 BodyLoader(BodyLoader&&) = default;
134 ~BodyLoader();
135
136 bool start(ScriptExecutionContext&, const FetchRequest&);
137 void stop();
138
139 void consumeDataByChunk(ConsumeDataByChunkCallback&&);
140
141#if ENABLE(STREAMS_API)
142 RefPtr<SharedBuffer> startStreaming();
143#endif
144 NotificationCallback takeNotificationCallback() { return WTFMove(m_responseCallback); }
145 ConsumeDataByChunkCallback takeConsumeDataCallback() { return WTFMove(m_consumeDataCallback); }
146
147 private:
148 // FetchLoaderClient API
149 void didSucceed() final;
150 void didFail(const ResourceError&) final;
151 void didReceiveResponse(const ResourceResponse&) final;
152 void didReceiveData(const char*, size_t) final;
153
154 FetchResponse& m_response;
155 NotificationCallback m_responseCallback;
156 ConsumeDataByChunkCallback m_consumeDataCallback;
157 std::unique_ptr<FetchLoader> m_loader;
158 Ref<PendingActivity<FetchResponse>> m_pendingActivity;
159 };
160
161 mutable Optional<ResourceResponse> m_filteredResponse;
162 ResourceResponse m_internalResponse;
163 Optional<BodyLoader> m_bodyLoader;
164 mutable String m_responseURL;
165 // Opaque responses will padd their body size when used with Cache API.
166 uint64_t m_bodySizeWithPadding { 0 };
167 uint64_t m_opaqueLoadIdentifier { 0 };
168 RefPtr<AbortSignal> m_abortSignal;
169};
170
171} // namespace WebCore
172