Parcourir la source

LibWeb: Make Fetch::Infrastructure::{Request,Response} ref-counted

With the addition of the 'fetch params' struct, the single ownership
model we had so far falls apart completely.

Additionally, this works nicely for FilteredResponse's internal response
instead of risking a dangling reference.

Replacing the public constructor with a create() function also found a
few instances of a Request being stack-allocated!
Linus Groh il y a 2 ans
Parent
commit
1c12f5c31d

+ 45 - 5
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp

@@ -14,6 +14,11 @@ Request::Request()
 {
 }
 
+NonnullRefPtr<Request> Request::create()
+{
+    return adopt_ref(*new Request());
+}
+
 // https://fetch.spec.whatwg.org/#concept-request-url
 AK::URL const& Request::url() const
 {
@@ -164,15 +169,50 @@ ErrorOr<ByteBuffer> Request::byte_serialize_origin() const
 }
 
 // https://fetch.spec.whatwg.org/#concept-request-clone
-WebIDL::ExceptionOr<NonnullOwnPtr<Request>> Request::clone() const
+WebIDL::ExceptionOr<NonnullRefPtr<Request>> Request::clone() const
 {
     // To clone a request request, run these steps:
 
     // 1. Let newRequest be a copy of request, except for its body.
-    BodyType tmp_body;
-    swap(tmp_body, const_cast<BodyType&>(m_body));
-    auto new_request = make<Infrastructure::Request>(*this);
-    swap(tmp_body, const_cast<BodyType&>(m_body));
+    auto new_request = Infrastructure::Request::create();
+    new_request->set_method(m_method);
+    new_request->set_local_urls_only(m_local_urls_only);
+    for (auto const& header : *m_header_list)
+        MUST(new_request->header_list()->append(header));
+    new_request->set_unsafe_request(m_unsafe_request);
+    new_request->set_client(m_client);
+    new_request->set_reserved_client(m_reserved_client);
+    new_request->set_replaces_client_id(m_replaces_client_id);
+    new_request->set_window(m_window);
+    new_request->set_keepalive(m_keepalive);
+    new_request->set_initiator_type(m_initiator_type);
+    new_request->set_service_workers_mode(m_service_workers_mode);
+    new_request->set_initiator(m_initiator);
+    new_request->set_destination(m_destination);
+    new_request->set_priority(m_priority);
+    new_request->set_origin(m_origin);
+    new_request->set_policy_container(m_policy_container);
+    new_request->set_referrer(m_referrer);
+    new_request->set_referrer_policy(m_referrer_policy);
+    new_request->set_mode(m_mode);
+    new_request->set_use_cors_preflight(m_use_cors_preflight);
+    new_request->set_credentials_mode(m_credentials_mode);
+    new_request->set_use_url_credentials(m_use_url_credentials);
+    new_request->set_cache_mode(m_cache_mode);
+    new_request->set_redirect_mode(m_redirect_mode);
+    new_request->set_integrity_metadata(m_integrity_metadata);
+    new_request->set_cryptographic_nonce_metadata(m_cryptographic_nonce_metadata);
+    new_request->set_parser_metadata(m_parser_metadata);
+    new_request->set_reload_navigation(m_reload_navigation);
+    new_request->set_history_navigation(m_history_navigation);
+    new_request->set_user_activation(m_user_activation);
+    new_request->set_render_blocking(m_render_blocking);
+    new_request->set_url_list(m_url_list);
+    new_request->set_redirect_count(m_redirect_count);
+    new_request->set_response_tainting(m_response_tainting);
+    new_request->set_prevent_no_cache_cache_control_header_modification(m_prevent_no_cache_cache_control_header_modification);
+    new_request->set_done(m_done);
+    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>())

+ 6 - 3
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h

@@ -10,6 +10,7 @@
 #include <AK/Error.h>
 #include <AK/Forward.h>
 #include <AK/Optional.h>
+#include <AK/RefCounted.h>
 #include <AK/String.h>
 #include <AK/URL.h>
 #include <AK/Variant.h>
