1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 20:17:42 +00:00

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!
This commit is contained in:
Linus Groh 2022-10-04 23:45:47 +01:00
parent 886ca9c7b6
commit 1c12f5c31d
14 changed files with 228 additions and 175 deletions

View file

@ -14,6 +14,11 @@ Request::Request()
{ {
} }
NonnullRefPtr<Request> Request::create()
{
return adopt_ref(*new Request());
}
// https://fetch.spec.whatwg.org/#concept-request-url // https://fetch.spec.whatwg.org/#concept-request-url
AK::URL const& Request::url() const 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 // 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: // To clone a request request, run these steps:
// 1. Let newRequest be a copy of request, except for its body. // 1. Let newRequest be a copy of request, except for its body.
BodyType tmp_body; auto new_request = Infrastructure::Request::create();
swap(tmp_body, const_cast<BodyType&>(m_body)); new_request->set_method(m_method);
auto new_request = make<Infrastructure::Request>(*this); new_request->set_local_urls_only(m_local_urls_only);
swap(tmp_body, const_cast<BodyType&>(m_body)); 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 requests body is non-null, set newRequests body to the result of cloning requests body. // 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>()) if (auto const* body = m_body.get_pointer<Body>())

View file

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

View file

@ -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 // 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 // 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. // 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(); auto response = network_error();
response->set_aborted(true); response->set_aborted(true);
return response; 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_status(0);
response->set_type(Type::Error); response->set_type(Type::Error);
VERIFY(!response->body().has_value()); 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 // 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: // 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 responses internal response. // FIXME: 1. If response is a filtered response, then return a new identical filtered response whose internal response is a clone of responses internal response.
// 2. Let newResponse be a copy of response, except for its body. // 2. Let newResponse be a copy of response, except for its body.
Optional<Body> tmp_body; auto new_response = Infrastructure::Response::create();
swap(tmp_body, const_cast<Optional<Body>&>(m_body)); new_response->set_type(m_type);
auto new_response = make<Infrastructure::Response>(*this); new_response->set_aborted(m_aborted);
swap(tmp_body, const_cast<Optional<Body>&>(m_body)); 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 responses body is non-null, then set newResponses body to the result of cloning responses body. // 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.has_value())
@ -103,8 +119,8 @@ WebIDL::ExceptionOr<NonnullOwnPtr<Response>> Response::clone() const
return new_response; return new_response;
} }
FilteredResponse::FilteredResponse(Response& internal_response) FilteredResponse::FilteredResponse(NonnullRefPtr<Response> internal_response)
: m_internal_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 // A basic filtered response is a filtered response whose type is "basic" and header list excludes
// any headers in internal responses header list whose name is a forbidden response-header name. // any headers in internal responses header list whose name is a forbidden response-header name.
auto header_list = make_ref_counted<HeaderList>(); 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)) if (!is_forbidden_response_header_name(header.name))
TRY(header_list->append(header)); 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) BasicFilteredResponse::BasicFilteredResponse(NonnullRefPtr<Response> internal_response, NonnullRefPtr<HeaderList> header_list)
: FilteredResponse(internal_response) : FilteredResponse(move(internal_response))
, m_header_list(move(header_list)) , 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 // A CORS filtered response is a filtered response whose type is "cors" and header list excludes
// any headers in internal responses header list whose name is not a CORS-safelisted response-header // any headers in internal responses header list whose name is not a CORS-safelisted response-header
// name, given internal responses CORS-exposed header-name list. // name, given internal responses CORS-exposed header-name list.
Vector<ReadonlyBytes> 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()); cors_exposed_header_name_list.append(header_name.span());
auto header_list = make_ref_counted<HeaderList>(); 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)) if (is_cors_safelisted_response_header_name(header.name, cors_exposed_header_name_list))
TRY(header_list->append(header)); 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) CORSFilteredResponse::CORSFilteredResponse(NonnullRefPtr<Response> internal_response, NonnullRefPtr<HeaderList> header_list)
: FilteredResponse(internal_response) : FilteredResponse(move(internal_response))
, m_header_list(move(header_list)) , 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", // 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. // 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) OpaqueFilteredResponse::OpaqueFilteredResponse(NonnullRefPtr<Response> internal_response)
: FilteredResponse(internal_response) : FilteredResponse(move(internal_response))
, m_header_list(make_ref_counted<HeaderList>()) , 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) OpaqueRedirectFilteredResponse::OpaqueRedirectFilteredResponse(NonnullRefPtr<Response> internal_response)
: FilteredResponse(internal_response) : FilteredResponse(move(internal_response))
, m_header_list(make_ref_counted<HeaderList>()) , m_header_list(make_ref_counted<HeaderList>())
{ {
} }

