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:
parent
953c19bdb7
commit
bdd3a16b16
21 changed files with 117 additions and 91 deletions
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue