1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 23:47:45 +00: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:
Aliaksandr Kalenik 2023-08-18 19:38:13 +02:00 committed by Andreas Kling
parent 953c19bdb7
commit bdd3a16b16
21 changed files with 117 additions and 91 deletions

View file

@ -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 bodys 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));

View file

@ -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);
}

View file

@ -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 requests body is non-null, set newRequests body to the result of cloning requests 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;

View file

@ -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>;

View file

@ -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 responses body is non-null, then set newResponses body to the result of cloning responses 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);
}
}

View file

@ -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;
};
}