1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 22:37:35 +00:00

LibWeb: Make Fetch::Infrastructure::{Request,Response,HeaderList} GC'd

This is the way.

On a more serious note, there's no reason to keep adding ref-counted
classes to LibWeb now that the majority of classes is GC'd - it only
adds the risk of discovering some cycle down the line, and forces us to
use handles as we can't visit().
This commit is contained in:
Linus Groh 2022-10-30 01:52:07 +00:00
parent 63122d0276
commit b1968b8bed
19 changed files with 270 additions and 169 deletions

View file

@ -20,9 +20,9 @@
namespace Web::Fetch {
Request::Request(JS::Realm& realm, NonnullRefPtr<Infrastructure::Request> request)
Request::Request(JS::Realm& realm, JS::NonnullGCPtr<Infrastructure::Request> request)
: PlatformObject(realm)
, m_request(move(request))
, m_request(request)
{
set_prototype(&Bindings::cached_web_prototype(realm, "Request"));
}
@ -32,6 +32,7 @@ Request::~Request() = default;
void Request::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_request);
visitor.visit(m_headers);
visitor.visit(m_signal);
}
@ -72,18 +73,14 @@ Optional<Infrastructure::Body&> Request::body_impl()
}
// https://fetch.spec.whatwg.org/#request-create
JS::NonnullGCPtr<Request> Request::create(NonnullRefPtr<Infrastructure::Request> request, Headers::Guard guard, JS::Realm& realm)
JS::NonnullGCPtr<Request> Request::create(JS::Realm& realm, JS::NonnullGCPtr<Infrastructure::Request> request, Headers::Guard guard)
{
// Copy a NonnullRefPtr to the request's header list before request is being move()'d.
auto request_reader_list = request->header_list();
// 1. Let requestObject be a new Request object with realm.
// 2. Set requestObjects request to request.
auto* request_object = realm.heap().allocate<Request>(realm, realm, move(request));
auto* request_object = realm.heap().allocate<Request>(realm, realm, request);
// 3. Set requestObjects headers to a new Headers object with realm, whose headers list is requests headers list and guard is guard.
request_object->m_headers = realm.heap().allocate<Headers>(realm, realm);
request_object->m_headers->set_header_list(move(request_reader_list));
request_object->m_headers = realm.heap().allocate<Headers>(realm, realm, request->header_list());
request_object->m_headers->set_guard(guard);
// 4. Set requestObjects signal to a new AbortSignal object with realm.
@ -96,11 +93,13 @@ JS::NonnullGCPtr<Request> Request::create(NonnullRefPtr<Infrastructure::Request>
// https://fetch.spec.whatwg.org/#dom-request
WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm& realm, RequestInfo const& input, RequestInit const& init)
{
auto& vm = realm.vm();
// Referred to as 'this' in the spec.
auto request_object = JS::NonnullGCPtr { *realm.heap().allocate<Request>(realm, realm, Infrastructure::Request::create()) };
auto request_object = JS::NonnullGCPtr { *realm.heap().allocate<Request>(realm, realm, Infrastructure::Request::create(vm)) };
// 1. Let request be null.
RefPtr<Infrastructure::Request> input_request;
JS::GCPtr<Infrastructure::Request> input_request;
// 2. Let fallbackMode be null.
Optional<Infrastructure::Request::Mode> fallback_mode;
@ -125,7 +124,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Input URL must not include credentials"sv };
// 4. Set request to a new request whose URL is parsedURL.
input_request = Infrastructure::Request::create();
input_request = Infrastructure::Request::create(vm);
input_request->set_url(move(parsed_url));
// 5. Set fallbackMode to "cors".
@ -179,10 +178,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
// header list
// A copy of requests header list.
auto header_list_copy = make_ref_counted<Infrastructure::HeaderList>();
auto header_list_copy = Infrastructure::HeaderList::create(vm);
for (auto& header : *request->header_list())
TRY_OR_RETURN_OOM(realm, header_list_copy->append(header));
request->set_header_list(move(header_list_copy));
request->set_header_list(header_list_copy);
// unsafe-request flag
// Set.
@ -389,8 +388,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
request_object->m_signal->follow(*input_signal);
// 30. Set thiss headers to a new Headers object with thiss relevant Realm, whose header list is requests header list and guard is "request".
request_object->m_headers = realm.heap().allocate<Headers>(realm, realm);
request_object->m_headers->set_header_list(request->header_list());
request_object->m_headers = realm.heap().allocate<Headers>(realm, realm, request->header_list());
request_object->m_headers->set_guard(Headers::Guard::Request);
// 31. If thiss requests mode is "no-cors", then:
@ -406,7 +404,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
// 32. If init is not empty, then:
if (!init.is_empty()) {
// 1. Let headers be a copy of thiss headers and its associated header list.
auto headers = Variant<HeadersInit, NonnullRefPtr<Infrastructure::HeaderList>> { request_object->headers()->header_list() };
auto headers = Variant<HeadersInit, JS::NonnullGCPtr<Infrastructure::HeaderList>> { request_object->headers()->header_list() };
// 2. If init["headers"] exists, then set headers to init["headers"].
if (init.headers.has_value())
@ -416,9 +414,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
request_object->headers()->header_list()->clear();
// 4. If headers is a Headers object, then for each header in its header list, append (headers name, headers value) to thiss headers.
if (headers.has<NonnullRefPtr<Infrastructure::HeaderList>>()) {
auto& header_list = *headers.get<NonnullRefPtr<Infrastructure::HeaderList>>();
for (auto& header : header_list)
if (auto* header_list = headers.get_pointer<JS::NonnullGCPtr<Infrastructure::HeaderList>>()) {
for (auto& header : *header_list->ptr())
TRY(request_object->headers()->append(String::copy(header.name), String::copy(header.value)));
}
// 5. Otherwise, fill thiss headers with headers.
@ -624,15 +621,17 @@ Bindings::RequestDuplex Request::duplex() const
// https://fetch.spec.whatwg.org/#dom-request-clone
WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::clone() const
{
auto& vm = this->vm();
// 1. If this is unusable, then throw a TypeError.
if (is_unusable())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request is unusable"sv };
// 2. Let clonedRequest be the result of cloning thiss request.
auto cloned_request = TRY(m_request->clone());
auto cloned_request = TRY(m_request->clone(vm));
// 3. Let clonedRequestObject be the result of creating a Request object, given clonedRequest, thiss headerss guard, and thiss relevant Realm.
auto cloned_request_object = Request::create(move(cloned_request), m_headers->guard(), HTML::relevant_realm(*this));
auto cloned_request_object = Request::create(HTML::relevant_realm(*this), cloned_request, m_headers->guard());
// 4. Make clonedRequestObjects signal follow thiss signal.
cloned_request_object->m_signal->follow(*m_signal);