View file

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

View file

@ -4,7 +4,6 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/ScopeGuard.h>
#include <AK/URLParser.h> #include <AK/URLParser.h>
#include <LibWeb/Bindings/Intrinsics.h> #include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/DOM/AbortSignal.h> #include <LibWeb/DOM/AbortSignal.h>
@ -20,7 +19,7 @@
namespace Web::Fetch { namespace Web::Fetch {
Request::Request(JS::Realm& realm, NonnullOwnPtr<Infrastructure::Request> request) Request::Request(JS::Realm& realm, NonnullRefPtr<Infrastructure::Request> request)
: PlatformObject(realm) : PlatformObject(realm)
, m_request(move(request)) , m_request(move(request))
{ {
@ -72,7 +71,7 @@ Optional<Infrastructure::Body&> Request::body_impl()
} }
// https://fetch.spec.whatwg.org/#request-create // 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. // Copy a NonnullRefPtr to the request's header list before request is being move()'d.
auto request_reader_list = request->header_list(); 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) WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm& realm, RequestInfo const& input, RequestInit const& init)
{ {
// Referred to as 'this' in the spec. // 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. // 1. Let request be null.
Infrastructure::Request const* input_request = nullptr; RefPtr<Infrastructure::Request> input_request;
// 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;
} };
// 2. Let fallbackMode be null. // 2. Let fallbackMode be null.
Optional<Infrastructure::Request::Mode> fallback_mode; 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 }; return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Input URL must not include credentials"sv };
// 4. Set request to a new request whose URL is parsedURL. // 4. Set request to a new request whose URL is parsedURL.
auto* new_request = new Infrastructure::Request(); input_request = Infrastructure::Request::create();
new_request->set_url(move(parsed_url)); input_request->set_url(move(parsed_url));
input_request = new_request;
// 5. Set fallbackMode to "cors". // 5. Set fallbackMode to "cors".
fallback_mode = Infrastructure::Request::Mode::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>>()); VERIFY(input.has<JS::Handle<Request>>());
// 2. Set request to inputs request. // 2. Set request to inputs request.
input_request = &input.get<JS::Handle<Request>>()->request(); input_request = input.get<JS::Handle<Request>>()->request();
delete_input_request.disarm();
// 3. Set signal to inputs signal. // 3. Set signal to inputs signal.
input_signal = input.get<JS::Handle<Request>>()->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: // 12. Set request to a new request with the following properties:
// NOTE: This is done at the beginning as the 'this' value Request object // NOTE: This is done at the beginning as the 'this' value Request object
// cannot exist with a null Infrastructure::Request. // cannot exist with a null Infrastructure::Request.
auto& request = request_object->request(); auto request = request_object->request();
// URL // URL
// requests URL. // requests URL.
request.set_url(input_request->url()); request->set_url(input_request->url());
// method // method
// requests method. // requests 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 // header list
// A copy of requests header list. // A copy of requests header list.
auto header_list_copy = make_ref_counted<Infrastructure::HeaderList>(); 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)); 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 // unsafe-request flag
// Set. // Set.
request.set_unsafe_request(true); request->set_unsafe_request(true);
// client // client
// Thiss relevant settings object. // Thiss relevant settings object.
request.set_client(&HTML::relevant_settings_object(*request_object)); request->set_client(&HTML::relevant_settings_object(*request_object));
// window // window
// window. // window.
request.set_window(window); request->set_window(window);
// priority // priority
// requests priority. // requests priority.
request.set_priority(input_request->priority()); request->set_priority(input_request->priority());
// origin // origin
// requests 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. // requests 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 // referrer
// requests referrer. // requests referrer.
request.set_referrer(input_request->referrer()); request->set_referrer(input_request->referrer());
// referrer policy // referrer policy
// requests referrer policy. // requests referrer policy.
request.set_referrer_policy(input_request->referrer_policy()); request->set_referrer_policy(input_request->referrer_policy());
// mode // mode
// requests mode. // requests mode.
request.set_mode(input_request->mode()); request->set_mode(input_request->mode());
// credentials mode // credentials mode
// requests credentials mode. // requests credentials mode.
request.set_credentials_mode(input_request->credentials_mode()); request->set_credentials_mode(input_request->credentials_mode());
// cache mode // cache mode
// requests cache mode. // requests cache mode.
request.set_cache_mode(input_request->cache_mode()); request->set_cache_mode(input_request->cache_mode());
// redirect mode // redirect mode
// requests redirect mode. // requests redirect mode.
request.set_redirect_mode(input_request->redirect_mode()); request->set_redirect_mode(input_request->redirect_mode());
// integrity metadata // integrity metadata
// requests integrity metadata. // requests integrity metadata.
request.set_integrity_metadata(input_request->integrity_metadata()); request->set_integrity_metadata(input_request->integrity_metadata());
// keepalive // keepalive
// requests keepalive. // requests keepalive.
request.set_keepalive(input_request->keepalive()); request->set_keepalive(input_request->keepalive());
// reload-navigation flag // reload-navigation flag
// requests reload-navigation flag. // requests reload-navigation flag.
request.set_reload_navigation(input_request->reload_navigation()); request->set_reload_navigation(input_request->reload_navigation());
// history-navigation flag // history-navigation flag
// requests history-navigation flag. // requests history-navigation flag.
request.set_history_navigation(input_request->history_navigation()); request->set_history_navigation(input_request->history_navigation());
// URL list // URL list
// A clone of requests URL list. // A clone of requests URL list.
request.set_url_list(input_request->url_list()); request->set_url_list(input_request->url_list());
// initiator type // initiator type
// "fetch". // "fetch".
request.set_initiator_type(Infrastructure::Request::InitiatorType::Fetch); request->set_initiator_type(Infrastructure::Request::InitiatorType::Fetch);
// 13. If init is not empty, then: // 13. If init is not empty, then:
if (!init.is_empty()) { if (!init.is_empty()) {
// 1. If requests mode is "navigate", then set it to "same-origin". // 1. If requests mode is "navigate", then set it to "same-origin".
if (request.mode() == Infrastructure::Request::Mode::Navigate) if (request->mode() == Infrastructure::Request::Mode::Navigate)
request.set_mode(Infrastructure::Request::Mode::SameOrigin); request->set_mode(Infrastructure::Request::Mode::SameOrigin);
// 2. Unset requests reload-navigation flag. // 2. Unset requests reload-navigation flag.
request.set_reload_navigation(false); request->set_reload_navigation(false);
// 3. Unset requests history-navigation flag. // 3. Unset requests history-navigation flag.
request.set_history_navigation(false); request->set_history_navigation(false);
// 4. Set requests origin to "client". // 4. Set requests origin to "client".
request.set_origin(Infrastructure::Request::Origin::Client); request->set_origin(Infrastructure::Request::Origin::Client);
// 5. Set requests referrer to "client". // 5. Set requests referrer to "client".
request.set_referrer(Infrastructure::Request::Referrer::Client); request->set_referrer(Infrastructure::Request::Referrer::Client);
// 6. Set requests referrer policy to the empty string. // 6. Set requests referrer policy to the empty string.
request.set_referrer_policy({}); request->set_referrer_policy({});
// 7. Set requests URL to requests current URL. // 7. Set requests URL to requests current URL.
request.set_url(request.current_url()); request->set_url(request->current_url());
// 8. Set requests URL list to « requests URL ». // 8. Set requests URL list to « requests URL ».
// NOTE: This is done implicitly by assigning the initial URL above. // 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 requests referrer to "no-referrer". // 2. If referrer is the empty string, then set requests referrer to "no-referrer".
if (referrer.is_empty()) { if (referrer.is_empty()) {
request.set_referrer(Infrastructure::Request::Referrer::NoReferrer); request->set_referrer(Infrastructure::Request::Referrer::NoReferrer);
} }
// 3. Otherwise: // 3. Otherwise:
else { else {
@ -312,18 +303,18 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
// then set requests referrer to "client". // then set requests referrer to "client".
// FIXME: Actually use the given origin once we have https://url.spec.whatwg.org/#concept-url-origin. // 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)) { 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 requests referrer to parsedReferrer. // 4. Otherwise, set requests referrer to parsedReferrer.
else { else {
request.set_referrer(move(parsed_referrer)); request->set_referrer(move(parsed_referrer));
} }
} }
} }
// 15. If init["referrerPolicy"] exists, then set requests referrer policy to it. // 15. If init["referrerPolicy"] exists, then set requests referrer policy to it.
if (init.referrer_policy.has_value()) 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. // 16. Let mode be init["mode"] if it exists, and fallbackMode otherwise.
auto mode = init.mode.has_value() 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 requests mode to mode. // 18. If mode is non-null, set requests mode to mode.
if (mode.has_value()) if (mode.has_value())
request.set_mode(*mode); request->set_mode(*mode);
// 19. If init["credentials"] exists, then set requests credentials mode to it. // 19. If init["credentials"] exists, then set requests credentials mode to it.
if (init.credentials.has_value()) 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 requests cache mode to it. // 20. If init["cache"] exists, then set requests cache mode to it.
if (init.cache.has_value()) 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 requests cache mode is "only-if-cached" and requests mode is not "same-origin", then throw a TypeError. // 21. If requests cache mode is "only-if-cached" and requests 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 }; 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 requests redirect mode to it. // 22. If init["redirect"] exists, then set requests redirect mode to it.
if (init.redirect.has_value()) 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 requests integrity metadata to it. // 23. If init["integrity"] exists, then set requests integrity metadata to it.
if (init.integrity.has_value()) if (init.integrity.has_value())
request.set_integrity_metadata(*init.integrity); request->set_integrity_metadata(*init.integrity);
// 24. If init["keepalive"] exists, then set requests keepalive to it. // 24. If init["keepalive"] exists, then set requests keepalive to it.
if (init.keepalive.has_value()) if (init.keepalive.has_value())
request.set_keepalive(*init.keepalive); request->set_keepalive(*init.keepalive);
// 25. If init["method"] exists, then: // 25. If init["method"] exists, then:
if (init.method.has_value()) { 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())); method = TRY_OR_RETURN_OOM(realm, Infrastructure::normalize_method(method.bytes()));
// 4. Set requests method to method. // 4. Set requests 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. // 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 thiss headers to a new Headers object with thiss relevant Realm, whose header list is requests header list and guard is "request". // 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 = 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); request_object->m_headers->set_guard(Headers::Guard::Request);
// 31. If thiss requests mode is "no-cors", then: // 31. If thiss requests 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 thiss requests method is not a CORS-safelisted method, then throw a TypeError. // 1. If thiss requests 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 }; return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must be one of GET, HEAD, or POST"sv };
// 2. Set thiss headerss guard to "request-no-cors". // 2. Set thiss headerss guard to "request-no-cors".
@ -438,11 +429,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
// 33. Let inputBody be inputs requests body if input is a Request object; otherwise null. // 33. Let inputBody be inputs requests body if input is a Request object; otherwise null.
auto const& input_body = input.has<JS::Handle<Request>>() 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> {}; : Optional<Infrastructure::Body> {};
// 34. If either init["body"] exists and is non-null or inputBody is non-null, and requests method is `GET` or `HEAD`, then throw a TypeError. // 34. If either init["body"] exists and is non-null or inputBody is non-null, and requests 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 }; return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must not be GET or HEAD when body is provided"sv };
// 35. Let initBody be null. // 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: // 36. If init["body"] exists and is non-null, then:
if (init.body.has_value() && (*init.body).has_value()) { if (init.body.has_value() && (*init.body).has_value()) {
// 1. Let bodyWithType be the result of extracting init["body"], with keepalive set to requests keepalive. // 1. Let bodyWithType be the result of extracting init["body"], with keepalive set to requests 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 bodyWithTypes body. // 2. Set initBody to bodyWithTypes body.
init_body = move(body_with_type.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 }; return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Body without source requires 'duplex' value to be set"sv };
// 2. If thiss requests mode is neither "same-origin" nor "cors", then throw a TypeError. // 2. If thiss requests 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 }; return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request mode must be 'same-origin' or 'cors'"sv };
// 3. Set thiss requests use-CORS-preflight flag. // 3. Set thiss requests 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. // 39. Let finalBody be inputOrInitBody.
@ -495,7 +486,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
// 41. Set thiss requests body to finalBody. // 41. Set thiss requests body to finalBody.
if (final_body.has_value()) if (final_body.has_value())
request_object->request().set_body(*final_body); request_object->request()->set_body(*final_body);
return JS::NonnullGCPtr { *request_object }; return JS::NonnullGCPtr { *request_object };
} }

