mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
LibWeb: Make Fetch::Infrastructure::Body
be GC allocated
Making the body GC-allocated allows us to avoid using `JS::Handle` for `m_stream` in its members.
This commit is contained in:
parent
953c19bdb7
commit
bdd3a16b16
Notes:
sideshowbarker
2024-07-17 20:19:08 +09:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/SerenityOS/serenity/commit/bdd3a16b16 Pull-request: https://github.com/SerenityOS/serenity/pull/20645 Reviewed-by: https://github.com/awesomekling
@ -233,7 +233,7 @@ JS::GCPtr<DOM::Document> load_document(Optional<HTML::NavigationParams> navigati
|
||||
|
||||
auto& realm = document->realm();
|
||||
|
||||
if (navigation_params->response->body().has_value()) {
|
||||
if (navigation_params->response->body()) {
|
||||
auto process_body = [navigation_params, document](ByteBuffer bytes) {
|
||||
if (!parse_document(*document, bytes)) {
|
||||
// FIXME: Load html page with an error if parsing failed.
|
||||
|
@ -31,7 +31,7 @@ bool BodyMixin::is_unusable() const
|
||||
{
|
||||
// An object including the Body interface mixin is said to be unusable if its body is non-null and its body’s stream is disturbed or locked.
|
||||
auto const& body = body_impl();
|
||||
return body.has_value() && (body->stream()->is_disturbed() || body->stream()->is_locked());
|
||||
return body && (body->stream()->is_disturbed() || body->stream()->is_locked());
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#dom-body-body
|
||||
@ -39,7 +39,7 @@ JS::GCPtr<Streams::ReadableStream> BodyMixin::body() const
|
||||
{
|
||||
// The body getter steps are to return null if this’s body is null; otherwise this’s body’s stream.
|
||||
auto const& body = body_impl();
|
||||
return body.has_value() ? body->stream().ptr() : nullptr;
|
||||
return body ? body->stream().ptr() : nullptr;
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#dom-body-bodyused
|
||||
@ -47,7 +47,7 @@ bool BodyMixin::body_used() const
|
||||
{
|
||||
// The bodyUsed getter steps are to return true if this’s body is non-null and this’s body’s stream is disturbed; otherwise false.
|
||||
auto const& body = body_impl();
|
||||
return body.has_value() && body->stream()->is_disturbed();
|
||||
return body && body->stream()->is_disturbed();
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#dom-body-arraybuffer
|
||||
@ -197,7 +197,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> consume_body(JS::Realm& realm
|
||||
|
||||
// 5. If object’s body is null, then run successSteps with an empty byte sequence.
|
||||
auto const& body = object.body_impl();
|
||||
if (!body.has_value()) {
|
||||
if (!body) {
|
||||
success_steps(ByteBuffer {});
|
||||
}
|
||||
// 6. Otherwise, fully read object’s body given successSteps, errorSteps, and object’s relevant global object.
|
||||
|
@ -27,8 +27,8 @@ public:
|
||||
virtual ~BodyMixin();
|
||||
|
||||
virtual ErrorOr<Optional<MimeSniff::MimeType>> mime_type_impl() const = 0;
|
||||
virtual Optional<Infrastructure::Body&> body_impl() = 0;
|
||||
virtual Optional<Infrastructure::Body const&> body_impl() const = 0;
|
||||
virtual JS::GCPtr<Infrastructure::Body> body_impl() = 0;
|
||||
virtual JS::GCPtr<Infrastructure::Body const> body_impl() const = 0;
|
||||
virtual Bindings::PlatformObject& as_platform_object() = 0;
|
||||
virtual Bindings::PlatformObject const& as_platform_object() const = 0;
|
||||
|
||||
|
@ -136,7 +136,7 @@ WebIDL::ExceptionOr<Infrastructure::BodyWithType> extract_body(JS::Realm& realm,
|
||||
// FIXME: 12. If action is non-null, then run these steps in parallel:
|
||||
|
||||
// 13. Let body be a body whose stream is stream, source is source, and length is length.
|
||||
auto body = Infrastructure::Body { JS::make_handle(*stream), move(source), move(length) };
|
||||
auto body = Infrastructure::Body::create(vm, *stream, move(source), move(length));
|
||||
|
||||
// 14. Return (body, type).
|
||||
return Infrastructure::BodyWithType { .body = move(body), .type = move(type) };
|
||||
|
@ -165,7 +165,7 @@ void abort_fetch(JS::Realm& realm, WebIDL::Promise const& promise, JS::NonnullGC
|
||||
WebIDL::reject_promise(realm, promise, error);
|
||||
|
||||
// 2. If request’s body is non-null and is readable, then cancel request’s body with error.
|
||||
if (auto* body = request->body().get_pointer<Infrastructure::Body>(); body != nullptr && body->stream()->is_readable()) {
|
||||
if (auto* body = request->body().get_pointer<JS::NonnullGCPtr<Infrastructure::Body>>(); body != nullptr && (*body)->stream()->is_readable()) {
|
||||
// TODO: Implement cancelling streams
|
||||
(void)error;
|
||||
}
|
||||
@ -178,7 +178,7 @@ void abort_fetch(JS::Realm& realm, WebIDL::Promise const& promise, JS::NonnullGC
|
||||
auto response = response_object->response();
|
||||
|
||||
// 5. If response’s body is non-null and is readable, then error response’s body with error.
|
||||
if (response->body().has_value()) {
|
||||
if (response->body()) {
|
||||
auto stream = response->body()->stream();
|
||||
if (stream->is_readable()) {
|
||||
// TODO: Implement erroring streams
|
||||
|
@ -498,7 +498,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
|
||||
};
|
||||
|
||||
// 2. If response’s body is null, then run processBodyError and abort these steps.
|
||||
if (!response->body().has_value()) {
|
||||
if (!response->body()) {
|
||||
process_body_error({});
|
||||
return;
|
||||
}
|
||||
@ -644,7 +644,7 @@ WebIDL::ExceptionOr<void> fetch_response_handover(JS::Realm& realm, Infrastructu
|
||||
auto internal_response = response.is_network_error() ? JS::NonnullGCPtr { response } : response.unsafe_response();
|
||||
|
||||
// 6. If internalResponse’s body is null, then run processResponseEndOfBody.
|
||||
if (!internal_response->body().has_value()) {
|
||||
if (!internal_response->body()) {
|
||||
process_response_end_of_body();
|
||||
}
|
||||
// 7. Otherwise:
|
||||
@ -672,7 +672,7 @@ WebIDL::ExceptionOr<void> fetch_response_handover(JS::Realm& realm, Infrastructu
|
||||
|
||||
// 3. If internalResponse's body is null, then queue a fetch task to run processBody given null, with
|
||||
// fetchParams’s task destination.
|
||||
if (!internal_response->body().has_value()) {
|
||||
if (!internal_response->body()) {
|
||||
Infrastructure::queue_fetch_task(task_destination, [process_body = move(process_body)]() {
|
||||
process_body({});
|
||||
});
|
||||
@ -1118,7 +1118,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> http_redirect_f
|
||||
// return a network error.
|
||||
if (actual_response->status() != 303
|
||||
&& !request->body().has<Empty>()
|
||||
&& request->body().get<Infrastructure::Body>().source().has<Empty>()) {
|
||||
&& request->body().get<JS::NonnullGCPtr<Infrastructure::Body>>()->source().has<Empty>()) {
|
||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has body but no body source"sv));
|
||||
}
|
||||
|
||||
@ -1160,7 +1160,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> http_redirect_f
|
||||
// request’s body’s source.
|
||||
// NOTE: request’s body’s source’s nullity has already been checked.
|
||||
if (!request->body().has<Empty>()) {
|
||||
auto const& source = request->body().get<Infrastructure::Body>().source();
|
||||
auto const& source = request->body().get<JS::NonnullGCPtr<Infrastructure::Body>>()->source();
|
||||
// NOTE: BodyInitOrReadableBytes is a superset of Body::SourceType
|
||||
auto converted_source = source.has<ByteBuffer>()
|
||||
? BodyInitOrReadableBytes { source.get<ByteBuffer>() }
|
||||
@ -1292,8 +1292,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
||||
include_credentials = IncludeCredentials::No;
|
||||
|
||||
// 5. Let contentLength be httpRequest’s body’s length, if httpRequest’s body is non-null; otherwise null.
|
||||
auto content_length = http_request->body().has<Infrastructure::Body>()
|
||||
? http_request->body().get<Infrastructure::Body>().length()
|
||||
auto content_length = http_request->body().has<JS::NonnullGCPtr<Infrastructure::Body>>()
|
||||
? http_request->body().get<JS::NonnullGCPtr<Infrastructure::Body>>()->length()
|
||||
: Optional<u64> {};
|
||||
|
||||
// 6. Let contentLengthHeaderValue be null.
|
||||
@ -1580,13 +1580,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
||||
// 2. If request’s body is non-null, then:
|
||||
if (!request->body().has<Empty>()) {
|
||||
// 1. If request’s body’s source is null, then return a network error.
|
||||
if (request->body().get<Infrastructure::Body>().source().has<Empty>()) {
|
||||
if (request->body().get<JS::NonnullGCPtr<Infrastructure::Body>>()->source().has<Empty>()) {
|
||||
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "Request has body but no body source"_string));
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Set request’s body to the body of the result of safely extracting request’s body’s source.
|
||||
auto const& source = request->body().get<Infrastructure::Body>().source();
|
||||
auto const& source = request->body().get<JS::NonnullGCPtr<Infrastructure::Body>>()->source();
|
||||
// NOTE: BodyInitOrReadableBytes is a superset of Body::SourceType
|
||||
auto converted_source = source.has<ByteBuffer>()
|
||||
? BodyInitOrReadableBytes { source.get<ByteBuffer>() }
|
||||
@ -1657,7 +1657,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
||||
// - isNewConnectionFetch is false
|
||||
&& is_new_connection_fetch == IsNewConnectionFetch::No
|
||||
// - request’s body is null, or request’s body is non-null and request’s body’s source is non-null
|
||||
&& (request->body().has<Empty>() || !request->body().get<Infrastructure::Body>().source().has<Empty>())
|
||||
&& (request->body().has<Empty>() || !request->body().get<JS::NonnullGCPtr<Infrastructure::Body>>()->source().has<Empty>())
|
||||
// then:
|
||||
) {
|
||||
// 1. If fetchParams is canceled, then return the appropriate network error for fetchParams.
|
||||
@ -1738,8 +1738,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load
|
||||
load_request.set_method(DeprecatedString::copy(request->method()));
|
||||
for (auto const& header : *request->header_list())
|
||||
load_request.set_header(DeprecatedString::copy(header.name), DeprecatedString::copy(header.value));
|
||||
if (auto const* body = request->body().get_pointer<Infrastructure::Body>()) {
|
||||
TRY(body->source().visit(
|
||||
if (auto const* body = request->body().get_pointer<JS::NonnullGCPtr<Infrastructure::Body>>()) {
|
||||
TRY((*body)->source().visit(
|
||||
[&](ByteBuffer const& byte_buffer) -> WebIDL::ExceptionOr<void> {
|
||||
load_request.set_body(TRY_OR_THROW_OOM(vm, ByteBuffer::copy(byte_buffer)));
|
||||
return {};
|
||||
|
@ -13,20 +13,36 @@
|
||||
|
||||
namespace Web::Fetch::Infrastructure {
|
||||
|
||||
Body::Body(JS::Handle<Streams::ReadableStream> stream)
|
||||
JS::NonnullGCPtr<Body> Body::create(JS::VM& vm, JS::NonnullGCPtr<Streams::ReadableStream> stream)
|
||||
{
|
||||
return vm.heap().allocate_without_realm<Body>(stream);
|
||||
}
|
||||
|
||||
JS::NonnullGCPtr<Body> Body::create(JS::VM& vm, JS::NonnullGCPtr<Streams::ReadableStream> stream, SourceType source, Optional<u64> length)
|
||||
{
|
||||
return vm.heap().allocate_without_realm<Body>(stream, source, length);
|
||||
}
|
||||
|
||||
Body::Body(JS::NonnullGCPtr<Streams::ReadableStream> stream)
|
||||
: m_stream(move(stream))
|
||||
{
|
||||
}
|
||||
|
||||
Body::Body(JS::Handle<Streams::ReadableStream> stream, SourceType source, Optional<u64> length)
|
||||
Body::Body(JS::NonnullGCPtr<Streams::ReadableStream> stream, SourceType source, Optional<u64> length)
|
||||
: m_stream(move(stream))
|
||||
, m_source(move(source))
|
||||
, m_length(move(length))
|
||||
{
|
||||
}
|
||||
|
||||
void Body::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_stream);
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-body-clone
|
||||
Body Body::clone(JS::Realm& realm) const
|
||||
JS::NonnullGCPtr<Body> Body::clone(JS::Realm& realm) const
|
||||
{
|
||||
// To clone a body body, run these steps:
|
||||
// FIXME: 1. Let « out1, out2 » be the result of teeing body’s stream.
|
||||
@ -34,7 +50,7 @@ Body Body::clone(JS::Realm& realm) const
|
||||
auto out2 = realm.heap().allocate<Streams::ReadableStream>(realm, realm);
|
||||
|
||||
// 3. Return a body whose stream is out2 and other members are copied from body.
|
||||
return Body { JS::make_handle(out2), m_source, m_length };
|
||||
return Body::create(realm.vm(), out2, m_source, m_length);
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#body-fully-read
|
||||
@ -80,7 +96,7 @@ WebIDL::ExceptionOr<void> Body::fully_read(JS::Realm& realm, Web::Fetch::Infrast
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#byte-sequence-as-a-body
|
||||
WebIDL::ExceptionOr<Body> byte_sequence_as_body(JS::Realm& realm, ReadonlyBytes bytes)
|
||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<Body>> byte_sequence_as_body(JS::Realm& realm, ReadonlyBytes bytes)
|
||||
{
|
||||
// To get a byte sequence bytes as a body, return the body of the result of safely extracting bytes.
|
||||
auto [body, _] = TRY(safely_extract_body(realm, bytes));
|
||||
|
@ -21,7 +21,9 @@
|
||||
namespace Web::Fetch::Infrastructure {
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-body
|
||||
class Body final {
|
||||
class Body final : public JS::Cell {
|
||||
JS_CELL(Body, JS::Cell);
|
||||
|
||||
public:
|
||||
using SourceType = Variant<Empty, ByteBuffer, JS::Handle<FileAPI::Blob>>;
|
||||
// processBody must be an algorithm accepting a byte sequence.
|
||||
@ -29,21 +31,26 @@ public:
|
||||
// processBodyError must be an algorithm optionally accepting an exception.
|
||||
using ProcessBodyErrorCallback = JS::SafeFunction<void(JS::GCPtr<WebIDL::DOMException>)>;
|
||||
|
||||
explicit Body(JS::Handle<Streams::ReadableStream>);
|
||||
Body(JS::Handle<Streams::ReadableStream>, SourceType, Optional<u64>);
|
||||
[[nodiscard]] static JS::NonnullGCPtr<Body> create(JS::VM&, JS::NonnullGCPtr<Streams::ReadableStream>);
|
||||
[[nodiscard]] static JS::NonnullGCPtr<Body> create(JS::VM&, JS::NonnullGCPtr<Streams::ReadableStream>, SourceType, Optional<u64>);
|
||||
|
||||
[[nodiscard]] JS::NonnullGCPtr<Streams::ReadableStream> stream() const { return *m_stream; }
|
||||
[[nodiscard]] SourceType const& source() const { return m_source; }
|
||||
[[nodiscard]] Optional<u64> const& length() const { return m_length; }
|
||||
|
||||
[[nodiscard]] Body clone(JS::Realm&) const;
|
||||
[[nodiscard]] JS::NonnullGCPtr<Body> clone(JS::Realm&) const;
|
||||
|
||||
WebIDL::ExceptionOr<void> fully_read(JS::Realm&, ProcessBodyCallback process_body, ProcessBodyErrorCallback process_body_error, TaskDestination task_destination) const;
|
||||
|
||||
virtual void visit_edges(JS::Cell::Visitor&) override;
|
||||
|
||||
private:
|
||||
explicit Body(JS::NonnullGCPtr<Streams::ReadableStream>);
|
||||
Body(JS::NonnullGCPtr<Streams::ReadableStream>, SourceType, Optional<u64>);
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-body-stream
|
||||
// A stream (a ReadableStream object).
|
||||
JS::Handle<Streams::ReadableStream> m_stream;
|
||||
JS::NonnullGCPtr<Streams::ReadableStream> m_stream;
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-body-source
|
||||
// A source (null, a byte sequence, a Blob object, or a FormData object), initially null.
|
||||
@ -57,10 +64,10 @@ private:
|
||||
// https://fetch.spec.whatwg.org/#body-with-type
|
||||
// A body with type is a tuple that consists of a body (a body) and a type (a header value or null).
|
||||
struct BodyWithType {
|
||||
Body body;
|
||||
JS::NonnullGCPtr<Body> body;
|
||||
Optional<ByteBuffer> type;
|
||||
};
|
||||
|
||||
WebIDL::ExceptionOr<Body> byte_sequence_as_body(JS::Realm&, ReadonlyBytes);
|
||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<Body>> byte_sequence_as_body(JS::Realm&, ReadonlyBytes);
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ void Request::visit_edges(JS::Cell::Visitor& visitor)
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_header_list);
|
||||
visitor.visit(m_client);
|
||||
m_body.visit(
|
||||
[&](JS::GCPtr<Body>& body) { visitor.visit(body); },
|
||||
[](auto&) {});
|
||||
m_reserved_client.visit(
|
||||
[&](JS::GCPtr<HTML::EnvironmentSettingsObject> const& value) { visitor.visit(value); },
|
||||
[](auto const&) {});
|
||||
@ -249,8 +252,8 @@ JS::NonnullGCPtr<Request> Request::clone(JS::Realm& realm) const
|
||||
new_request->set_timing_allow_failed(m_timing_allow_failed);
|
||||
|
||||
// 2. If request’s body is non-null, set newRequest’s body to the result of cloning request’s body.
|
||||
if (auto const* body = m_body.get_pointer<Body>())
|
||||
new_request->set_body(body->clone(realm));
|
||||
if (auto const* body = m_body.get_pointer<JS::NonnullGCPtr<Body>>())
|
||||
new_request->set_body((*body)->clone(realm));
|
||||
|
||||
// 3. Return newRequest.
|
||||
return new_request;
|
||||
|
@ -153,7 +153,7 @@ public:
|
||||
// Members are implementation-defined
|
||||
struct Priority { };
|
||||
|
||||
using BodyType = Variant<Empty, ByteBuffer, Body>;
|
||||
using BodyType = Variant<Empty, ByteBuffer, JS::NonnullGCPtr<Body>>;
|
||||
using OriginType = Variant<Origin, HTML::Origin>;
|
||||
using PolicyContainerType = Variant<PolicyContainer, HTML::PolicyContainer>;
|
||||
using ReferrerType = Variant<Referrer, AK::URL>;
|
||||
|
@ -26,6 +26,7 @@ void Response::visit_edges(JS::Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_header_list);
|
||||
visitor.visit(m_body);
|
||||
}
|
||||
|
||||
JS::NonnullGCPtr<Response> Response::create(JS::VM& vm)
|
||||
@ -50,7 +51,7 @@ JS::NonnullGCPtr<Response> Response::network_error(JS::VM& vm, Variant<String, S
|
||||
auto response = Response::create(vm);
|
||||
response->set_status(0);
|
||||
response->set_type(Type::Error);
|
||||
VERIFY(!response->body().has_value());
|
||||
VERIFY(!response->body());
|
||||
response->m_network_error_message = move(message);
|
||||
return response;
|
||||
}
|
||||
@ -163,7 +164,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::clone(JS::Realm& realm
|
||||
// FIXME: service worker timing info
|
||||
|
||||
// 3. If response’s body is non-null, then set newResponse’s body to the result of cloning response’s body.
|
||||
if (m_body.has_value())
|
||||
if (m_body)
|
||||
new_response->set_body(m_body->clone(realm));
|
||||
|
||||
// 4. Return newResponse.
|
||||
@ -283,6 +284,7 @@ void OpaqueFilteredResponse::visit_edges(JS::Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_header_list);
|
||||
visitor.visit(m_body);
|
||||
}
|
||||
|
||||
JS::NonnullGCPtr<OpaqueRedirectFilteredResponse> OpaqueRedirectFilteredResponse::create(JS::VM& vm, JS::NonnullGCPtr<Response> internal_response)
|
||||
@ -302,6 +304,7 @@ void OpaqueRedirectFilteredResponse::visit_edges(JS::Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_header_list);
|
||||
visitor.visit(m_body);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -75,9 +75,9 @@ public:
|
||||
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const { return m_header_list; }
|
||||
void set_header_list(JS::NonnullGCPtr<HeaderList> header_list) { m_header_list = header_list; }
|
||||
|
||||
[[nodiscard]] virtual Optional<Body> const& body() const { return m_body; }
|
||||
[[nodiscard]] virtual Optional<Body>& body() { return m_body; }
|
||||
void set_body(Optional<Body> body) { m_body = move(body); }
|
||||
[[nodiscard]] virtual JS::GCPtr<Body> const& body() const { return m_body; }
|
||||
[[nodiscard]] virtual JS::GCPtr<Body>& body() { return m_body; }
|
||||
void set_body(JS::GCPtr<Body> body) { m_body = move(body); }
|
||||
|
||||
[[nodiscard]] virtual Optional<CacheState> const& cache_state() const { return m_cache_state; }
|
||||
void set_cache_state(Optional<CacheState> cache_state) { m_cache_state = move(cache_state); }
|
||||
@ -147,7 +147,7 @@ private:
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-response-body
|
||||
// A response has an associated body (null or a body). Unless stated otherwise it is null.
|
||||
Optional<Body> m_body;
|
||||
JS::GCPtr<Body> m_body;
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-response-cache-state
|
||||
// A response has an associated cache state (the empty string, "local", or "validated"). Unless stated otherwise, it is the empty string.
|
||||
@ -199,8 +199,8 @@ public:
|
||||
[[nodiscard]] virtual Status status() const override { return m_internal_response->status(); }
|
||||
[[nodiscard]] virtual ReadonlyBytes status_message() const override { return m_internal_response->status_message(); }
|
||||
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const override { return m_internal_response->header_list(); }
|
||||
[[nodiscard]] virtual Optional<Body> const& body() const override { return m_internal_response->body(); }
|
||||
[[nodiscard]] virtual Optional<Body>& body() override { return m_internal_response->body(); }
|
||||
[[nodiscard]] virtual JS::GCPtr<Body> const& body() const override { return m_internal_response->body(); }
|
||||
[[nodiscard]] virtual JS::GCPtr<Body>& body() override { return m_internal_response->body(); }
|
||||
[[nodiscard]] virtual Optional<CacheState> const& cache_state() const override { return m_internal_response->cache_state(); }
|
||||
[[nodiscard]] virtual Vector<ByteBuffer> const& cors_exposed_header_name_list() const override { return m_internal_response->cors_exposed_header_name_list(); }
|
||||
[[nodiscard]] virtual bool range_requested() const override { return m_internal_response->range_requested(); }
|
||||
@ -267,8 +267,8 @@ public:
|
||||
[[nodiscard]] virtual Status status() const override { return 0; }
|
||||
[[nodiscard]] virtual ReadonlyBytes status_message() const override { return {}; }
|
||||
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const override { return m_header_list; }
|
||||
[[nodiscard]] virtual Optional<Body> const& body() const override { return m_body; }
|
||||
[[nodiscard]] virtual Optional<Body>& body() override { return m_body; }
|
||||
[[nodiscard]] virtual JS::GCPtr<Body> const& body() const override { return m_body; }
|
||||
[[nodiscard]] virtual JS::GCPtr<Body>& body() override { return m_body; }
|
||||
|
||||
private:
|
||||
OpaqueFilteredResponse(JS::NonnullGCPtr<Response>, JS::NonnullGCPtr<HeaderList>);
|
||||
@ -277,7 +277,7 @@ private:
|
||||
|
||||
Vector<AK::URL> m_url_list;
|
||||
JS::NonnullGCPtr<HeaderList> m_header_list;
|
||||
Optional<Body> m_body;
|
||||
JS::GCPtr<Body> m_body;
|
||||
};
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect
|
||||
@ -291,8 +291,8 @@ public:
|
||||
[[nodiscard]] virtual Status status() const override { return 0; }
|
||||
[[nodiscard]] virtual ReadonlyBytes status_message() const override { return {}; }
|
||||
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const override { return m_header_list; }
|
||||
[[nodiscard]] virtual Optional<Body> const& body() const override { return m_body; }
|
||||
[[nodiscard]] virtual Optional<Body>& body() override { return m_body; }
|
||||
[[nodiscard]] virtual JS::GCPtr<Body> const& body() const override { return m_body; }
|
||||
[[nodiscard]] virtual JS::GCPtr<Body>& body() override { return m_body; }
|
||||
|
||||
private:
|
||||
OpaqueRedirectFilteredResponse(JS::NonnullGCPtr<Response>, JS::NonnullGCPtr<HeaderList>);
|
||||
@ -300,6 +300,6 @@ private:
|
||||
virtual void visit_edges(JS::Cell::Visitor&) override;
|
||||
|
||||
JS::NonnullGCPtr<HeaderList> m_header_list;
|
||||
Optional<Body> m_body;
|
||||
JS::GCPtr<Body> m_body;
|
||||
};
|
||||
}
|
||||
|
@ -54,28 +54,28 @@ ErrorOr<Optional<MimeSniff::MimeType>> Request::mime_type_impl() const
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-body-body
|
||||
// https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A7
|
||||
Optional<Infrastructure::Body const&> Request::body_impl() const
|
||||
JS::GCPtr<Infrastructure::Body const> Request::body_impl() const
|
||||
{
|
||||
// Objects including the Body interface mixin have an associated body (null or a body).
|
||||
// A Request object’s body is its request’s body.
|
||||
return m_request->body().visit(
|
||||
[](Infrastructure::Body const& b) -> Optional<Infrastructure::Body const&> { return b; },
|
||||
[](Empty) -> Optional<Infrastructure::Body const&> { return {}; },
|
||||
[](JS::NonnullGCPtr<Infrastructure::Body> const& b) -> JS::GCPtr<Infrastructure::Body const> { return b; },
|
||||
[](Empty) -> JS::GCPtr<Infrastructure::Body const> { return nullptr; },
|
||||
// A byte sequence will be safely extracted into a body early on in fetch.
|
||||
[](ByteBuffer const&) -> Optional<Infrastructure::Body const&> { VERIFY_NOT_REACHED(); });
|
||||
[](ByteBuffer const&) -> JS::GCPtr<Infrastructure::Body const> { VERIFY_NOT_REACHED(); });
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-body-body
|
||||
// https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A7
|
||||
Optional<Infrastructure::Body&> Request::body_impl()
|
||||
JS::GCPtr<Infrastructure::Body> Request::body_impl()
|
||||
{
|
||||
// Objects including the Body interface mixin have an associated body (null or a body).
|
||||
// A Request object’s body is its request’s body.
|
||||
return m_request->body().visit(
|
||||
[](Infrastructure::Body& b) -> Optional<Infrastructure::Body&> { return b; },
|
||||
[](Empty) -> Optional<Infrastructure::Body&> { return {}; },
|
||||
[](JS::NonnullGCPtr<Infrastructure::Body>& b) -> JS::GCPtr<Infrastructure::Body> { return b; },
|
||||
[](Empty) -> JS::GCPtr<Infrastructure::Body> { return {}; },
|
||||
// A byte sequence will be safely extracted into a body early on in fetch.
|
||||
[](ByteBuffer&) -> Optional<Infrastructure::Body&> { VERIFY_NOT_REACHED(); });
|
||||
[](ByteBuffer&) -> JS::GCPtr<Infrastructure::Body> { VERIFY_NOT_REACHED(); });
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#request-create
|
||||
@ -440,7 +440,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must not be GET or HEAD when body is provided"sv };
|
||||
|
||||
// 35. Let initBody be null.
|
||||
Optional<Infrastructure::Body> init_body;
|
||||
JS::GCPtr<Infrastructure::Body> init_body;
|
||||
|
||||
// 36. If init["body"] exists and is non-null, then:
|
||||
if (init.body.has_value() && (*init.body).has_value()) {
|
||||
@ -448,7 +448,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
|
||||
auto body_with_type = TRY(extract_body(realm, (*init.body).value(), request->keepalive()));
|
||||
|
||||
// 2. Set initBody to bodyWithType’s body.
|
||||
init_body = move(body_with_type.body);
|
||||
init_body = body_with_type.body;
|
||||
|
||||
// 3. Let type be bodyWithType’s type.
|
||||
auto const& type = body_with_type.type;
|
||||
@ -459,15 +459,15 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
|
||||
}
|
||||
|
||||
// 37. Let inputOrInitBody be initBody if it is non-null; otherwise inputBody.
|
||||
Optional<Infrastructure::Request::BodyType> input_or_init_body = init_body.has_value()
|
||||
? Infrastructure::Request::BodyType { init_body.value() }
|
||||
Optional<Infrastructure::Request::BodyType> input_or_init_body = init_body
|
||||
? Infrastructure::Request::BodyType { *init_body }
|
||||
: input_body;
|
||||
|
||||
// 38. If inputOrInitBody is non-null and inputOrInitBody’s source is null, then:
|
||||
// FIXME: The spec doesn't check if inputOrInitBody is a body before accessing source.
|
||||
if (input_or_init_body.has_value() && input_or_init_body->has<Infrastructure::Body>() && input_or_init_body->get<Infrastructure::Body>().source().has<Empty>()) {
|
||||
if (input_or_init_body.has_value() && input_or_init_body->has<JS::NonnullGCPtr<Infrastructure::Body>>() && input_or_init_body->get<JS::NonnullGCPtr<Infrastructure::Body>>()->source().has<Empty>()) {
|
||||
// 1. If initBody is non-null and init["duplex"] does not exist, then throw a TypeError.
|
||||
if (init_body.has_value() && !init.duplex.has_value())
|
||||
if (init_body && !init.duplex.has_value())
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Body without source requires 'duplex' value to be set"sv };
|
||||
|
||||
// 2. If this’s request’s mode is neither "same-origin" nor "cors", then throw a TypeError.
|
||||
@ -482,7 +482,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
|
||||
auto const& final_body = input_or_init_body;
|
||||
|
||||
// 40. If initBody is null and inputBody is non-null, then:
|
||||
if (!init_body.has_value() && input_body.has_value()) {
|
||||
if (!init_body && input_body.has_value()) {
|
||||
// 2. If input is unusable, then throw a TypeError.
|
||||
if (input.has<JS::Handle<Request>>() && input.get<JS::Handle<Request>>()->is_unusable())
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request is unusable"sv };
|
||||
|
@ -73,8 +73,8 @@ public:
|
||||
|
||||
// ^BodyMixin
|
||||
virtual ErrorOr<Optional<MimeSniff::MimeType>> mime_type_impl() const override;
|
||||
virtual Optional<Infrastructure::Body&> body_impl() override;
|
||||
virtual Optional<Infrastructure::Body const&> body_impl() const override;
|
||||
virtual JS::GCPtr<Infrastructure::Body> body_impl() override;
|
||||
virtual JS::GCPtr<Infrastructure::Body const> body_impl() const override;
|
||||
virtual Bindings::PlatformObject& as_platform_object() override { return *this; }
|
||||
virtual Bindings::PlatformObject const& as_platform_object() const override { return *this; }
|
||||
|
||||
|
@ -50,24 +50,20 @@ ErrorOr<Optional<MimeSniff::MimeType>> Response::mime_type_impl() const
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-body-body
|
||||
// https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A8
|
||||
Optional<Infrastructure::Body const&> Response::body_impl() const
|
||||
JS::GCPtr<Infrastructure::Body const> Response::body_impl() const
|
||||
{
|
||||
// Objects including the Body interface mixin have an associated body (null or a body).
|
||||
// A Response object’s body is its response’s body.
|
||||
return m_response->body().has_value()
|
||||
? m_response->body().value()
|
||||
: Optional<Infrastructure::Body const&> {};
|
||||
return m_response->body() ? m_response->body() : nullptr;
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-body-body
|
||||
// https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A8
|
||||
Optional<Infrastructure::Body&> Response::body_impl()
|
||||
JS::GCPtr<Infrastructure::Body> Response::body_impl()
|
||||
{
|
||||
// Objects including the Body interface mixin have an associated body (null or a body).
|
||||
// A Response object’s body is its response’s body.
|
||||
return m_response->body().has_value()
|
||||
? m_response->body().value()
|
||||
: Optional<Infrastructure::Body&> {};
|
||||
return m_response->body() ? m_response->body() : nullptr;
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#response-create
|
||||
|
@ -40,8 +40,8 @@ public:
|
||||
|
||||
// ^BodyMixin
|
||||
virtual ErrorOr<Optional<MimeSniff::MimeType>> mime_type_impl() const override;
|
||||
virtual Optional<Infrastructure::Body&> body_impl() override;
|
||||
virtual Optional<Infrastructure::Body const&> body_impl() const override;
|
||||
virtual JS::GCPtr<Infrastructure::Body> body_impl() override;
|
||||
virtual JS::GCPtr<Infrastructure::Body const> body_impl() const override;
|
||||
virtual Bindings::PlatformObject& as_platform_object() override { return *this; }
|
||||
virtual Bindings::PlatformObject const& as_platform_object() const override { return *this; }
|
||||
|
||||
|
@ -1003,7 +1003,7 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::fetch_resource(AK::URL const& url_re
|
||||
|
||||
// 5. Otherwise, incrementally read response's body given updateMedia, processEndOfMedia, an empty algorithm, and global.
|
||||
|
||||
VERIFY(response->body().has_value());
|
||||
VERIFY(response->body());
|
||||
auto empty_algorithm = [](auto) {};
|
||||
|
||||
// FIXME: We are "fully" reading the response here, rather than "incrementally". Memory concerns aside, this should be okay for now as we are
|
||||
|
@ -189,7 +189,7 @@ WebIDL::ExceptionOr<void> HTMLVideoElement::determine_element_poster_frame(Optio
|
||||
m_poster_frame = move(image.release_value().frames[0].bitmap);
|
||||
};
|
||||
|
||||
VERIFY(response->body().has_value());
|
||||
VERIFY(response->body());
|
||||
auto empty_algorithm = [](auto) {};
|
||||
|
||||
response->body()->fully_read(realm, move(on_image_data_read), move(empty_algorithm), JS::NonnullGCPtr { global }).release_value_but_fixme_should_propagate_errors();
|
||||
|
@ -82,8 +82,8 @@ void SharedImageRequest::fetch_image(JS::Realm& realm, JS::NonnullGCPtr<Fetch::I
|
||||
handle_failed_fetch();
|
||||
};
|
||||
|
||||
if (response->body().has_value())
|
||||
response->body().value().fully_read(realm, move(process_body), move(process_body_error), JS::NonnullGCPtr { realm.global_object() }).release_value_but_fixme_should_propagate_errors();
|
||||
if (response->body())
|
||||
response->body()->fully_read(realm, move(process_body), move(process_body_error), JS::NonnullGCPtr { realm.global_object() }).release_value_but_fixme_should_propagate_errors();
|
||||
};
|
||||
|
||||
m_state = State::Fetching;
|
||||
|
@ -82,6 +82,7 @@ void XMLHttpRequest::visit_edges(Cell::Visitor& visitor)
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_upload_object);
|
||||
visitor.visit(m_author_request_headers);
|
||||
visitor.visit(m_request_body);
|
||||
visitor.visit(m_response);
|
||||
visitor.visit(m_fetch_controller);
|
||||
|
||||
@ -194,7 +195,7 @@ WebIDL::ExceptionOr<JS::Value> XMLHttpRequest::response()
|
||||
// Note: Automatically done by the layers above us.
|
||||
|
||||
// 2. If this’s response’s body is null, then return null.
|
||||
if (!m_response->body().has_value())
|
||||
if (!m_response->body())
|
||||
return JS::js_null();
|
||||
|
||||
// 3. Let jsonObject be the result of running parse JSON from bytes on this’s received bytes. If that threw an exception, then return null.
|
||||
@ -214,7 +215,7 @@ WebIDL::ExceptionOr<JS::Value> XMLHttpRequest::response()
|
||||
String XMLHttpRequest::get_text_response() const
|
||||
{
|
||||
// 1. If xhr’s response’s body is null, then return the empty string.
|
||||
if (!m_response->body().has_value())
|
||||
if (!m_response->body())
|
||||
return String {};
|
||||
|
||||
// 2. Let charset be the result of get a final encoding for xhr.
|
||||
@ -559,8 +560,8 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
||||
|
||||
// body
|
||||
// This’s request body.
|
||||
if (m_request_body.has_value())
|
||||
request->set_body(m_request_body.value());
|
||||
if (m_request_body)
|
||||
request->set_body(JS::NonnullGCPtr { *m_request_body });
|
||||
|
||||
// client
|
||||
// This’s relevant settings object.
|
||||
@ -594,7 +595,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
||||
|
||||
// 9. If req’s body is null, then set this’s upload complete flag.
|
||||
// NOTE: req's body is always m_request_body here, see step 6.
|
||||
if (!m_request_body.has_value())
|
||||
if (!m_request_body)
|
||||
m_upload_complete = true;
|
||||
|
||||
// 10. Set this’s send() flag.
|
||||
@ -615,11 +616,11 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
||||
// NOTE: req's body is always m_request_body here, see step 6.
|
||||
// 4. Assert: requestBodyLength is an integer.
|
||||
// NOTE: This is done to provide a better assertion failure message, whereas below the message would be "m_has_value"
|
||||
if (m_request_body.has_value())
|
||||
if (m_request_body)
|
||||
VERIFY(m_request_body->length().has_value());
|
||||
|
||||
// NOTE: This is const to allow the callback functions to take a copy of it and know it won't change.
|
||||
auto const request_body_length = m_request_body.has_value() ? m_request_body->length().value() : 0;
|
||||
auto const request_body_length = m_request_body ? m_request_body->length().value() : 0;
|
||||
|
||||
// 5. If this’s upload complete flag is unset and this’s upload listener flag is set, then fire a progress event named loadstart at this’s upload object with requestBodyTransmitted and requestBodyLength.
|
||||
if (!m_upload_complete && m_upload_listener)
|
||||
@ -691,7 +692,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
||||
return;
|
||||
|
||||
// 7. If this’s response’s body is null, then run handle response end-of-body for this and return.
|
||||
if (!m_response->body().has_value()) {
|
||||
if (!m_response->body()) {
|
||||
// NOTE: This cannot throw, as `handle_response_end_of_body` only throws in a synchronous context.
|
||||
// FIXME: However, we can receive allocation failures, but we can't propagate them anywhere currently.
|
||||
handle_response_end_of_body().release_value_but_fixme_should_propagate_errors();
|
||||
|
@ -136,7 +136,7 @@ private:
|
||||
// https://xhr.spec.whatwg.org/#request-body
|
||||
// request body
|
||||
// Initially null.
|
||||
Optional<Fetch::Infrastructure::Body> m_request_body;
|
||||
JS::GCPtr<Fetch::Infrastructure::Body> m_request_body;
|
||||
|
||||
// https://xhr.spec.whatwg.org/#synchronous-flag
|
||||
// synchronous flag
|
||||
|
Loading…
Reference in New Issue
Block a user