mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-30 08:41:15 +00:00
LibWeb: Make Fetch::Infrastructure::{Request,Response,HeaderList} GC'd
This is the way. On a more serious note, there's no reason to keep adding ref-counted classes to LibWeb now that the majority of classes is GC'd - it only adds the risk of discovering some cycle down the line, and forces us to use handles as we can't visit().
This commit is contained in:
parent
63122d0276
commit
b1968b8bed
Notes:
sideshowbarker
2024-07-17 05:01:32 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/b1968b8bed Pull-request: https://github.com/SerenityOS/serenity/pull/15853
|
@ -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 this’s 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)
|
||||
{
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 response’s 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 response’s 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 response’s 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 requestObject’s 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 requestObject’s headers to a new Headers object with realm, whose headers list is request’s 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 requestObject’s 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 request’s 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 this’s headers to a new Headers object with this’s relevant Realm, whose header list is request’s header list and guard is "request".
|
||||
request_object->m_headers = realm.heap().allocate<Headers>(realm, realm);
|
||||
request_object->m_headers->set_header_list(request->header_list());
|
||||
request_object->m_headers = realm.heap().allocate<Headers>(realm, realm, request->header_list());
|
||||
request_object->m_headers->set_guard(Headers::Guard::Request);
|
||||
|
||||
// 31. If this’s request’s 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 this’s 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 (header’s name, header’s value) to this’s 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 this’s 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 this’s 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, this’s headers’s guard, and this’s 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 clonedRequestObject’s signal follow this’s signal.
|
||||
cloned_request_object->m_signal->follow(*m_signal);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 responseObject’s 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 responseObject’s headers to a new Headers object with realm, whose headers list is response’s 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 this’s 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 this’s headers to a new Headers object with this’s relevant Realm, whose header list is this’s response’s header list and guard is "response".
|
||||
response_object->m_headers = realm.heap().allocate<Headers>(realm, realm);
|
||||
response_object->m_headers->set_header_list(response_object->response()->header_list());
|
||||
response_object->m_headers = 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 this’s 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 this’s relevant Realm.
|
||||
// FIXME: How can we reliably get 'this', i.e. the object the function was called on, in IDL-defined functions?
|
||||
auto response_object = Response::create(Infrastructure::Response::create(), Headers::Guard::Immutable, realm);
|
||||
auto response_object = Response::create(realm, Infrastructure::Response::create(vm), Headers::Guard::Immutable);
|
||||
|
||||
// 5. Set responseObject’s response’s 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 this’s relevant Realm.
|
||||
// FIXME: How can we reliably get 'this', i.e. the object the function was called on, in IDL-defined functions?
|
||||
auto response_object = Response::create(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 this’s 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, this’s headers’s guard, and this’s 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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {},
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue