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

This is the way.

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

View file

@ -13,8 +13,10 @@ namespace Web::Fetch {
// https://fetch.spec.whatwg.org/#dom-headers
WebIDL::ExceptionOr<JS::NonnullGCPtr<Headers>> Headers::construct_impl(JS::Realm& realm, Optional<HeadersInit> const& init)
{
auto& vm = realm.vm();
// The new Headers(init) constructor steps are:
auto* headers = realm.heap().allocate<Headers>(realm, realm);
auto* headers = realm.heap().allocate<Headers>(realm, realm, Infrastructure::HeaderList::create(vm));
// 1. Set thiss guard to "none".
headers->m_guard = Guard::None;
@ -26,15 +28,21 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Headers>> Headers::construct_impl(JS::Realm
return JS::NonnullGCPtr(*headers);
}
Headers::Headers(JS::Realm& realm)
Headers::Headers(JS::Realm& realm, JS::NonnullGCPtr<Infrastructure::HeaderList> header_list)
: PlatformObject(realm)
, m_header_list(make_ref_counted<Infrastructure::HeaderList>())
, m_header_list(header_list)
{
set_prototype(&Bindings::cached_web_prototype(realm, "Headers"));
}
Headers::~Headers() = default;
void Headers::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_header_list);
}
// https://fetch.spec.whatwg.org/#dom-headers-append
WebIDL::ExceptionOr<void> Headers::append(String const& name_string, String const& value_string)
{

View file

@ -10,6 +10,7 @@
#include <AK/String.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibJS/Forward.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
@ -35,9 +36,8 @@ public:
virtual ~Headers() override;
[[nodiscard]] NonnullRefPtr<Infrastructure::HeaderList>& header_list() { return m_header_list; }
[[nodiscard]] NonnullRefPtr<Infrastructure::HeaderList> const& header_list() const { return m_header_list; }
void set_header_list(NonnullRefPtr<Infrastructure::HeaderList> header_list) { m_header_list = move(header_list); }
[[nodiscard]] JS::NonnullGCPtr<Infrastructure::HeaderList> header_list() const { return m_header_list; }
void set_header_list(JS::NonnullGCPtr<Infrastructure::HeaderList> header_list) { m_header_list = header_list; }
[[nodiscard]] Guard guard() const { return m_guard; }
void set_guard(Guard guard) { m_guard = guard; }
@ -58,13 +58,15 @@ public:
private:
friend class HeadersIterator;
explicit Headers(JS::Realm&);
Headers(JS::Realm&, JS::NonnullGCPtr<Infrastructure::HeaderList>);
virtual void visit_edges(JS::Cell::Visitor&) override;
void remove_privileged_no_cors_headers();
// https://fetch.spec.whatwg.org/#concept-headers-header-list
// A Headers object has an associated header list (a header list), which is initially empty.
NonnullRefPtr<Infrastructure::HeaderList> m_header_list;
JS::NonnullGCPtr<Infrastructure::HeaderList> m_header_list;
// https://fetch.spec.whatwg.org/#concept-headers-guard
// A Headers object also has an associated guard, which is a headers guard. A headers guard is "immutable", "request", "request-no-cors", "response" or "none".

View file

@ -11,6 +11,8 @@
#include <AK/GenericLexer.h>
#include <AK/QuickSort.h>
#include <AK/ScopeGuard.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/VM.h>
#include <LibRegex/Regex.h>
#include <LibWeb/Fetch/Infrastructure/HTTP.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
@ -42,6 +44,11 @@ ErrorOr<Header> Header::from_string_pair(StringView name, StringView value)
};
}
JS::NonnullGCPtr<HeaderList> HeaderList::create(JS::VM& vm)
{
return { *vm.heap().allocate_without_realm<HeaderList>() };
}
// https://fetch.spec.whatwg.org/#header-list-contains
bool HeaderList::contains(ReadonlyBytes name) const
{

View file

@ -13,6 +13,8 @@
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/Vector.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/MimeSniff/MimeType.h>
namespace Web::Fetch::Infrastructure {
@ -29,13 +31,17 @@ struct Header {
// https://fetch.spec.whatwg.org/#concept-header-list
// A header list is a list of zero or more headers. It is initially the empty list.
class HeaderList final
: public RefCounted<HeaderList>
: public JS::Cell
, Vector<Header> {
JS_CELL(HeaderList, JS::Cell);
public:
using Vector::begin;
using Vector::clear;
using Vector::end;
[[nodiscard]] static JS::NonnullGCPtr<HeaderList> create(JS::VM&);
[[nodiscard]] bool contains(ReadonlyBytes) const;
[[nodiscard]] ErrorOr<Optional<ByteBuffer>> get(ReadonlyBytes) const;
[[nodiscard]] ErrorOr<Optional<Vector<String>>> get_decode_and_split(ReadonlyBytes) const;

View file

@ -5,18 +5,26 @@
*/
#include <AK/Array.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
namespace Web::Fetch::Infrastructure {
Request::Request()
: m_header_list(make_ref_counted<HeaderList>())
Request::Request(JS::NonnullGCPtr<HeaderList> header_list)
: m_header_list(header_list)
{
}
NonnullRefPtr<Request> Request::create()
void Request::visit_edges(JS::Cell::Visitor& visitor)
{
return adopt_ref(*new Request());
Base::visit_edges(visitor);
visitor.visit(m_header_list);
}
JS::NonnullGCPtr<Request> Request::create(JS::VM& vm)
{
return { *vm.heap().allocate_without_realm<Request>(HeaderList::create(vm)) };
}
// https://fetch.spec.whatwg.org/#concept-request-url
@ -181,12 +189,12 @@ ErrorOr<ByteBuffer> Request::byte_serialize_origin() const
}
// https://fetch.spec.whatwg.org/#concept-request-clone
WebIDL::ExceptionOr<NonnullRefPtr<Request>> Request::clone() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::clone(JS::VM& vm) const
{
// To clone a request request, run these steps:
// 1. Let newRequest be a copy of request, except for its body.
auto new_request = Infrastructure::Request::create();
auto new_request = Infrastructure::Request::create(vm);
new_request->set_method(m_method);
new_request->set_local_urls_only(m_local_urls_only);
for (auto const& header : *m_header_list)

View file

@ -10,11 +10,12 @@
#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>
#include <AK/Vector.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
#include <LibWeb/HTML/Origin.h>
@ -24,7 +25,9 @@
namespace Web::Fetch::Infrastructure {
// https://fetch.spec.whatwg.org/#concept-request
class Request final : public RefCounted<Request> {
class Request final : public JS::Cell {
JS_CELL(Request, JS::Cell);
public:
enum class CacheMode {
Default,
@ -156,7 +159,7 @@ public:
using ReservedClientType = Variant<Empty, HTML::Environment*, HTML::EnvironmentSettingsObject*>;
using WindowType = Variant<Window, HTML::EnvironmentSettingsObject*>;
static NonnullRefPtr<Request> create();
[[nodiscard]] static JS::NonnullGCPtr<Request> create(JS::VM&);
[[nodiscard]] ReadonlyBytes method() const { return m_method; }
void set_method(ByteBuffer method) { m_method = move(method); }
@ -164,9 +167,8 @@ public:
[[nodiscard]] bool local_urls_only() const { return m_local_urls_only; }
void set_local_urls_only(bool local_urls_only) { m_local_urls_only = local_urls_only; }
[[nodiscard]] NonnullRefPtr<HeaderList> const& header_list() const { return m_header_list; }
[[nodiscard]] NonnullRefPtr<HeaderList>& header_list() { return m_header_list; }
void set_header_list(NonnullRefPtr<HeaderList> header_list) { m_header_list = move(header_list); }
[[nodiscard]] JS::NonnullGCPtr<HeaderList> header_list() const { return m_header_list; }
void set_header_list(JS::NonnullGCPtr<HeaderList> header_list) { m_header_list = header_list; }
[[nodiscard]] bool unsafe_request() const { return m_unsafe_request; }
void set_unsafe_request(bool unsafe_request) { m_unsafe_request = unsafe_request; }
@ -294,14 +296,16 @@ public:
[[nodiscard]] String serialize_origin() const;
[[nodiscard]] ErrorOr<ByteBuffer> byte_serialize_origin() const;
[[nodiscard]] WebIDL::ExceptionOr<NonnullRefPtr<Request>> clone() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> clone(JS::VM&) const;
[[nodiscard]] ErrorOr<void> add_range_header(u64 first, Optional<u64> const& last);
[[nodiscard]] bool cross_origin_embedder_policy_allows_credentials() const;
private:
Request();
explicit Request(JS::NonnullGCPtr<HeaderList>);
virtual void visit_edges(JS::Cell::Visitor&) override;
// https://fetch.spec.whatwg.org/#concept-request-method
// A request has an associated method (a method). Unless stated otherwise it is `GET`.
@ -313,7 +317,7 @@ private:
// https://fetch.spec.whatwg.org/#concept-request-header-list
// A request has an associated header list (a header list). Unless stated otherwise it is empty.
NonnullRefPtr<HeaderList> m_header_list;
JS::NonnullGCPtr<HeaderList> m_header_list;
// https://fetch.spec.whatwg.org/#unsafe-request-flag
// A request has an associated unsafe-request flag. Unless stated otherwise it is unset.

View file

@ -4,36 +4,44 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/VM.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Responses.h>
namespace Web::Fetch::Infrastructure {
Response::Response()
: m_header_list(make_ref_counted<HeaderList>())
Response::Response(JS::NonnullGCPtr<HeaderList> header_list)
: m_header_list(header_list)
{
}
NonnullRefPtr<Response> Response::create()
void Response::visit_edges(JS::Cell::Visitor& visitor)
{
return adopt_ref(*new Response());
Base::visit_edges(visitor);
visitor.visit(m_header_list);
}
JS::NonnullGCPtr<Response> Response::create(JS::VM& vm)
{
return { *vm.heap().allocate_without_realm<Response>(HeaderList::create(vm)) };
}
// 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.
NonnullRefPtr<Response> Response::aborted_network_error()
JS::NonnullGCPtr<Response> Response::aborted_network_error(JS::VM& vm)
{
auto response = network_error();
auto response = network_error(vm);
response->set_aborted(true);
return response;
}
NonnullRefPtr<Response> Response::network_error()
JS::NonnullGCPtr<Response> Response::network_error(JS::VM& vm)
{
auto response = Response::create();
auto response = Response::create(vm);
response->set_status(0);
response->set_type(Type::Error);
VERIFY(!response->body().has_value());
@ -93,29 +101,28 @@ ErrorOr<Optional<AK::URL>> Response::location_url(Optional<String> const& reques
}
// https://fetch.spec.whatwg.org/#concept-response-clone
WebIDL::ExceptionOr<NonnullRefPtr<Response>> Response::clone() const
WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::clone(JS::VM& vm) const
{
// To clone a response response, run these steps:
auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm();
// 1. If response is a filtered response, then return a new identical filtered response whose internal response is a clone of responses internal response.
if (is<FilteredResponse>(*this)) {
auto internal_response = TRY(static_cast<FilteredResponse const&>(*this).internal_response()->clone());
auto internal_response = TRY(static_cast<FilteredResponse const&>(*this).internal_response()->clone(vm));
if (is<BasicFilteredResponse>(*this))
return TRY_OR_RETURN_OOM(realm, BasicFilteredResponse::create(move(internal_response)));
return TRY_OR_RETURN_OOM(realm, BasicFilteredResponse::create(vm, internal_response));
if (is<CORSFilteredResponse>(*this))
return TRY_OR_RETURN_OOM(realm, CORSFilteredResponse::create(move(internal_response)));
return TRY_OR_RETURN_OOM(realm, CORSFilteredResponse::create(vm, internal_response));
if (is<OpaqueFilteredResponse>(*this))
return OpaqueFilteredResponse::create(move(internal_response));
return OpaqueFilteredResponse::create(vm, internal_response);
if (is<OpaqueRedirectFilteredResponse>(*this))
return OpaqueRedirectFilteredResponse::create(move(internal_response));
return OpaqueRedirectFilteredResponse::create(vm, internal_response);
VERIFY_NOT_REACHED();
}
// 2. Let newResponse be a copy of response, except for its body.
auto new_response = Infrastructure::Response::create();
auto new_response = Infrastructure::Response::create(vm);
new_response->set_type(m_type);
new_response->set_aborted(m_aborted);
new_response->set_url_list(m_url_list);
@ -139,8 +146,9 @@ WebIDL::ExceptionOr<NonnullRefPtr<Response>> Response::clone() const
return new_response;
}
FilteredResponse::FilteredResponse(NonnullRefPtr<Response> internal_response)
: m_internal_response(move(internal_response))
FilteredResponse::FilteredResponse(JS::NonnullGCPtr<Response> internal_response, JS::NonnullGCPtr<HeaderList> header_list)
: Response(header_list)
, m_internal_response(internal_response)
{
}
@ -148,26 +156,38 @@ FilteredResponse::~FilteredResponse()
{
}
ErrorOr<NonnullRefPtr<BasicFilteredResponse>> BasicFilteredResponse::create(NonnullRefPtr<Response> internal_response)
void FilteredResponse::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_internal_response);
}
ErrorOr<JS::NonnullGCPtr<BasicFilteredResponse>> BasicFilteredResponse::create(JS::VM& vm, JS::NonnullGCPtr<Response> internal_response)
{
// 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.
auto header_list = make_ref_counted<HeaderList>();
auto header_list = HeaderList::create(vm);
for (auto const& header : *internal_response->header_list()) {
if (!is_forbidden_response_header_name(header.name))
TRY(header_list->append(header));
}
return adopt_ref(*new BasicFilteredResponse(move(internal_response), move(header_list)));
return { *vm.heap().allocate_without_realm<BasicFilteredResponse>(internal_response, header_list) };
}
BasicFilteredResponse::BasicFilteredResponse(NonnullRefPtr<Response> internal_response, NonnullRefPtr<HeaderList> header_list)
: FilteredResponse(move(internal_response))
, m_header_list(move(header_list))
BasicFilteredResponse::BasicFilteredResponse(JS::NonnullGCPtr<Response> internal_response, JS::NonnullGCPtr<HeaderList> header_list)
: FilteredResponse(internal_response, header_list)
, m_header_list(header_list)
{
}
ErrorOr<NonnullRefPtr<CORSFilteredResponse>> CORSFilteredResponse::create(NonnullRefPtr<Response> internal_response)
void BasicFilteredResponse::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_header_list);
}
ErrorOr<JS::NonnullGCPtr<CORSFilteredResponse>> CORSFilteredResponse::create(JS::VM& vm, JS::NonnullGCPtr<Response> internal_response)
{
// 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
@ -176,43 +196,63 @@ ErrorOr<NonnullRefPtr<CORSFilteredResponse>> CORSFilteredResponse::create(Nonnul
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>();
auto header_list = HeaderList::create(vm);
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_ref(*new CORSFilteredResponse(move(internal_response), move(header_list)));
return { *vm.heap().allocate_without_realm<CORSFilteredResponse>(internal_response, header_list) };
}
CORSFilteredResponse::CORSFilteredResponse(NonnullRefPtr<Response> internal_response, NonnullRefPtr<HeaderList> header_list)
: FilteredResponse(move(internal_response))
, m_header_list(move(header_list))
CORSFilteredResponse::CORSFilteredResponse(JS::NonnullGCPtr<Response> internal_response, JS::NonnullGCPtr<HeaderList> header_list)
: FilteredResponse(internal_response, header_list)
, m_header_list(header_list)
{
}
NonnullRefPtr<OpaqueFilteredResponse> OpaqueFilteredResponse::create(NonnullRefPtr<Response> internal_response)
void CORSFilteredResponse::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_header_list);
}
JS::NonnullGCPtr<OpaqueFilteredResponse> OpaqueFilteredResponse::create(JS::VM& vm, JS::NonnullGCPtr<Response> internal_response)
{
// An opaque filtered response is a filtered response whose type is "opaque", URL list is the empty list,
// status is 0, status message is the empty byte sequence, header list is empty, and body is null.
return { *vm.heap().allocate_without_realm<OpaqueFilteredResponse>(internal_response, HeaderList::create(vm)) };
}
OpaqueFilteredResponse::OpaqueFilteredResponse(JS::NonnullGCPtr<Response> internal_response, JS::NonnullGCPtr<HeaderList> header_list)
: FilteredResponse(internal_response, header_list)
, m_header_list(header_list)
{
}
void OpaqueFilteredResponse::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_header_list);
}
JS::NonnullGCPtr<OpaqueRedirectFilteredResponse> OpaqueRedirectFilteredResponse::create(JS::VM& vm, JS::NonnullGCPtr<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_ref(*new OpaqueFilteredResponse(move(internal_response)));
return { *vm.heap().allocate_without_realm<OpaqueRedirectFilteredResponse>(internal_response, HeaderList::create(vm)) };
}
OpaqueFilteredResponse::OpaqueFilteredResponse(NonnullRefPtr<Response> internal_response)
: FilteredResponse(move(internal_response))
, m_header_list(make_ref_counted<HeaderList>())
OpaqueRedirectFilteredResponse::OpaqueRedirectFilteredResponse(JS::NonnullGCPtr<Response> internal_response, JS::NonnullGCPtr<HeaderList> header_list)
: FilteredResponse(internal_response, header_list)
, m_header_list(header_list)
{
}
NonnullRefPtr<OpaqueRedirectFilteredResponse> OpaqueRedirectFilteredResponse::create(NonnullRefPtr<Response> internal_response)
{
return adopt_ref(*new OpaqueRedirectFilteredResponse(move(internal_response)));
}
OpaqueRedirectFilteredResponse::OpaqueRedirectFilteredResponse(NonnullRefPtr<Response> internal_response)
: FilteredResponse(move(internal_response))
, m_header_list(make_ref_counted<HeaderList>())
void OpaqueRedirectFilteredResponse::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_header_list);
}
}

View file

@ -10,9 +10,10 @@
#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 <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Statuses.h>
@ -20,7 +21,9 @@
namespace Web::Fetch::Infrastructure {
// https://fetch.spec.whatwg.org/#concept-response
class Response : public RefCounted<Response> {
class Response : public JS::Cell {
JS_CELL(Response, JS::Cell);
public:
enum class CacheState {
Local,
@ -45,9 +48,9 @@ public:
u64 decoded_size { 0 };
};
[[nodiscard]] static NonnullRefPtr<Response> create();
[[nodiscard]] static NonnullRefPtr<Response> aborted_network_error();
[[nodiscard]] static NonnullRefPtr<Response> network_error();
[[nodiscard]] static JS::NonnullGCPtr<Response> create(JS::VM&);
[[nodiscard]] static JS::NonnullGCPtr<Response> aborted_network_error(JS::VM&);
[[nodiscard]] static JS::NonnullGCPtr<Response> network_error(JS::VM&);
virtual ~Response() = default;
@ -67,9 +70,8 @@ public:
[[nodiscard]] virtual ReadonlyBytes status_message() const { return m_status_message; }
void set_status_message(ByteBuffer status_message) { m_status_message = move(status_message); }
[[nodiscard]] virtual NonnullRefPtr<HeaderList> const& header_list() const { return m_header_list; }
[[nodiscard]] virtual NonnullRefPtr<HeaderList>& header_list() { return m_header_list; }
void set_header_list(NonnullRefPtr<HeaderList> header_list) { m_header_list = move(header_list); }
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const { return m_header_list; }
void set_header_list(JS::NonnullGCPtr<HeaderList> header_list) { m_header_list = header_list; }
[[nodiscard]] virtual Optional<Body> const& body() const { return m_body; }
[[nodiscard]] virtual Optional<Body>& body() { return m_body; }
@ -99,10 +101,12 @@ public:
[[nodiscard]] Optional<AK::URL const&> url() const;
[[nodiscard]] ErrorOr<Optional<AK::URL>> location_url(Optional<String> const& request_fragment) const;
[[nodiscard]] WebIDL::ExceptionOr<NonnullRefPtr<Response>> clone() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> clone(JS::VM&) const;
protected:
Response();
explicit Response(JS::NonnullGCPtr<HeaderList>);
virtual void visit_edges(JS::Cell::Visitor&) override;
private:
// https://fetch.spec.whatwg.org/#concept-response-type
@ -127,7 +131,7 @@ private:
// https://fetch.spec.whatwg.org/#concept-response-header-list
// A response has an associated header list (a header list). Unless stated otherwise it is empty.
NonnullRefPtr<HeaderList> m_header_list;
JS::NonnullGCPtr<HeaderList> m_header_list;
// https://fetch.spec.whatwg.org/#concept-response-body
// A response has an associated body (null or a body). Unless stated otherwise it is null.
@ -163,8 +167,10 @@ private:
// https://fetch.spec.whatwg.org/#concept-filtered-response
class FilteredResponse : public Response {
JS_CELL(FilteredResponse, Response);
public:
explicit FilteredResponse(NonnullRefPtr<Response>);
FilteredResponse(JS::NonnullGCPtr<Response>, JS::NonnullGCPtr<HeaderList>);
virtual ~FilteredResponse() = 0;
[[nodiscard]] virtual Type type() const override { return m_internal_response->type(); }
@ -173,8 +179,7 @@ public:
[[nodiscard]] virtual Vector<AK::URL>& url_list() 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 NonnullRefPtr<HeaderList>& header_list() override { return m_internal_response->header_list(); }
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const override { return m_internal_response->header_list(); }
[[nodiscard]] virtual Optional<Body> const& body() const override { return m_internal_response->body(); }
[[nodiscard]] virtual Optional<Body>& body() override { return m_internal_response->body(); }
[[nodiscard]] virtual Optional<CacheState> const& cache_state() const override { return m_internal_response->cache_state(); }
@ -184,83 +189,98 @@ public:
[[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; }
[[nodiscard]] JS::NonnullGCPtr<Response> internal_response() const { return m_internal_response; }
protected:
virtual void visit_edges(JS::Cell::Visitor&) override;
private:
// https://fetch.spec.whatwg.org/#concept-internal-response
NonnullRefPtr<Response> m_internal_response;
JS::NonnullGCPtr<Response> m_internal_response;
};
// https://fetch.spec.whatwg.org/#concept-filtered-response-basic
class BasicFilteredResponse final : public FilteredResponse {
JS_CELL(OpaqueRedirectFilteredResponse, FilteredResponse);
public:
static ErrorOr<NonnullRefPtr<BasicFilteredResponse>> create(NonnullRefPtr<Response>);
[[nodiscard]] static ErrorOr<JS::NonnullGCPtr<BasicFilteredResponse>> create(JS::VM&, JS::NonnullGCPtr<Response>);
[[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>& header_list() override { return m_header_list; }
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const override { return m_header_list; }
private:
BasicFilteredResponse(NonnullRefPtr<Response>, NonnullRefPtr<HeaderList>);
BasicFilteredResponse(JS::NonnullGCPtr<Response>, JS::NonnullGCPtr<HeaderList>);
NonnullRefPtr<HeaderList> m_header_list;
virtual void visit_edges(JS::Cell::Visitor&) override;
JS::NonnullGCPtr<HeaderList> m_header_list;
};
// https://fetch.spec.whatwg.org/#concept-filtered-response-cors
class CORSFilteredResponse final : public FilteredResponse {
JS_CELL(CORSFilteredResponse, FilteredResponse);
public:
static ErrorOr<NonnullRefPtr<CORSFilteredResponse>> create(NonnullRefPtr<Response>);
[[nodiscard]] static ErrorOr<JS::NonnullGCPtr<CORSFilteredResponse>> create(JS::VM&, JS::NonnullGCPtr<Response>);
[[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>& header_list() override { return m_header_list; }
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const override { return m_header_list; }
private:
CORSFilteredResponse(NonnullRefPtr<Response>, NonnullRefPtr<HeaderList>);
CORSFilteredResponse(JS::NonnullGCPtr<Response>, JS::NonnullGCPtr<HeaderList>);
NonnullRefPtr<HeaderList> m_header_list;
virtual void visit_edges(JS::Cell::Visitor&) override;
JS::NonnullGCPtr<HeaderList> m_header_list;
};
// https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
class OpaqueFilteredResponse final : public FilteredResponse {
JS_CELL(OpaqueFilteredResponse, FilteredResponse);
public:
static NonnullRefPtr<OpaqueFilteredResponse> create(NonnullRefPtr<Response>);
[[nodiscard]] static JS::NonnullGCPtr<OpaqueFilteredResponse> create(JS::VM&, JS::NonnullGCPtr<Response>);
[[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>& url_list() override { return m_url_list; }
[[nodiscard]] virtual Status status() const override { return 0; }
[[nodiscard]] virtual ReadonlyBytes status_message() const override { return {}; }
[[nodiscard]] virtual NonnullRefPtr<HeaderList> const& header_list() const override { return m_header_list; }
[[nodiscard]] virtual NonnullRefPtr<HeaderList>& header_list() override { return m_header_list; }
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const override { return m_header_list; }
[[nodiscard]] virtual Optional<Body> const& body() const override { return m_body; }
[[nodiscard]] virtual Optional<Body>& body() override { return m_body; }
private:
explicit OpaqueFilteredResponse(NonnullRefPtr<Response>);
OpaqueFilteredResponse(JS::NonnullGCPtr<Response>, JS::NonnullGCPtr<HeaderList>);
virtual void visit_edges(JS::Cell::Visitor&) override;
Vector<AK::URL> m_url_list;
NonnullRefPtr<HeaderList> m_header_list;
JS::NonnullGCPtr<HeaderList> m_header_list;
Optional<Body> m_body;
};
// https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect
class OpaqueRedirectFilteredResponse final : public FilteredResponse {
JS_CELL(OpaqueRedirectFilteredResponse, FilteredResponse);
public:
static NonnullRefPtr<OpaqueRedirectFilteredResponse> create(NonnullRefPtr<Response>);
[[nodiscard]] static JS::NonnullGCPtr<OpaqueRedirectFilteredResponse> create(JS::VM&, JS::NonnullGCPtr<Response>);
[[nodiscard]] virtual Type type() const override { return Type::OpaqueRedirect; }
[[nodiscard]] virtual Status status() const override { return 0; }
[[nodiscard]] virtual ReadonlyBytes status_message() const override { return {}; }
[[nodiscard]] virtual NonnullRefPtr<HeaderList> const& header_list() const override { return m_header_list; }
[[nodiscard]] virtual NonnullRefPtr<HeaderList>& header_list() override { return m_header_list; }
[[nodiscard]] virtual JS::NonnullGCPtr<HeaderList> header_list() const override { return m_header_list; }
[[nodiscard]] virtual Optional<Body> const& body() const override { return m_body; }
[[nodiscard]] virtual Optional<Body>& body() override { return m_body; }
private:
explicit OpaqueRedirectFilteredResponse(NonnullRefPtr<Response>);
OpaqueRedirectFilteredResponse(JS::NonnullGCPtr<Response>, JS::NonnullGCPtr<HeaderList>);
NonnullRefPtr<HeaderList> m_header_list;
virtual void visit_edges(JS::Cell::Visitor&) override;
JS::NonnullGCPtr<HeaderList> m_header_list;
Optional<Body> m_body;
};

View file

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

View file

@ -64,7 +64,7 @@ class Request final
WEB_PLATFORM_OBJECT(Request, Bindings::PlatformObject);
public:
static JS::NonnullGCPtr<Request> create(NonnullRefPtr<Infrastructure::Request>, Headers::Guard, JS::Realm&);
[[nodiscard]] static JS::NonnullGCPtr<Request> create(JS::Realm&, JS::NonnullGCPtr<Infrastructure::Request>, Headers::Guard);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> construct_impl(JS::Realm&, RequestInfo const& input, RequestInit const& init = {});
virtual ~Request() override;
@ -74,7 +74,7 @@ public:
virtual Optional<Infrastructure::Body&> body_impl() override;
virtual Optional<Infrastructure::Body const&> body_impl() const override;
[[nodiscard]] NonnullRefPtr<Infrastructure::Request> request() const { return m_request; }
[[nodiscard]] JS::NonnullGCPtr<Infrastructure::Request> request() const { return m_request; }
// JS API functions
[[nodiscard]] String method() const;
@ -96,13 +96,13 @@ public:
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> clone() const;
private:
Request(JS::Realm&, NonnullRefPtr<Infrastructure::Request>);
Request(JS::Realm&, JS::NonnullGCPtr<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).
NonnullRefPtr<Infrastructure::Request> m_request;
JS::NonnullGCPtr<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.

View file

@ -17,9 +17,9 @@
namespace Web::Fetch {
Response::Response(JS::Realm& realm, NonnullRefPtr<Infrastructure::Response> response)
Response::Response(JS::Realm& realm, JS::NonnullGCPtr<Infrastructure::Response> response)
: PlatformObject(realm)
, m_response(move(response))
, m_response(response)
{
set_prototype(&Bindings::cached_web_prototype(realm, "Response"));
}
@ -29,6 +29,7 @@ Response::~Response() = default;
void Response::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_response);
visitor.visit(m_headers);
}
@ -64,18 +65,14 @@ Optional<Infrastructure::Body&> Response::body_impl()
}
// https://fetch.spec.whatwg.org/#response-create
JS::NonnullGCPtr<Response> Response::create(NonnullRefPtr<Infrastructure::Response> response, Headers::Guard guard, JS::Realm& realm)
JS::NonnullGCPtr<Response> Response::create(JS::Realm& realm, JS::NonnullGCPtr<Infrastructure::Response> response, Headers::Guard guard)
{
// Copy a NonnullRefPtr to the response's header list before response is being move()'d.
auto response_reader_list = response->header_list();
// 1. Let responseObject be a new Response object with realm.
// 2. Set responseObjects response to response.
auto* response_object = realm.heap().allocate<Response>(realm, realm, move(response));
auto* response_object = realm.heap().allocate<Response>(realm, realm, response);
// 3. Set responseObjects headers to a new Headers object with realm, whose headers list is responses headers list and guard is guard.
response_object->m_headers = realm.heap().allocate<Headers>(realm, realm);
response_object->m_headers->set_header_list(move(response_reader_list));
response_object->m_headers = realm.heap().allocate<Headers>(realm, realm, response->header_list());
response_object->m_headers->set_guard(guard);
// 4. Return responseObject.
@ -126,16 +123,17 @@ WebIDL::ExceptionOr<void> Response::initialize_response(ResponseInit const& init
// https://fetch.spec.whatwg.org/#dom-response
WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::construct_impl(JS::Realm& realm, Optional<BodyInit> const& body, ResponseInit const& init)
{
auto& vm = realm.vm();
// Referred to as 'this' in the spec.
auto response_object = JS::NonnullGCPtr { *realm.heap().allocate<Response>(realm, realm, Infrastructure::Response::create()) };
auto response_object = JS::NonnullGCPtr { *realm.heap().allocate<Response>(realm, realm, Infrastructure::Response::create(vm)) };
// 1. Set thiss response to a new response.
// NOTE: This is done at the beginning as the 'this' value Response object
// cannot exist with a null Infrastructure::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->set_header_list(response_object->response()->header_list());
response_object->m_headers = realm.heap().allocate<Headers>(realm, realm, response_object->response()->header_list());
response_object->m_headers->set_guard(Headers::Guard::Response);
// 3. Let bodyWithType be null.
@ -156,7 +154,7 @@ JS::NonnullGCPtr<Response> Response::error(JS::VM& vm)
{
// The static error() method steps are to return the result of creating a Response object, given a new network error, "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?
return Response::create(Infrastructure::Response::network_error(), Headers::Guard::Immutable, *vm.current_realm());
return Response::create(*vm.current_realm(), Infrastructure::Response::network_error(vm), Headers::Guard::Immutable);
}
// https://fetch.spec.whatwg.org/#dom-response-redirect
@ -178,7 +176,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::redirect(JS::VM& vm, S
// 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?
auto response_object = Response::create(Infrastructure::Response::create(), Headers::Guard::Immutable, realm);
auto response_object = Response::create(realm, Infrastructure::Response::create(vm), Headers::Guard::Immutable);
// 5. Set responseObjects responses status to status.
response_object->response()->set_status(status);
@ -207,7 +205,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::json(JS::VM& vm, JS::V
// 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?
auto response_object = Response::create(Infrastructure::Response::create(), Headers::Guard::Response, realm);
auto response_object = Response::create(realm, Infrastructure::Response::create(vm), Headers::Guard::Response);
// 4. Perform initialize a response given responseObject, init, and (body, "application/json").
auto body_with_type = Infrastructure::BodyWithType {
@ -274,15 +272,17 @@ JS::NonnullGCPtr<Headers> Response::headers() const
// https://fetch.spec.whatwg.org/#dom-response-clone
WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::clone() const
{
auto& vm = this->vm();
// 1. If this is unusable, then throw a TypeError.
if (is_unusable())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Response is unusable"sv };
// 2. Let clonedResponse be the result of cloning thiss response.
auto cloned_response = TRY(m_response->clone());
auto cloned_response = TRY(m_response->clone(vm));
// 3. Return the result of creating a Response object, given clonedResponse, thiss headerss guard, and thiss relevant Realm.
return Response::create(move(cloned_response), m_headers->guard(), HTML::relevant_realm(*this));
return Response::create(HTML::relevant_realm(*this), cloned_response, m_headers->guard());
}
}

View file

@ -31,7 +31,7 @@ class Response final
WEB_PLATFORM_OBJECT(Response, Bindings::PlatformObject);
public:
static JS::NonnullGCPtr<Response> create(NonnullRefPtr<Infrastructure::Response>, Headers::Guard, JS::Realm&);
static JS::NonnullGCPtr<Response> create(JS::Realm&, JS::NonnullGCPtr<Infrastructure::Response>, Headers::Guard);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> construct_impl(JS::Realm&, Optional<BodyInit> const& body = {}, ResponseInit const& init = {});
virtual ~Response() override;
@ -41,7 +41,7 @@ public:
virtual Optional<Infrastructure::Body&> body_impl() override;
virtual Optional<Infrastructure::Body const&> body_impl() const override;
[[nodiscard]] NonnullRefPtr<Infrastructure::Response> response() const { return m_response; }
[[nodiscard]] JS::NonnullGCPtr<Infrastructure::Response> response() const { return m_response; }
// JS API functions
[[nodiscard]] static JS::NonnullGCPtr<Response> error(JS::VM&);
@ -60,7 +60,7 @@ public:
using BodyMixin::json;
private:
Response(JS::Realm&, NonnullRefPtr<Infrastructure::Response>);
Response(JS::Realm&, JS::NonnullGCPtr<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).
NonnullRefPtr<Infrastructure::Response> m_response;
JS::NonnullGCPtr<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.

View file

@ -885,14 +885,14 @@ void BrowsingContext::remove()
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
WebIDL::ExceptionOr<void> BrowsingContext::navigate(
NonnullRefPtr<Fetch::Infrastructure::Request> resource,
JS::NonnullGCPtr<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(NonnullRefPtr<Fetch::Infrastructure::Response>)> process_response_end_of_body)
Function<void(JS::NonnullGCPtr<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.
@ -1060,7 +1060,8 @@ 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::create();
auto& vm = Bindings::main_thread_vm();
auto request = Fetch::Infrastructure::Request::create(vm);
request->set_url(entry->url);
// 3. If explicitHistoryNavigation is true, then set request's history-navigation flag.
@ -1071,7 +1072,7 @@ WebIDL::ExceptionOr<void> BrowsingContext::traverse_the_history(size_t entry_ind
// 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(move(request), *entry->original_source_browsing_context, false, HistoryHandlingBehavior::EntryUpdate, entry->policy_container));
TRY(navigate(request, *entry->original_source_browsing_context, false, HistoryHandlingBehavior::EntryUpdate, entry->policy_container));
// 5. Return.
return {};

View file

@ -13,6 +13,7 @@
#include <LibGfx/Bitmap.h>
#include <LibGfx/Rect.h>
#include <LibGfx/Size.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/DOM/Position.h>
#include <LibWeb/HTML/BrowsingContextContainer.h>
@ -216,14 +217,14 @@ public:
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
WebIDL::ExceptionOr<void> navigate(
NonnullRefPtr<Fetch::Infrastructure::Request> resource,
JS::NonnullGCPtr<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(NonnullRefPtr<Fetch::Infrastructure::Response>)> process_response_end_of_body = {});
Function<void(JS::NonnullGCPtr<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);

View file

@ -169,7 +169,7 @@ 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::create();
auto resource = Fetch::Infrastructure::Request::create(vm());
resource->set_url(url);
// FIXME: Set the referrer policy.
@ -193,11 +193,11 @@ void BrowsingContextContainer::shared_attribute_processing_steps_for_iframe_and_
}
// 8. Navigate to the resource: navigate an iframe or frame given element and resource.
navigate_an_iframe_or_frame(move(resource));
navigate_an_iframe_or_frame(resource);
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame
void BrowsingContextContainer::navigate_an_iframe_or_frame(NonnullRefPtr<Fetch::Infrastructure::Request> resource)
void BrowsingContextContainer::navigate_an_iframe_or_frame(JS::NonnullGCPtr<Fetch::Infrastructure::Request> resource)
{
// 1. Let historyHandling be "default".
auto history_handling = HistoryHandlingBehavior::Default;
@ -220,7 +220,7 @@ void BrowsingContextContainer::navigate_an_iframe_or_frame(NonnullRefPtr<Fetch::
// FIXME: and processResponseEndOfBody set to reportFrameTiming.
auto* source_browsing_context = document().browsing_context();
VERIFY(source_browsing_context);
m_nested_browsing_context->navigate(move(resource), *source_browsing_context, false, history_handling);
m_nested_browsing_context->navigate(resource, *source_browsing_context, false, history_handling);
}
}

View file

@ -37,7 +37,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(NonnullRefPtr<Fetch::Infrastructure::Request>);
void navigate_an_iframe_or_frame(JS::NonnullGCPtr<Fetch::Infrastructure::Request>);
void create_new_nested_browsing_context();

View file

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

View file

@ -11,6 +11,7 @@
#include <LibGemini/Document.h>
#include <LibGfx/ImageDecoder.h>
#include <LibMarkdown/Document.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Cookie/ParsedCookie.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/ElementFactory.h>
@ -298,12 +299,13 @@ bool FrameLoader::load(const AK::URL& url, Type type)
void FrameLoader::load_html(StringView html, const AK::URL& url)
{
auto response = Fetch::Infrastructure::Response::create();
auto& vm = Bindings::main_thread_vm();
auto response = Fetch::Infrastructure::Response::create(vm);
response->url_list().append(url);
HTML::NavigationParams navigation_params {
.id = {},
.request = nullptr,
.response = move(response),
.response = response,
.origin = HTML::Origin {},
.policy_container = HTML::PolicyContainer {},
.final_sandboxing_flag_set = HTML::SandboxingFlagSet {},
@ -418,15 +420,16 @@ void FrameLoader::resource_did_load()
// FIXME: Pass incumbentNavigationOrigin
auto response_origin = HTML::determine_the_origin(browsing_context(), url, final_sandboxing_flag_set, {});
auto response = Fetch::Infrastructure::Response::create();
auto& vm = Bindings::main_thread_vm();
auto response = Fetch::Infrastructure::Response::create(vm);
response->url_list().append(url);
HTML::NavigationParams navigation_params {
.id = {},
.request = nullptr,
.response = move(response),
.response = response,
.origin = move(response_origin),
.policy_container = HTML::PolicyContainer {},
.final_sandboxing_flag_set = move(final_sandboxing_flag_set),
.final_sandboxing_flag_set = final_sandboxing_flag_set,
.cross_origin_opener_policy = HTML::CrossOriginOpenerPolicy {},
.coop_enforcement_result = HTML::CrossOriginOpenerPolicyEnforcementResult {},
.reserved_environment = {},

View file

@ -236,8 +236,10 @@ MimeSniff::MimeType XMLHttpRequest::get_final_mime_type() const
// https://xhr.spec.whatwg.org/#response-mime-type
MimeSniff::MimeType XMLHttpRequest::get_response_mime_type() const
{
auto& vm = this->vm();
// FIXME: Use an actual HeaderList for XHR headers.
auto header_list = make_ref_counted<Fetch::Infrastructure::HeaderList>();
auto header_list = Fetch::Infrastructure::HeaderList::create(vm);
for (auto const& entry : m_response_headers) {
auto header = Fetch::Infrastructure::Header::from_string_pair(entry.key, entry.value).release_value_but_fixme_should_propagate_errors();
header_list->append(move(header)).release_value_but_fixme_should_propagate_errors();