View file

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

View file

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

View file

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

View file

@ -864,21 +864,21 @@ void BrowsingContext::remove()
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
WebIDL::ExceptionOr<void> BrowsingContext::navigate( WebIDL::ExceptionOr<void> BrowsingContext::navigate(
Fetch::Infrastructure::Request resource, NonnullRefPtr<Fetch::Infrastructure::Request> resource,
BrowsingContext& source_browsing_context, BrowsingContext& source_browsing_context,
bool exceptions_enabled, bool exceptions_enabled,
HistoryHandlingBehavior history_handling, HistoryHandlingBehavior history_handling,
Optional<PolicyContainer> history_policy_container, Optional<PolicyContainer> history_policy_container,
String navigation_type, String navigation_type,
Optional<String> navigation_id, 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. // 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. // 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. // 2. If resource is a request and historyHandling is "reload", then set resource's reload-navigation flag.
if (history_handling == HistoryHandlingBehavior::Reload) 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: // 3. If the source browsing context is not allowed to navigate browsingContext, then:
if (!source_browsing_context.is_allowed_to_navigate(*this)) { 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" // - resource is a request whose URL's scheme is "javascript"
if (history_handling == HistoryHandlingBehavior::Default if (history_handling == HistoryHandlingBehavior::Default
&& (still_on_its_initial_about_blank_document() && (still_on_its_initial_about_blank_document()
|| resource.url().equals(active_document()->url()) || resource->url().equals(active_document()->url())
|| resource.url().scheme() == "javascript"sv)) { || resource->url().scheme() == "javascript"sv)) {
// then set historyHandling to "replace". // then set historyHandling to "replace".
history_handling = HistoryHandlingBehavior::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, // 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: // and resource's URL's fragment is non-null, then:
if (history_handling != HistoryHandlingBehavior::Reload if (history_handling != HistoryHandlingBehavior::Reload
&& resource.url().equals(active_document()->url(), AK::URL::ExcludeFragment::Yes) && resource->url().equals(active_document()->url(), AK::URL::ExcludeFragment::Yes)
&& !resource.url().fragment().is_null()) { && !resource->url().fragment().is_null()) {
// 1. Navigate to a fragment given browsingContext, resource's URL, historyHandling, and navigationId. // 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. // 2. Return.
return {}; return {};
@ -982,7 +982,7 @@ WebIDL::ExceptionOr<void> BrowsingContext::navigate(
(void)process_response_end_of_body; (void)process_response_end_of_body;
// AD-HOC: // AD-HOC:
loader().load(resource.url(), FrameLoader::Type::IFrame); loader().load(resource->url(), FrameLoader::Type::IFrame);
return {}; return {};
} }
@ -1039,18 +1039,18 @@ WebIDL::ExceptionOr<void> BrowsingContext::traverse_the_history(size_t entry_ind
VERIFY(history_handling == HistoryHandlingBehavior::Default); VERIFY(history_handling == HistoryHandlingBehavior::Default);
// 2. Let request be a new request whose URL is entry's URL. // 2. Let request be a new request whose URL is entry's URL.
auto request = Fetch::Infrastructure::Request(); auto request = Fetch::Infrastructure::Request::create();
request.set_url(entry->url); request->set_url(entry->url);
// 3. If explicitHistoryNavigation is true, then set request's history-navigation flag. // 3. If explicitHistoryNavigation is true, then set request's history-navigation flag.
if (explicit_history_navigation) 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" // 4. Navigate the browsing context to request with historyHandling set to "entry update"
// and with historyPolicyContainer set to entry's policy container. // 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. // 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); 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. // 5. Return.
return {}; return {};

View file

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

View file

@ -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. // 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(); auto resource = Fetch::Infrastructure::Request::create();
resource.set_url(url); resource->set_url(url);
// FIXME: Set the referrer policy. // FIXME: Set the referrer policy.
// AD-HOC: // 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 // 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". // 1. Let historyHandling be "default".
auto history_handling = HistoryHandlingBehavior::Default; auto history_handling = HistoryHandlingBehavior::Default;

View file

@ -35,7 +35,7 @@ protected:
void shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion); 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 // 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(); void create_new_nested_browsing_context();

View file

@ -23,10 +23,10 @@ struct NavigationParams {
String id; String id;
// null or a request that started the navigation // 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) // 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 // an origin to use for the new Document
Origin origin; Origin origin;

View file

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