diff --git a/Userland/Libraries/LibWeb/Fetch/Headers.cpp b/Userland/Libraries/LibWeb/Fetch/Headers.cpp index c921e54992..574d1abfd4 100644 --- a/Userland/Libraries/LibWeb/Fetch/Headers.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Headers.cpp @@ -28,6 +28,7 @@ WebIDL::ExceptionOr> Headers::create_with_global_objec Headers::Headers(HTML::Window& window) : PlatformObject(window.realm()) + , m_header_list(make_ref_counted()) { set_prototype(&window.cached_web_prototype("Headers")); } @@ -73,11 +74,11 @@ WebIDL::ExceptionOr Headers::delete_(String const& name_string) return {}; // 6. If this’s header list does not contain name, then return. - if (!m_header_list.contains(name)) + if (!m_header_list->contains(name)) return {}; // 7. Delete name from this’s header list. - m_header_list.delete_(name); + m_header_list->delete_(name); // 8. If this’s guard is "request-no-cors", then remove privileged no-CORS request headers from this. if (m_guard == Guard::RequestNoCORS) @@ -97,7 +98,7 @@ WebIDL::ExceptionOr Headers::get(String const& name_string) return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header name" }; // 2. Return the result of getting name from this’s header list. - auto byte_buffer = TRY_OR_RETURN_OOM(global_object(), m_header_list.get(name)); + auto byte_buffer = TRY_OR_RETURN_OOM(global_object(), m_header_list->get(name)); // FIXME: Teach BindingsGenerator about Optional return byte_buffer.has_value() ? String { byte_buffer->span() } : String {}; } @@ -113,7 +114,7 @@ WebIDL::ExceptionOr Headers::has(String const& name_string) return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header name" }; // 2. Return true if this’s header list contains name; otherwise false. - return m_header_list.contains(name); + return m_header_list->contains(name); } // https://fetch.spec.whatwg.org/#dom-headers-set @@ -154,7 +155,7 @@ WebIDL::ExceptionOr Headers::set(String const& name_string, String const& return {}; // 7. Set (name, value) in this’s header list. - TRY_OR_RETURN_OOM(global_object(), m_header_list.set(move(header))); + TRY_OR_RETURN_OOM(global_object(), m_header_list->set(move(header))); // 8. If this’s guard is "request-no-cors", then remove privileged no-CORS request headers from this. if (m_guard == Guard::RequestNoCORS) @@ -168,7 +169,7 @@ JS::ThrowCompletionOr Headers::for_each(ForEachCallback callback) { // The value pairs to iterate over are the return value of running sort and combine with this’s header list. auto value_pairs_to_iterate_over = [&]() -> JS::ThrowCompletionOr> { - auto headers_or_error = m_header_list.sort_and_combine(); + auto headers_or_error = m_header_list->sort_and_combine(); if (headers_or_error.is_error()) return vm().throw_completion(JS::ErrorType::NotEnoughMemoryToAllocate); return headers_or_error.release_value(); @@ -226,7 +227,7 @@ WebIDL::ExceptionOr Headers::append(Infrastructure::Header header) // 5. Otherwise, if headers’s guard is "request-no-cors": if (m_guard == Guard::RequestNoCORS) { // 1. Let temporaryValue be the result of getting name from headers’s header list. - auto temporary_value = TRY_OR_RETURN_OOM(global_object(), m_header_list.get(name)); + auto temporary_value = TRY_OR_RETURN_OOM(global_object(), m_header_list->get(name)); // 2. If temporaryValue is null, then set temporaryValue to value. if (!temporary_value.has_value()) { @@ -253,8 +254,8 @@ WebIDL::ExceptionOr Headers::append(Infrastructure::Header header) if (m_guard == Guard::Response && Infrastructure::is_forbidden_response_header_name(name)) return {}; - // 7. Append (name, value) to headers’s header list. - TRY_OR_RETURN_OOM(global_object(), m_header_list.append(move(header))); + // 7. Append (name, value) to headers’s header list + TRY_OR_RETURN_OOM(global_object(), m_header_list->append(move(header))); // 8. If headers’s guard is "request-no-cors", then remove privileged no-CORS request headers from headers. if (m_guard == Guard::RequestNoCORS) @@ -309,7 +310,7 @@ void Headers::remove_privileged_no_cors_headers() // 1. For each headerName of privileged no-CORS request-header names: for (auto const& header_name : privileged_no_cors_request_header_names) { // 1. Delete headerName from headers’s header list. - m_header_list.delete_(header_name.bytes()); + m_header_list->delete_(header_name.bytes()); } } diff --git a/Userland/Libraries/LibWeb/Fetch/Headers.h b/Userland/Libraries/LibWeb/Fetch/Headers.h index 2ff735db80..98c5914538 100644 --- a/Userland/Libraries/LibWeb/Fetch/Headers.h +++ b/Userland/Libraries/LibWeb/Fetch/Headers.h @@ -35,9 +35,9 @@ public: virtual ~Headers() override; - [[nodiscard]] Infrastructure::HeaderList& header_list() { return m_header_list; } - [[nodiscard]] Infrastructure::HeaderList const& header_list() const { return m_header_list; } - void set_header_list(Infrastructure::HeaderList header_list) { m_header_list = move(header_list); } + [[nodiscard]] NonnullRefPtr& header_list() { return m_header_list; } + [[nodiscard]] NonnullRefPtr const& header_list() const { return m_header_list; } + void set_header_list(NonnullRefPtr header_list) { m_header_list = move(header_list); } [[nodiscard]] Guard guard() const { return m_guard; } void set_guard(Guard guard) { m_guard = guard; } @@ -63,7 +63,7 @@ private: // https://fetch.spec.whatwg.org/#concept-headers-header-list // A Headers object has an associated header list (a header list), which is initially empty. - Infrastructure::HeaderList m_header_list; + NonnullRefPtr 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". diff --git a/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp b/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp index 47110fdd4c..6f118d6369 100644 --- a/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp +++ b/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp @@ -38,7 +38,7 @@ JS::ThrowCompletionOr HeadersIterator::next() { // The value pairs to iterate over are the return value of running sort and combine with this’s header list. auto value_pairs_to_iterate_over = [&]() -> JS::ThrowCompletionOr> { - auto headers_or_error = m_headers.m_header_list.sort_and_combine(); + auto headers_or_error = m_headers.m_header_list->sort_and_combine(); if (headers_or_error.is_error()) return vm().throw_completion(JS::ErrorType::NotEnoughMemoryToAllocate); return headers_or_error.release_value(); diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h index db36c03f75..e1461120aa 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h @@ -26,7 +26,9 @@ 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 : Vector
{ +class HeaderList final + : public RefCounted + , Vector
{ public: using Vector::begin; using Vector::end; diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp index cee01c4fe3..793f1ed1bb 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp @@ -9,6 +9,11 @@ namespace Web::Fetch::Infrastructure { +Request::Request() + : m_header_list(make_ref_counted()) +{ +} + // https://fetch.spec.whatwg.org/#concept-request-url AK::URL const& Request::url() const { @@ -202,7 +207,7 @@ ErrorOr Request::add_range_reader(u64 first, Optional const& last) .name = TRY(ByteBuffer::copy("Range"sv.bytes())), .value = move(range_value), }; - TRY(m_header_list.append(move(header))); + TRY(m_header_list->append(move(header))); return {}; } diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h index 6a453123cc..645bb9648a 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h @@ -154,7 +154,7 @@ public: using ReservedClientType = Variant; using WindowType = Variant; - Request() = default; + Request(); [[nodiscard]] ReadonlyBytes method() const { return m_method; } void set_method(ByteBuffer method) { m_method = move(method); } @@ -162,9 +162,9 @@ 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]] HeaderList const& header_list() const { return m_header_list; } - [[nodiscard]] HeaderList& header_list() { return m_header_list; } - void set_header_list(HeaderList header_list) { m_header_list = move(header_list); } + [[nodiscard]] NonnullRefPtr const& header_list() const { return m_header_list; } + [[nodiscard]] NonnullRefPtr& header_list() { return m_header_list; } + void set_header_list(NonnullRefPtr header_list) { m_header_list = move(header_list); } [[nodiscard]] bool unsafe_request() const { return m_unsafe_request; } void set_unsafe_request(bool unsafe_request) { m_unsafe_request = unsafe_request; } @@ -304,7 +304,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. - HeaderList m_header_list; + NonnullRefPtr 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. diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp index 0be7e4e758..156126d7d5 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp @@ -9,6 +9,11 @@ namespace Web::Fetch::Infrastructure { +Response::Response() + : m_header_list(make_ref_counted()) +{ +} + // 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. @@ -111,16 +116,16 @@ ErrorOr> BasicFilteredResponse::create(Resp { // 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. - HeaderList header_list; - for (auto const& header : internal_response.header_list()) { + auto header_list = make_ref_counted(); + for (auto const& header : *internal_response.header_list()) { if (!is_forbidden_response_header_name(header.name)) - TRY(header_list.append(header)); + TRY(header_list->append(header)); } return adopt_own(*new BasicFilteredResponse(internal_response, move(header_list))); } -BasicFilteredResponse::BasicFilteredResponse(Response& internal_response, HeaderList header_list) +BasicFilteredResponse::BasicFilteredResponse(Response& internal_response, NonnullRefPtr header_list) : FilteredResponse(internal_response) , m_header_list(move(header_list)) { @@ -135,16 +140,16 @@ ErrorOr> CORSFilteredResponse::create(Respon for (auto const& header_name : internal_response.cors_exposed_header_name_list()) cors_exposed_header_name_list.append(header_name.span()); - HeaderList header_list; - for (auto const& header : internal_response.header_list()) { + auto header_list = make_ref_counted(); + 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)); + TRY(header_list->append(header)); } return adopt_own(*new CORSFilteredResponse(internal_response, move(header_list))); } -CORSFilteredResponse::CORSFilteredResponse(Response& internal_response, HeaderList header_list) +CORSFilteredResponse::CORSFilteredResponse(Response& internal_response, NonnullRefPtr header_list) : FilteredResponse(internal_response) , m_header_list(move(header_list)) { @@ -159,6 +164,7 @@ NonnullOwnPtr OpaqueFilteredResponse::create(Response& i OpaqueFilteredResponse::OpaqueFilteredResponse(Response& internal_response) : FilteredResponse(internal_response) + , m_header_list(make_ref_counted()) { } @@ -169,6 +175,7 @@ NonnullOwnPtr OpaqueRedirectFilteredResponse::cr OpaqueRedirectFilteredResponse::OpaqueRedirectFilteredResponse(Response& internal_response) : FilteredResponse(internal_response) + , m_header_list(make_ref_counted()) { } diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h index 879f0ecf32..d7c879223f 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h @@ -47,7 +47,7 @@ public: [[nodiscard]] static NonnullOwnPtr aborted_network_error(); [[nodiscard]] static NonnullOwnPtr network_error(); - Response() = default; + Response(); virtual ~Response() = default; [[nodiscard]] virtual Type type() const { return m_type; } @@ -66,9 +66,9 @@ 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 HeaderList const& header_list() const { return m_header_list; } - [[nodiscard]] HeaderList& header_list() { return m_header_list; } - void set_header_list(HeaderList header_list) { m_header_list = move(header_list); } + [[nodiscard]] virtual NonnullRefPtr const& header_list() const { return m_header_list; } + [[nodiscard]] NonnullRefPtr& header_list() { return m_header_list; } + void set_header_list(NonnullRefPtr header_list) { m_header_list = move(header_list); } [[nodiscard]] virtual Optional const& body() const { return m_body; } [[nodiscard]] Optional& body() { return m_body; } @@ -124,7 +124,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. - HeaderList m_header_list; + NonnullRefPtr 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. @@ -169,7 +169,7 @@ public: [[nodiscard]] virtual Vector const& url_list() const override { return m_internal_response.url_list(); } [[nodiscard]] virtual Status status() const override { return m_internal_response.status(); } [[nodiscard]] virtual ReadonlyBytes status_message() const override { return m_internal_response.status_message(); } - [[nodiscard]] virtual HeaderList const& header_list() const override { return m_internal_response.header_list(); } + [[nodiscard]] virtual NonnullRefPtr const& header_list() const override { return m_internal_response.header_list(); } [[nodiscard]] virtual Optional const& body() const override { return m_internal_response.body(); } [[nodiscard]] virtual Optional const& cache_state() const override { return m_internal_response.cache_state(); } [[nodiscard]] virtual Vector const& cors_exposed_header_name_list() const override { return m_internal_response.cors_exposed_header_name_list(); } @@ -192,12 +192,12 @@ public: static ErrorOr> create(Response&); [[nodiscard]] virtual Type type() const override { return Type::Basic; } - [[nodiscard]] virtual HeaderList const& header_list() const override { return m_header_list; } + [[nodiscard]] virtual NonnullRefPtr const& header_list() const override { return m_header_list; } private: - BasicFilteredResponse(Response&, HeaderList); + BasicFilteredResponse(Response&, NonnullRefPtr); - HeaderList m_header_list; + NonnullRefPtr m_header_list; }; // https://fetch.spec.whatwg.org/#concept-filtered-response-cors @@ -206,12 +206,12 @@ public: static ErrorOr> create(Response&); [[nodiscard]] virtual Type type() const override { return Type::CORS; } - [[nodiscard]] virtual HeaderList const& header_list() const override { return m_header_list; } + [[nodiscard]] virtual NonnullRefPtr const& header_list() const override { return m_header_list; } private: - CORSFilteredResponse(Response&, HeaderList); + CORSFilteredResponse(Response&, NonnullRefPtr); - HeaderList m_header_list; + NonnullRefPtr m_header_list; }; // https://fetch.spec.whatwg.org/#concept-filtered-response-opaque @@ -223,14 +223,14 @@ public: [[nodiscard]] virtual Vector const& url_list() const override { return m_url_list; } [[nodiscard]] virtual Status status() const override { return 0; } [[nodiscard]] virtual ReadonlyBytes status_message() const override { return {}; } - [[nodiscard]] virtual HeaderList const& header_list() const override { return m_header_list; } + [[nodiscard]] virtual NonnullRefPtr const& header_list() const override { return m_header_list; } [[nodiscard]] virtual Optional const& body() const override { return m_body; } private: explicit OpaqueFilteredResponse(Response&); Vector m_url_list; - HeaderList m_header_list; + NonnullRefPtr m_header_list; Optional m_body; }; @@ -242,13 +242,13 @@ public: [[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 HeaderList const& header_list() const override { return m_header_list; } + [[nodiscard]] virtual NonnullRefPtr const& header_list() const override { return m_header_list; } [[nodiscard]] virtual Optional const& body() const override { return m_body; } private: explicit OpaqueRedirectFilteredResponse(Response&); - HeaderList m_header_list; + NonnullRefPtr m_header_list; Optional m_body; };