@@ -23,7 +24,7 @@
 namespace Web::Fetch::Infrastructure {
 
 // https://fetch.spec.whatwg.org/#concept-request
-class Request final {
+class Request final : public RefCounted<Request> {
 public:
     enum class CacheMode {
         Default,
@@ -154,7 +155,7 @@ public:
     using ReservedClientType = Variant<Empty, HTML::Environment*, HTML::EnvironmentSettingsObject*>;
     using WindowType = Variant<Window, HTML::EnvironmentSettingsObject*>;
 
-    Request();
+    static NonnullRefPtr<Request> create();
 
     [[nodiscard]] ReadonlyBytes method() const { return m_method; }
     void set_method(ByteBuffer method) { m_method = move(method); }
@@ -290,13 +291,15 @@ public:
     [[nodiscard]] String serialize_origin() const;
     [[nodiscard]] ErrorOr<ByteBuffer> byte_serialize_origin() const;
 
-    [[nodiscard]] WebIDL::ExceptionOr<NonnullOwnPtr<Request>> clone() const;
+    [[nodiscard]] WebIDL::ExceptionOr<NonnullRefPtr<Request>> clone() const;
 
     [[nodiscard]] ErrorOr<void> add_range_reader(u64 first, Optional<u64> const& last);
 
     [[nodiscard]] bool cross_origin_embedder_policy_allows_credentials() const;
 
 private:
+    Request();
+
     // https://fetch.spec.whatwg.org/#concept-request-method
     // A request has an associated method (a method). Unless stated otherwise it is `GET`.
     ByteBuffer m_method { ByteBuffer::copy("GET"sv.bytes()).release_value() };

+ 45 - 29
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp

@@ -14,20 +14,25 @@ Response::Response()
 {
 }
 
+NonnullRefPtr<Response> Response::create()
+{
+    return adopt_ref(*new Response());
+}
+
 // https://fetch.spec.whatwg.org/#ref-for-concept-network-error%E2%91%A3
 // A network error is a response whose status is always 0, status message is always
 // the empty byte sequence, header list is always empty, and body is always null.
 
-NonnullOwnPtr<Response> Response::aborted_network_error()
+NonnullRefPtr<Response> Response::aborted_network_error()
 {
     auto response = network_error();
     response->set_aborted(true);
     return response;
 }
 
-NonnullOwnPtr<Response> Response::network_error()
+NonnullRefPtr<Response> Response::network_error()
 {
-    auto response = make<Response>();
+    auto response = Response::create();
     response->set_status(0);
     response->set_type(Type::Error);
     VERIFY(!response->body().has_value());
@@ -83,17 +88,28 @@ ErrorOr<Optional<AK::URL>> Response::location_url(Optional<String> const& reques
 }
 
 // https://fetch.spec.whatwg.org/#concept-response-clone
-WebIDL::ExceptionOr<NonnullOwnPtr<Response>> Response::clone() const
+WebIDL::ExceptionOr<NonnullRefPtr<Response>> Response::clone() const
 {
     // To clone a response response, run these steps:
 
     // FIXME: 1. If response is a filtered response, then return a new identical filtered response whose internal response is a clone of response’s internal response.
 
     // 2. Let newResponse be a copy of response, except for its body.
-    Optional<Body> tmp_body;
-    swap(tmp_body, const_cast<Optional<Body>&>(m_body));
-    auto new_response = make<Infrastructure::Response>(*this);
-    swap(tmp_body, const_cast<Optional<Body>&>(m_body));
+    auto new_response = Infrastructure::Response::create();
+    new_response->set_type(m_type);
+    new_response->set_aborted(m_aborted);
+    new_response->set_url_list(m_url_list);
+    new_response->set_status(m_status);
+    new_response->set_status_message(m_status_message);
+    for (auto const& header : *m_header_list)
+        MUST(new_response->header_list()->append(header));
+    new_response->set_cache_state(m_cache_state);
+    new_response->set_cors_exposed_header_name_list(m_cors_exposed_header_name_list);
+    new_response->set_range_requested(m_range_requested);
+    new_response->set_request_includes_credentials(m_request_includes_credentials);
+    new_response->set_timing_allow_passed(m_timing_allow_passed);
+    new_response->set_body_info(m_body_info);
+    // 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())
@@ -103,8 +119,8 @@ WebIDL::ExceptionOr<NonnullOwnPtr<Response>> Response::clone() const
     return new_response;
 }
 
-FilteredResponse::FilteredResponse(Response& internal_response)
-    : m_internal_response(internal_response)
+FilteredResponse::FilteredResponse(NonnullRefPtr<Response> internal_response)
+    : m_internal_response(move(internal_response))
 {
 }
 
@@ -112,69 +128,69 @@ FilteredResponse::~FilteredResponse()
 {
 }
 
-ErrorOr<NonnullOwnPtr<BasicFilteredResponse>> BasicFilteredResponse::create(Response& internal_response)
+ErrorOr<NonnullRefPtr<BasicFilteredResponse>> BasicFilteredResponse::create(NonnullRefPtr<Response> internal_response)
 {
     // A basic filtered response is a filtered response whose type is "basic" and header list excludes
     // any headers in internal response’s header list whose name is a forbidden response-header name.
     auto header_list = make_ref_counted<HeaderList>();
-    for (auto const& header : *internal_response.header_list()) {
+    for (auto const& header : *internal_response->header_list()) {
         if (!is_forbidden_response_header_name(header.name))
             TRY(header_list->append(header));
     }
 
-    return adopt_own(*new BasicFilteredResponse(internal_response, move(header_list)));
+    return adopt_ref(*new BasicFilteredResponse(internal_response, move(header_list)));
 }
 
-BasicFilteredResponse::BasicFilteredResponse(Response& internal_response, NonnullRefPtr<HeaderList> header_list)
-    : FilteredResponse(internal_response)
+BasicFilteredResponse::BasicFilteredResponse(NonnullRefPtr<Response> internal_response, NonnullRefPtr<HeaderList> header_list)
+    : FilteredResponse(move(internal_response))
     , m_header_list(move(header_list))
 {
 }
 
-ErrorOr<NonnullOwnPtr<CORSFilteredResponse>> CORSFilteredResponse::create(Response& internal_response)
+ErrorOr<NonnullRefPtr<CORSFilteredResponse>> CORSFilteredResponse::create(NonnullRefPtr<Response> internal_response)
 {
     // A CORS filtered response is a filtered response whose type is "cors" and header list excludes
     // any headers in internal response’s header list whose name is not a CORS-safelisted response-header
     // name, given internal response’s CORS-exposed header-name list.
     Vector<ReadonlyBytes> cors_exposed_header_name_list;
-    for (auto const& header_name : internal_response.cors_exposed_header_name_list())
+    for (auto const& header_name : internal_response->cors_exposed_header_name_list())
         cors_exposed_header_name_list.append(header_name.span());
 
     auto header_list = make_ref_counted<HeaderList>();
-    for (auto const& header : *internal_response.header_list()) {
+    for (auto const& header : *internal_response->header_list()) {
         if (is_cors_safelisted_response_header_name(header.name, cors_exposed_header_name_list))
             TRY(header_list->append(header));
     }
 
-    return adopt_own(*new CORSFilteredResponse(internal_response, move(header_list)));
+    return adopt_ref(*new CORSFilteredResponse(internal_response, move(header_list)));
 }
 
-CORSFilteredResponse::CORSFilteredResponse(Response& internal_response, NonnullRefPtr<HeaderList> header_list)
-    : FilteredResponse(internal_response)
+CORSFilteredResponse::CORSFilteredResponse(NonnullRefPtr<Response> internal_response, NonnullRefPtr<HeaderList> header_list)
+    : FilteredResponse(move(internal_response))
     , m_header_list(move(header_list))
 {
 }
 
-NonnullOwnPtr<OpaqueFilteredResponse> OpaqueFilteredResponse::create(Response& internal_response)
+NonnullRefPtr<OpaqueFilteredResponse> OpaqueFilteredResponse::create(NonnullRefPtr<Response> internal_response)
 {
     // An opaque-redirect filtered response is a filtered response whose type is "opaqueredirect",
     // status is 0, status message is the empty byte sequence, header list is empty, and body is null.
-    return adopt_own(*new OpaqueFilteredResponse(internal_response));
+    return adopt_ref(*new OpaqueFilteredResponse(move(internal_response)));
 }
 
-OpaqueFilteredResponse::OpaqueFilteredResponse(Response& internal_response)
-    : FilteredResponse(internal_response)
+OpaqueFilteredResponse::OpaqueFilteredResponse(NonnullRefPtr<Response> internal_response)
+    : FilteredResponse(move(internal_response))
     , m_header_list(make_ref_counted<HeaderList>())
 {
 }
 
-NonnullOwnPtr<OpaqueRedirectFilteredResponse> OpaqueRedirectFilteredResponse::create(Response& internal_response)
+NonnullRefPtr<OpaqueRedirectFilteredResponse> OpaqueRedirectFilteredResponse::create(NonnullRefPtr<Response> internal_response)
 {
-    return adopt_own(*new OpaqueRedirectFilteredResponse(internal_response));
+    return adopt_ref(*new OpaqueRedirectFilteredResponse(move(internal_response)));
 }
 
-OpaqueRedirectFilteredResponse::OpaqueRedirectFilteredResponse(Response& internal_response)
-    : FilteredResponse(internal_response)
+OpaqueRedirectFilteredResponse::OpaqueRedirectFilteredResponse(NonnullRefPtr<Response> internal_response)
+    : FilteredResponse(move(internal_response))
     , m_header_list(make_ref_counted<HeaderList>())
 {
 }

+ 34 - 31
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h

@@ -10,6 +10,7 @@
 #include <AK/Error.h>
 #include <AK/Forward.h>
 #include <AK/Optional.h>
+#include <AK/RefCounted.h>
 #include <AK/URL.h>
 #include <AK/Vector.h>
 #include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
@@ -19,7 +20,7 @@
 namespace Web::Fetch::Infrastructure {
 
 // https://fetch.spec.whatwg.org/#concept-response
-class Response {
+class Response : public RefCounted<Response> {
 public:
     enum class CacheState {
         Local,
@@ -44,10 +45,10 @@ public:
         u64 decoded_size { 0 };
     };
 
-    [[nodiscard]] static NonnullOwnPtr<Response> aborted_network_error();
-    [[nodiscard]] static NonnullOwnPtr<Response> network_error();
+    [[nodiscard]] static NonnullRefPtr<Response> create();
+    [[nodiscard]] static NonnullRefPtr<Response> aborted_network_error();
+    [[nodiscard]] static NonnullRefPtr<Response> network_error();
 
-    Response();
     virtual ~Response() = default;
 
     [[nodiscard]] virtual Type type() const { return m_type; }
@@ -100,7 +101,10 @@ public:
     [[nodiscard]] Optional<AK::URL const&> url() const;
     [[nodiscard]] ErrorOr<Optional<AK::URL>> location_url(Optional<String> const& request_fragment) const;
 
-    [[nodiscard]] WebIDL::ExceptionOr<NonnullOwnPtr<Response>> clone() const;
+    [[nodiscard]] WebIDL::ExceptionOr<NonnullRefPtr<Response>> clone() const;
+
+protected:
+    Response();
 
 private:
     // https://fetch.spec.whatwg.org/#concept-response-type
@@ -162,41 +166,40 @@ private:
 // https://fetch.spec.whatwg.org/#concept-filtered-response
 class FilteredResponse : public Response {
 public:
-    explicit FilteredResponse(Response&);
+    explicit FilteredResponse(NonnullRefPtr<Response>);
     virtual ~FilteredResponse() = 0;
 
-    [[nodiscard]] virtual Type type() const override { return m_internal_response.type(); }
-    [[nodiscard]] virtual bool aborted() const override { return m_internal_response.aborted(); }
-    [[nodiscard]] virtual Vector<AK::URL> const& url_list() const override { return m_internal_response.url_list(); }
-    [[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 NonnullRefPtr<HeaderList> const& 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<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(); }
-    [[nodiscard]] virtual bool request_includes_credentials() const override { return m_internal_response.request_includes_credentials(); }
-    [[nodiscard]] virtual bool timing_allow_passed() const override { return m_internal_response.timing_allow_passed(); }
-    [[nodiscard]] virtual BodyInfo const& body_info() const override { return m_internal_response.body_info(); }
-
-    [[nodiscard]] Response const& internal_response() const { return m_internal_response; }
-    [[nodiscard]] Response& internal_response() { return m_internal_response; }
+    [[nodiscard]] virtual Type type() const override { return m_internal_response->type(); }
+    [[nodiscard]] virtual bool aborted() const override { return m_internal_response->aborted(); }
+    [[nodiscard]] virtual Vector<AK::URL> const& url_list() const override { return m_internal_response->url_list(); }
+    [[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 NonnullRefPtr<HeaderList> const& 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<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(); }
+    [[nodiscard]] virtual bool request_includes_credentials() const override { return m_internal_response->request_includes_credentials(); }
+    [[nodiscard]] virtual bool timing_allow_passed() const override { return m_internal_response->timing_allow_passed(); }
+    [[nodiscard]] virtual BodyInfo const& body_info() const override { return m_internal_response->body_info(); }
+
+    [[nodiscard]] NonnullRefPtr<Response> internal_response() const { return m_internal_response; }
 
 protected:
     // https://fetch.spec.whatwg.org/#concept-internal-response
-    Response& m_internal_response;
+    NonnullRefPtr<Response> m_internal_response;
 };
 
 // https://fetch.spec.whatwg.org/#concept-filtered-response-basic
 class BasicFilteredResponse final : public FilteredResponse {
 public:
-    static ErrorOr<NonnullOwnPtr<BasicFilteredResponse>> create(Response&);
+    static ErrorOr<NonnullRefPtr<BasicFilteredResponse>> create(NonnullRefPtr<Response>);
 
     [[nodiscard]] virtual Type type() const override { return Type::Basic; }
     [[nodiscard]] virtual NonnullRefPtr<HeaderList> const& header_list() const override { return m_header_list; }
 
 private:
-    BasicFilteredResponse(Response&, NonnullRefPtr<HeaderList>);
+    BasicFilteredResponse(NonnullRefPtr<Response>, NonnullRefPtr<HeaderList>);
 
     NonnullRefPtr<HeaderList> m_header_list;
 };
@@ -204,13 +207,13 @@ private:
 // https://fetch.spec.whatwg.org/#concept-filtered-response-cors
 class CORSFilteredResponse final : public FilteredResponse {
 public:
-    static ErrorOr<NonnullOwnPtr<CORSFilteredResponse>> create(Response&);
+    static ErrorOr<NonnullRefPtr<CORSFilteredResponse>> create(NonnullRefPtr<Response>);
 
     [[nodiscard]] virtual Type type() const override { return Type::CORS; }
     [[nodiscard]] virtual NonnullRefPtr<HeaderList> const& header_list() const override { return m_header_list; }
 
 private:
-    CORSFilteredResponse(Response&, NonnullRefPtr<HeaderList>);
+    CORSFilteredResponse(NonnullRefPtr<Response>, NonnullRefPtr<HeaderList>);
 
     NonnullRefPtr<HeaderList> m_header_list;
 };
@@ -218,7 +221,7 @@ private:
 // https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
 class OpaqueFilteredResponse final : public FilteredResponse {
 public:
-    static NonnullOwnPtr<OpaqueFilteredResponse> create(Response&);
+    static NonnullRefPtr<OpaqueFilteredResponse> create(NonnullRefPtr<Response>);
 
     [[nodiscard]] virtual Type type() const override { return Type::Opaque; }
     [[nodiscard]] virtual Vector<AK::URL> const& url_list() const override { return m_url_list; }
@@ -228,7 +231,7 @@ public:
     [[nodiscard]] virtual Optional<Body> const& body() const override { return m_body; }
 
 private:
-    explicit OpaqueFilteredResponse(Response&);
+    explicit OpaqueFilteredResponse(NonnullRefPtr<Response>);
 
     Vector<AK::URL> m_url_list;
     NonnullRefPtr<HeaderList> m_header_list;
@@ -238,7 +241,7 @@ private:
 // https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect
 class OpaqueRedirectFilteredResponse final : public FilteredResponse {
 public:
-    static NonnullOwnPtr<OpaqueRedirectFilteredResponse> create(Response&);
+    static NonnullRefPtr<OpaqueRedirectFilteredResponse> create(NonnullRefPtr<Response>);
 
     [[nodiscard]] virtual Type type() const override { return Type::OpaqueRedirect; }
     [[nodiscard]] virtual Status status() const override { return 0; }
@@ -247,7 +250,7 @@ public:
     [[nodiscard]] virtual Optional<Body> const& body() const override { return m_body; }
 
 private:
-    explicit OpaqueRedirectFilteredResponse(Response&);
+    explicit OpaqueRedirectFilteredResponse(NonnullRefPtr<Response>);
 
     NonnullRefPtr<HeaderList> m_header_list;
     Optional<Body> m_body;

+ 58 - 67
Userland/Libraries/LibWeb/Fetch/Request.cpp

@@ -4,7 +4,6 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include <AK/ScopeGuard.h>
 #include <AK/URLParser.h>
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/DOM/AbortSignal.h>
@@ -20,7 +19,7 @@
 
 namespace Web::Fetch {
 
-Request::Request(JS::Realm& realm, NonnullOwnPtr<Infrastructure::Request> request)
+Request::Request(JS::Realm& realm, NonnullRefPtr<Infrastructure::Request> request)
     : PlatformObject(realm)
     , m_request(move(request))
 {
@@ -72,7 +71,7 @@ Optional<Infrastructure::Body&> Request::body_impl()
 }
 
 // https://fetch.spec.whatwg.org/#request-create
-JS::NonnullGCPtr<Request> Request::create(NonnullOwnPtr<Infrastructure::Request> request, Headers::Guard guard, JS::Realm& realm)
+JS::NonnullGCPtr<Request> Request::create(NonnullRefPtr<Infrastructure::Request> request, Headers::Guard guard, JS::Realm& realm)
 {
     // Copy a NonnullRefPtr to the request's header list before request is being move()'d.
     auto request_reader_list = request->header_list();
@@ -97,16 +96,10 @@ JS::NonnullGCPtr<Request> Request::create(NonnullOwnPtr<Infrastructure::Request>
 WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm& realm, RequestInfo const& input, RequestInit const& init)
 {
     // Referred to as 'this' in the spec.
-    auto request_object = JS::NonnullGCPtr { *realm.heap().allocate<Request>(realm, realm, make<Infrastructure::Request>()) };
+    auto request_object = JS::NonnullGCPtr { *realm.heap().allocate<Request>(realm, realm, Infrastructure::Request::create()) };
 
     // 1. Let request be null.
-    Infrastructure::Request const* input_request = nullptr;
-
-    // Cleanup for the special case where we create a temporary Request ourselves
-    // instead of just taking a pointer from something else.
-    ArmedScopeGuard delete_input_request { [&] {
-        delete input_request;
-    } };
+    RefPtr<Infrastructure::Request> input_request;
 
     // 2. Let fallbackMode be null.
     Optional<Infrastructure::Request::Mode> fallback_mode;
@@ -131,9 +124,8 @@ 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.
-        auto* new_request = new Infrastructure::Request();
-        new_request->set_url(move(parsed_url));
-        input_request = new_request;
+        input_request = Infrastructure::Request::create();
+        input_request->set_url(move(parsed_url));
 
         // 5. Set fallbackMode to "cors".
         fallback_mode = Infrastructure::Request::Mode::CORS;
@@ -144,8 +136,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
         VERIFY(input.has<JS::Handle<Request>>());
 
         // 2. Set request to input’s request.
-        input_request = &input.get<JS::Handle<Request>>()->request();
-        delete_input_request.disarm();
+        input_request = input.get<JS::Handle<Request>>()->request();
 
         // 3. Set signal to input’s signal.
         input_signal = input.get<JS::Handle<Request>>()->signal();
@@ -175,114 +166,114 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
     // 12. Set request to a new request with the following properties:
     // NOTE: This is done at the beginning as the 'this' value Request object
     //       cannot exist with a null Infrastructure::Request.
-    auto& request = request_object->request();
+    auto request = request_object->request();
 
     // URL
     //     request’s URL.
-    request.set_url(input_request->url());
+    request->set_url(input_request->url());
 
     // method
     //     request’s method.
-    request.set_method(TRY_OR_RETURN_OOM(realm, ByteBuffer::copy(request.method())));
+    request->set_method(TRY_OR_RETURN_OOM(realm, ByteBuffer::copy(request->method())));
 
     // header list
     //     A copy of request’s header list.
     auto header_list_copy = make_ref_counted<Infrastructure::HeaderList>();
-    for (auto& header : *request.header_list())
+    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(move(header_list_copy));
 
     // unsafe-request flag
     //     Set.
-    request.set_unsafe_request(true);
+    request->set_unsafe_request(true);
 
     // client
     //     This’s relevant settings object.
-    request.set_client(&HTML::relevant_settings_object(*request_object));
+    request->set_client(&HTML::relevant_settings_object(*request_object));
 
     // window
     //     window.
-    request.set_window(window);
+    request->set_window(window);
 
     // priority
     //     request’s priority.
-    request.set_priority(input_request->priority());
+    request->set_priority(input_request->priority());
 
     // origin
     //     request’s origin. The propagation of the origin is only significant for navigation requests being handled by a service worker. In this scenario a request can have an origin that is different from the current client.
-    request.set_origin(input_request->origin());
+    request->set_origin(input_request->origin());
 
     // referrer
     //     request’s referrer.
-    request.set_referrer(input_request->referrer());
+    request->set_referrer(input_request->referrer());
 
     // referrer policy
     //     request’s referrer policy.
-    request.set_referrer_policy(input_request->referrer_policy());
+    request->set_referrer_policy(input_request->referrer_policy());
 
     // mode
     //     request’s mode.
-    request.set_mode(input_request->mode());
+    request->set_mode(input_request->mode());
 
     // credentials mode
     //     request’s credentials mode.
-    request.set_credentials_mode(input_request->credentials_mode());
+    request->set_credentials_mode(input_request->credentials_mode());
 
     // cache mode
     //     request’s cache mode.
-    request.set_cache_mode(input_request->cache_mode());
+    request->set_cache_mode(input_request->cache_mode());
 
     // redirect mode
     //     request’s redirect mode.
-    request.set_redirect_mode(input_request->redirect_mode());
+    request->set_redirect_mode(input_request->redirect_mode());
 
     // integrity metadata
     //     request’s integrity metadata.
-    request.set_integrity_metadata(input_request->integrity_metadata());
+    request->set_integrity_metadata(input_request->integrity_metadata());
 
     // keepalive
     //     request’s keepalive.
-    request.set_keepalive(input_request->keepalive());
+    request->set_keepalive(input_request->keepalive());
 
     // reload-navigation flag
     //     request’s reload-navigation flag.
-    request.set_reload_navigation(input_request->reload_navigation());
+    request->set_reload_navigation(input_request->reload_navigation());
 
     // history-navigation flag
     //     request’s history-navigation flag.
-    request.set_history_navigation(input_request->history_navigation());
+    request->set_history_navigation(input_request->history_navigation());
 
     // URL list
     //     A clone of request’s URL list.
-    request.set_url_list(input_request->url_list());
+    request->set_url_list(input_request->url_list());
 
     // initiator type
     //     "fetch".
-    request.set_initiator_type(Infrastructure::Request::InitiatorType::Fetch);
+    request->set_initiator_type(Infrastructure::Request::InitiatorType::Fetch);
 
     // 13. If init is not empty, then:
     if (!init.is_empty()) {
         // 1. If request’s mode is "navigate", then set it to "same-origin".
-        if (request.mode() == Infrastructure::Request::Mode::Navigate)
-            request.set_mode(Infrastructure::Request::Mode::SameOrigin);
+        if (request->mode() == Infrastructure::Request::Mode::Navigate)
+            request->set_mode(Infrastructure::Request::Mode::SameOrigin);
 
         // 2. Unset request’s reload-navigation flag.
-        request.set_reload_navigation(false);
+        request->set_reload_navigation(false);
 
         // 3. Unset request’s history-navigation flag.
-        request.set_history_navigation(false);
+        request->set_history_navigation(false);
 
         // 4. Set request’s origin to "client".
-        request.set_origin(Infrastructure::Request::Origin::Client);
+        request->set_origin(Infrastructure::Request::Origin::Client);
 
         // 5. Set request’s referrer to "client".
-        request.set_referrer(Infrastructure::Request::Referrer::Client);
+        request->set_referrer(Infrastructure::Request::Referrer::Client);
 
         // 6. Set request’s referrer policy to the empty string.
-        request.set_referrer_policy({});
+        request->set_referrer_policy({});
 
         // 7. Set request’s URL to request’s current URL.
-        request.set_url(request.current_url());
+        request->set_url(request->current_url());
 
         // 8. Set request’s URL list to « request’s URL ».
         // NOTE: This is done implicitly by assigning the initial URL above.
@@ -295,7 +286,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
 
         // 2. If referrer is the empty string, then set request’s referrer to "no-referrer".
         if (referrer.is_empty()) {
-            request.set_referrer(Infrastructure::Request::Referrer::NoReferrer);
+            request->set_referrer(Infrastructure::Request::Referrer::NoReferrer);
         }
         // 3. Otherwise:
         else {
@@ -312,18 +303,18 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
             // then set request’s referrer to "client".
             // FIXME: Actually use the given origin once we have https://url.spec.whatwg.org/#concept-url-origin.
             if ((parsed_referrer.scheme() == "about"sv && parsed_referrer.path() == "client"sv) || !HTML::Origin().is_same_origin(origin)) {
-                request.set_referrer(Infrastructure::Request::Referrer::Client);
+                request->set_referrer(Infrastructure::Request::Referrer::Client);
             }
             // 4. Otherwise, set request’s referrer to parsedReferrer.
             else {
-                request.set_referrer(move(parsed_referrer));
+                request->set_referrer(move(parsed_referrer));
             }
         }
     }
 
     // 15. If init["referrerPolicy"] exists, then set request’s referrer policy to it.
     if (init.referrer_policy.has_value())
-        request.set_referrer_policy(from_bindings_enum(*init.referrer_policy));
+        request->set_referrer_policy(from_bindings_enum(*init.referrer_policy));
 
     // 16. Let mode be init["mode"] if it exists, and fallbackMode otherwise.
     auto mode = init.mode.has_value()
@@ -336,31 +327,31 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
 
     // 18. If mode is non-null, set request’s mode to mode.
     if (mode.has_value())
-        request.set_mode(*mode);
+        request->set_mode(*mode);
 
     // 19. If init["credentials"] exists, then set request’s credentials mode to it.
     if (init.credentials.has_value())
-        request.set_credentials_mode(from_bindings_enum(*init.credentials));
+        request->set_credentials_mode(from_bindings_enum(*init.credentials));
 
     // 20. If init["cache"] exists, then set request’s cache mode to it.
     if (init.cache.has_value())
-        request.set_cache_mode(from_bindings_enum(*init.cache));
+        request->set_cache_mode(from_bindings_enum(*init.cache));
 
     // 21. If request’s cache mode is "only-if-cached" and request’s mode is not "same-origin", then throw a TypeError.
-    if (request.cache_mode() == Infrastructure::Request::CacheMode::OnlyIfCached && request.mode() != Infrastructure::Request::Mode::SameOrigin)
+    if (request->cache_mode() == Infrastructure::Request::CacheMode::OnlyIfCached && request->mode() != Infrastructure::Request::Mode::SameOrigin)
         return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Mode must be 'same-origin' when cache mode is 'only-if-cached'"sv };
 
     // 22. If init["redirect"] exists, then set request’s redirect mode to it.
     if (init.redirect.has_value())
-        request.set_redirect_mode(from_bindings_enum(*init.redirect));
+        request->set_redirect_mode(from_bindings_enum(*init.redirect));
 
     // 23. If init["integrity"] exists, then set request’s integrity metadata to it.
     if (init.integrity.has_value())
-        request.set_integrity_metadata(*init.integrity);
+        request->set_integrity_metadata(*init.integrity);
 
     // 24. If init["keepalive"] exists, then set request’s keepalive to it.
     if (init.keepalive.has_value())
-        request.set_keepalive(*init.keepalive);
+        request->set_keepalive(*init.keepalive);
 
     // 25. If init["method"] exists, then:
     if (init.method.has_value()) {
@@ -377,7 +368,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
         method = TRY_OR_RETURN_OOM(realm, Infrastructure::normalize_method(method.bytes()));
 
         // 4. Set request’s method to method.
-        request.set_method(MUST(ByteBuffer::copy(method.bytes())));
+        request->set_method(MUST(ByteBuffer::copy(method.bytes())));
     }
 
     // 26. If init["signal"] exists, then set signal to it.
@@ -399,13 +390,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
 
     // 30. Set this’s headers to a new Headers object with this’s relevant Realm, whose header list is request’s 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->set_header_list(request->header_list());
     request_object->m_headers->set_guard(Headers::Guard::Request);
 
     // 31. If this’s request’s mode is "no-cors", then:
-    if (request_object->request().mode() == Infrastructure::Request::Mode::NoCORS) {
+    if (request_object->request()->mode() == Infrastructure::Request::Mode::NoCORS) {
         // 1. If this’s request’s method is not a CORS-safelisted method, then throw a TypeError.
-        if (!Infrastructure::is_cors_safelisted_method(request_object->request().method()))
+        if (!Infrastructure::is_cors_safelisted_method(request_object->request()->method()))
             return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must be one of GET, HEAD, or POST"sv };
 
         // 2. Set this’s headers’s guard to "request-no-cors".
@@ -438,11 +429,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
 
     // 33. Let inputBody be input’s request’s body if input is a Request object; otherwise null.
     auto const& input_body = input.has<JS::Handle<Request>>()
-        ? input.get<JS::Handle<Request>>()->request().body().get<Infrastructure::Body>()
+        ? input.get<JS::Handle<Request>>()->request()->body().get<Infrastructure::Body>()
         : Optional<Infrastructure::Body> {};
 
     // 34. If either init["body"] exists and is non-null or inputBody is non-null, and request’s method is `GET` or `HEAD`, then throw a TypeError.
-    if (((init.body.has_value() && (*init.body).has_value()) || input_body.has_value()) && StringView { request.method() }.is_one_of("GET"sv, "HEAD"sv))
+    if (((init.body.has_value() && (*init.body).has_value()) || input_body.has_value()) && StringView { request->method() }.is_one_of("GET"sv, "HEAD"sv))
         return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must not be GET or HEAD when body is provided"sv };
 
     // 35. Let initBody be null.
@@ -451,7 +442,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
     // 36. If init["body"] exists and is non-null, then:
     if (init.body.has_value() && (*init.body).has_value()) {
         // 1. Let bodyWithType be the result of extracting init["body"], with keepalive set to request’s keepalive.
-        auto body_with_type = TRY(extract_body(realm, (*init.body).value(), request.keepalive()));
+        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);
@@ -474,11 +465,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
             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.
-        if (request_object->request().mode() != Infrastructure::Request::Mode::SameOrigin && request_object->request().mode() != Infrastructure::Request::Mode::CORS)
+        if (request_object->request()->mode() != Infrastructure::Request::Mode::SameOrigin && request_object->request()->mode() != Infrastructure::Request::Mode::CORS)
             return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request mode must be 'same-origin' or 'cors'"sv };
 
         // 3. Set this’s request’s use-CORS-preflight flag.
-        request_object->request().set_use_cors_preflight(true);
+        request_object->request()->set_use_cors_preflight(true);
     }
 
     // 39. Let finalBody be inputOrInitBody.
@@ -495,7 +486,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
 
     // 41. Set this’s request’s body to finalBody.
     if (final_body.has_value())
-        request_object->request().set_body(*final_body);
+        request_object->request()->set_body(*final_body);
 
     return JS::NonnullGCPtr { *request_object };
 }

+ 5 - 5
Userland/Libraries/LibWeb/Fetch/Request.h

@@ -12,6 +12,7 @@
 #include <LibWeb/Fetch/Body.h>
 #include <LibWeb/Fetch/BodyInit.h>
 #include <LibWeb/Fetch/Headers.h>
+#include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
 #include <LibWeb/Forward.h>
 
 namespace Web::Fetch {
@@ -63,7 +64,7 @@ class Request final
     WEB_PLATFORM_OBJECT(Request, Bindings::PlatformObject);
 
 public:
-    static JS::NonnullGCPtr<Request> create(NonnullOwnPtr<Infrastructure::Request>, Headers::Guard, JS::Realm&);
+    static JS::NonnullGCPtr<Request> create(NonnullRefPtr<Infrastructure::Request>, Headers::Guard, JS::Realm&);
     static WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> construct_impl(JS::Realm&, RequestInfo const& input, RequestInit const& init = {});
 
     virtual ~Request() override;
@@ -73,8 +74,7 @@ public:
     virtual Optional<Infrastructure::Body&> body_impl() override;
     virtual Optional<Infrastructure::Body const&> body_impl() const override;
 
-    [[nodiscard]] Infrastructure::Request& request() { return *m_request; }
-    [[nodiscard]] Infrastructure::Request const& request() const { return *m_request; }
+    [[nodiscard]] NonnullRefPtr<Infrastructure::Request> request() const { return m_request; }
 
     // JS API functions
     [[nodiscard]] String method() const;
@@ -95,13 +95,13 @@ public:
     [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> clone() const;
 
 private:
-    Request(JS::Realm&, NonnullOwnPtr<Infrastructure::Request>);
+    Request(JS::Realm&, NonnullRefPtr<Infrastructure::Request>);
 
     virtual void visit_edges(Cell::Visitor&) override;
 
     // https://fetch.spec.whatwg.org/#concept-request-request
     // A Request object has an associated request (a request).
-    NonnullOwnPtr<Infrastructure::Request> m_request;
+    NonnullRefPtr<Infrastructure::Request> m_request;
 
     // https://fetch.spec.whatwg.org/#request-headers
     // A Request object also has an associated headers (null or a Headers object), initially null.

+ 8 - 8
Userland/Libraries/LibWeb/Fetch/Response.cpp

@@ -17,7 +17,7 @@
 
 namespace Web::Fetch {
 
-Response::Response(JS::Realm& realm, NonnullOwnPtr<Infrastructure::Response> response)
+Response::Response(JS::Realm& realm, NonnullRefPtr<Infrastructure::Response> response)
     : PlatformObject(realm)
     , m_response(move(response))
 {
@@ -64,7 +64,7 @@ Optional<Infrastructure::Body&> Response::body_impl()
 }
 
 // https://fetch.spec.whatwg.org/#response-create
-JS::NonnullGCPtr<Response> Response::create(NonnullOwnPtr<Infrastructure::Response> response, Headers::Guard guard, JS::Realm& realm)
+JS::NonnullGCPtr<Response> Response::create(NonnullRefPtr<Infrastructure::Response> response, Headers::Guard guard, JS::Realm& realm)
 {
     // Copy a NonnullRefPtr to the response's header list before response is being move()'d.
     auto response_reader_list = response->header_list();
@@ -127,7 +127,7 @@ WebIDL::ExceptionOr<void> Response::initialize_response(ResponseInit const& init
 WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::construct_impl(JS::Realm& realm, Optional<BodyInit> const& body, ResponseInit const& init)
 {
     // Referred to as 'this' in the spec.
-    auto response_object = JS::NonnullGCPtr { *realm.heap().allocate<Response>(realm, realm, make<Infrastructure::Response>()) };
+    auto response_object = JS::NonnullGCPtr { *realm.heap().allocate<Response>(realm, realm, Infrastructure::Response::create()) };
 
     // 1. Set this’s response to a new response.
     // NOTE: This is done at the beginning as the 'this' value Response object
@@ -135,7 +135,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::construct_impl(JS::Rea
 
     // 2. Set this’s headers to a new Headers object with this’s relevant Realm, whose header list is this’s response’s header list and guard is "response".
     response_object->m_headers = realm.heap().allocate<Headers>(realm, realm);
-    response_object->m_headers->set_header_list(response_object->response().header_list());
+    response_object->m_headers->set_header_list(response_object->response()->header_list());
     response_object->m_headers->set_guard(Headers::Guard::Response);
 
     // 3. Let bodyWithType be null.
@@ -180,10 +180,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::redirect(String const&
 
     // 4. Let responseObject be the result of creating a Response object, given a new response, "immutable", and this’s relevant Realm.
     // FIXME: How can we reliably get 'this', i.e. the object the function was called on, in IDL-defined functions?
-    auto response_object = Response::create(make<Infrastructure::Response>(), Headers::Guard::Immutable, realm);
+    auto response_object = Response::create(Infrastructure::Response::create(), Headers::Guard::Immutable, realm);
 
     // 5. Set responseObject’s response’s status to status.
-    response_object->response().set_status(status);
+    response_object->response()->set_status(status);
 
     // 6. Let value be parsedURL, serialized and isomorphic encoded.
     auto value = parsed_url.serialize();
@@ -193,7 +193,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::redirect(String const&
         .name = TRY_OR_RETURN_OOM(realm, ByteBuffer::copy("Location"sv.bytes())),
         .value = TRY_OR_RETURN_OOM(realm, ByteBuffer::copy(value.bytes())),
     };
-    TRY_OR_RETURN_OOM(realm, response_object->response().header_list()->append(move(header)));
+    TRY_OR_RETURN_OOM(realm, response_object->response()->header_list()->append(move(header)));
 
     // 8. Return responseObject.
     return response_object;
@@ -213,7 +213,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::json(JS::Value data, R
 
     // 3. Let responseObject be the result of creating a Response object, given a new response, "response", and this’s relevant Realm.
     // FIXME: How can we reliably get 'this', i.e. the object the function was called on, in IDL-defined functions?
-    auto response_object = Response::create(make<Infrastructure::Response>(), Headers::Guard::Response, realm);
+    auto response_object = Response::create(Infrastructure::Response::create(), Headers::Guard::Response, realm);
 
     // 4. Perform initialize a response given responseObject, init, and (body, "application/json").
     auto body_with_type = Infrastructure::BodyWithType {

+ 5 - 5
Userland/Libraries/LibWeb/Fetch/Response.h

@@ -12,6 +12,7 @@
 #include <LibWeb/Fetch/Body.h>
 #include <LibWeb/Fetch/BodyInit.h>
 #include <LibWeb/Fetch/Headers.h>
+#include <LibWeb/Fetch/Infrastructure/HTTP/Responses.h>
 #include <LibWeb/Forward.h>
 
 namespace Web::Fetch {
@@ -30,7 +31,7 @@ class Response final
     WEB_PLATFORM_OBJECT(Response, Bindings::PlatformObject);
 
 public:
-    static JS::NonnullGCPtr<Response> create(NonnullOwnPtr<Infrastructure::Response>, Headers::Guard, JS::Realm&);
+    static JS::NonnullGCPtr<Response> create(NonnullRefPtr<Infrastructure::Response>, Headers::Guard, JS::Realm&);
     static WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> construct_impl(JS::Realm&, Optional<BodyInit> const& body = {}, ResponseInit const& init = {});
 
     virtual ~Response() override;
@@ -40,8 +41,7 @@ public:
     virtual Optional<Infrastructure::Body&> body_impl() override;
     virtual Optional<Infrastructure::Body const&> body_impl() const override;
 
-    [[nodiscard]] Infrastructure::Response& response() { return *m_response; }
-    [[nodiscard]] Infrastructure::Response const& response() const { return *m_response; }
+    [[nodiscard]] NonnullRefPtr<Infrastructure::Response> response() const { return m_response; }
 
     // JS API functions
     [[nodiscard]] static JS::NonnullGCPtr<Response> error();
@@ -60,7 +60,7 @@ public:
     using BodyMixin::json;
 
 private:
-    Response(JS::Realm&, NonnullOwnPtr<Infrastructure::Response>);
+    Response(JS::Realm&, NonnullRefPtr<Infrastructure::Response>);
 
     virtual void visit_edges(Cell::Visitor&) override;
 
@@ -68,7 +68,7 @@ private:
 
     // https://fetch.spec.whatwg.org/#concept-response-response
     // A Response object has an associated response (a response).
-    NonnullOwnPtr<Infrastructure::Response> m_response;
+    NonnullRefPtr<Infrastructure::Response> m_response;
 
     // https://fetch.spec.whatwg.org/#response-headers
     // A Response object also has an associated headers (null or a Headers object), initially null.

+ 13 - 13
Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp

@@ -864,21 +864,21 @@ void BrowsingContext::remove()
 
 // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
 WebIDL::ExceptionOr<void> BrowsingContext::navigate(
-    Fetch::Infrastructure::Request resource,
+    NonnullRefPtr<Fetch::Infrastructure::Request> resource,
     BrowsingContext& source_browsing_context,
     bool exceptions_enabled,
     HistoryHandlingBehavior history_handling,
     Optional<PolicyContainer> history_policy_container,
     String navigation_type,
     Optional<String> navigation_id,
-    Function<void(NonnullOwnPtr<Fetch::Infrastructure::Response>)> process_response_end_of_body)
+    Function<void(NonnullRefPtr<Fetch::Infrastructure::Response>)> process_response_end_of_body)
 {
     // 1. If resource is a URL, then set resource to a new request whose URL is resource.
     // NOTE: This function only accepts resources that are already a request, so this is irrelevant.
 
     // 2. If resource is a request and historyHandling is "reload", then set resource's reload-navigation flag.
     if (history_handling == HistoryHandlingBehavior::Reload)
-        resource.set_reload_navigation(true);
+        resource->set_reload_navigation(true);
 
     // 3. If the source browsing context is not allowed to navigate browsingContext, then:
     if (!source_browsing_context.is_allowed_to_navigate(*this)) {
@@ -918,8 +918,8 @@ WebIDL::ExceptionOr<void> BrowsingContext::navigate(
     //    - resource is a request whose URL's scheme is "javascript"
     if (history_handling == HistoryHandlingBehavior::Default
         && (still_on_its_initial_about_blank_document()
-            || resource.url().equals(active_document()->url())
-            || resource.url().scheme() == "javascript"sv)) {
+            || resource->url().equals(active_document()->url())
+            || resource->url().scheme() == "javascript"sv)) {
         // then set historyHandling to "replace".
         history_handling = HistoryHandlingBehavior::Replace;
     }
@@ -928,10 +928,10 @@ WebIDL::ExceptionOr<void> BrowsingContext::navigate(
     //    resource's URL equals browsingContext's active document's URL with exclude fragments set to true,
     //    and resource's URL's fragment is non-null, then:
     if (history_handling != HistoryHandlingBehavior::Reload
-        && resource.url().equals(active_document()->url(), AK::URL::ExcludeFragment::Yes)
-        && !resource.url().fragment().is_null()) {
+        && resource->url().equals(active_document()->url(), AK::URL::ExcludeFragment::Yes)
+        && !resource->url().fragment().is_null()) {
         // 1. Navigate to a fragment given browsingContext, resource's URL, historyHandling, and navigationId.
-        navigate_to_a_fragment(resource.url(), history_handling, *navigation_id);
+        navigate_to_a_fragment(resource->url(), history_handling, *navigation_id);
 
         // 2. Return.
         return {};
@@ -982,7 +982,7 @@ WebIDL::ExceptionOr<void> BrowsingContext::navigate(
     (void)process_response_end_of_body;
 
     // AD-HOC:
-    loader().load(resource.url(), FrameLoader::Type::IFrame);
+    loader().load(resource->url(), FrameLoader::Type::IFrame);
     return {};
 }
 
@@ -1039,18 +1039,18 @@ WebIDL::ExceptionOr<void> BrowsingContext::traverse_the_history(size_t entry_ind
         VERIFY(history_handling == HistoryHandlingBehavior::Default);
 
         // 2. Let request be a new request whose URL is entry's URL.
-        auto request = Fetch::Infrastructure::Request();
-        request.set_url(entry->url);
+        auto request = Fetch::Infrastructure::Request::create();
+        request->set_url(entry->url);
 
         // 3. If explicitHistoryNavigation is true, then set request's history-navigation flag.
         if (explicit_history_navigation)
-            request.set_history_navigation(true);
+            request->set_history_navigation(true);
 
         // 4. Navigate the browsing context to request with historyHandling set to "entry update"
         //    and with historyPolicyContainer set to entry's policy container.
         //    The navigation must be done using the same source browsing context as was used the first time entry was created.
         VERIFY(entry->original_source_browsing_context);
-        TRY(navigate(request, *entry->original_source_browsing_context, false, HistoryHandlingBehavior::EntryUpdate, entry->policy_container));
+        TRY(navigate(move(request), *entry->original_source_browsing_context, false, HistoryHandlingBehavior::EntryUpdate, entry->policy_container));
 
         // 5. Return.
         return {};

+ 2 - 2
Userland/Libraries/LibWeb/HTML/BrowsingContext.h

@@ -141,14 +141,14 @@ public:
 
     // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
     WebIDL::ExceptionOr<void> navigate(
-        Fetch::Infrastructure::Request resource,
+        NonnullRefPtr<Fetch::Infrastructure::Request> resource,
         BrowsingContext& source_browsing_context,
         bool exceptions_enabled = false,
         HistoryHandlingBehavior history_handling = HistoryHandlingBehavior::Default,
         Optional<PolicyContainer> history_policy_container = {},
         String navigation_type = "other",
         Optional<String> navigation_id = {},
-        Function<void(NonnullOwnPtr<Fetch::Infrastructure::Response>)> process_response_end_of_body = {});
+        Function<void(NonnullRefPtr<Fetch::Infrastructure::Response>)> process_response_end_of_body = {});
 
     // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid
     WebIDL::ExceptionOr<void> navigate_to_a_fragment(AK::URL const&, HistoryHandlingBehavior, String navigation_id);

+ 3 - 3
Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp

@@ -163,8 +163,8 @@ void BrowsingContextContainer::shared_attribute_processing_steps_for_iframe_and_
     }
 
     // 5. Let resource be a new request whose URL is url and whose referrer policy is the current state of element's referrerpolicy content attribute.
-    auto resource = Fetch::Infrastructure::Request();
-    resource.set_url(url);
+    auto resource = Fetch::Infrastructure::Request::create();
+    resource->set_url(url);
     // FIXME: Set the referrer policy.
 
     // AD-HOC:
@@ -191,7 +191,7 @@ void BrowsingContextContainer::shared_attribute_processing_steps_for_iframe_and_
 }
 
 // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame
-void BrowsingContextContainer::navigate_an_iframe_or_frame(Fetch::Infrastructure::Request resource)
+void BrowsingContextContainer::navigate_an_iframe_or_frame(NonnullRefPtr<Fetch::Infrastructure::Request> resource)
 {
     // 1. Let historyHandling be "default".
     auto history_handling = HistoryHandlingBehavior::Default;

+ 1 - 1
Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.h

@@ -35,7 +35,7 @@ protected:
     void shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion);
 
     // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame
-    void navigate_an_iframe_or_frame(Fetch::Infrastructure::Request);
+    void navigate_an_iframe_or_frame(NonnullRefPtr<Fetch::Infrastructure::Request>);
 
     void create_new_nested_browsing_context();
 

+ 2 - 2
Userland/Libraries/LibWeb/HTML/NavigationParams.h

@@ -23,10 +23,10 @@ struct NavigationParams {
     String id;
 
     // null or a request that started the navigation
-    OwnPtr<Fetch::Infrastructure::Request> request;
+    RefPtr<Fetch::Infrastructure::Request> request;
 
     // a response that ultimately was navigated to (potentially a network error)
-    NonnullOwnPtr<Fetch::Infrastructure::Response> response;
+    NonnullRefPtr<Fetch::Infrastructure::Response> response;
 
     // an origin to use for the new Document
     Origin origin;

+ 2 - 2
Userland/Libraries/LibWeb/Loader/FrameLoader.cpp

@@ -299,7 +299,7 @@ bool FrameLoader::load(const AK::URL& url, Type type)
 
 void FrameLoader::load_html(StringView html, const AK::URL& url)
 {
-    auto response = make<Fetch::Infrastructure::Response>();
+    auto response = Fetch::Infrastructure::Response::create();
     response->url_list().append(url);
     HTML::NavigationParams navigation_params {
         .id = {},
@@ -419,7 +419,7 @@ void FrameLoader::resource_did_load()
     // FIXME: Pass incumbentNavigationOrigin
     auto response_origin = HTML::determine_the_origin(browsing_context(), url, final_sandboxing_flag_set, {});
 
-    auto response = make<Fetch::Infrastructure::Response>();
+    auto response = Fetch::Infrastructure::Response::create();
     response->url_list().append(url);
     HTML::NavigationParams navigation_params {
         .id = {},