diff options
author | Linus Groh <mail@linusgroh.de> | 2022-07-19 00:19:24 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-07-19 00:27:35 +0100 |
commit | ed49b66f2558a928e04b8f30c31f15426e894b7e (patch) | |
tree | 02962bc49bc21d8dbdf845d24d41dafeba4b3789 | |
parent | b5ab1f6b4aed38dfbdd098826245dfc8eb46c88e (diff) | |
download | serenity-ed49b66f2558a928e04b8f30c31f15426e894b7e.zip |
LibWeb: Implement '5.1. Headers class' from the Fetch API :^)
-rw-r--r-- | Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/Headers.cpp | 311 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/Headers.h | 77 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/Headers.idl | 13 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp | 55 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Fetch/HeadersIterator.h | 47 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Forward.h | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/idl_files.cmake | 1 |
9 files changed, 516 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h b/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h index c4e39a3433..de38e1c2a6 100644 --- a/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h +++ b/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h @@ -235,6 +235,8 @@ #include <LibWeb/Bindings/HTMLUnknownElementPrototype.h> #include <LibWeb/Bindings/HTMLVideoElementConstructor.h> #include <LibWeb/Bindings/HTMLVideoElementPrototype.h> +#include <LibWeb/Bindings/HeadersConstructor.h> +#include <LibWeb/Bindings/HeadersPrototype.h> #include <LibWeb/Bindings/HistoryConstructor.h> #include <LibWeb/Bindings/HistoryPrototype.h> #include <LibWeb/Bindings/IdleDeadlineConstructor.h> @@ -420,6 +422,7 @@ ADD_WINDOW_OBJECT_INTERFACE(ErrorEvent) \ ADD_WINDOW_OBJECT_INTERFACE(Event) \ ADD_WINDOW_OBJECT_INTERFACE(EventTarget) \ + ADD_WINDOW_OBJECT_INTERFACE(Headers) \ ADD_WINDOW_OBJECT_INTERFACE(History) \ ADD_WINDOW_OBJECT_INTERFACE(HTMLAnchorElement) \ ADD_WINDOW_OBJECT_INTERFACE(HTMLAreaElement) \ diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index e37e1ffc10..aaba562ed3 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -117,6 +117,8 @@ set(SOURCES Dump.cpp Encoding/TextDecoder.cpp Encoding/TextEncoder.cpp + Fetch/Headers.cpp + Fetch/HeadersIterator.cpp Fetch/Infrastructure/HTTP.cpp Fetch/Infrastructure/URL.cpp Fetch/Infrastructure/HTTP/Bodies.cpp diff --git a/Userland/Libraries/LibWeb/Fetch/Headers.cpp b/Userland/Libraries/LibWeb/Fetch/Headers.cpp new file mode 100644 index 0000000000..2d2bc9b16e --- /dev/null +++ b/Userland/Libraries/LibWeb/Fetch/Headers.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibWeb/Bindings/HeadersWrapper.h> +#include <LibWeb/Fetch/Headers.h> + +namespace Web::Fetch { + +// https://fetch.spec.whatwg.org/#dom-headers +DOM::ExceptionOr<NonnullRefPtr<Headers>> Headers::create(Optional<HeadersInit> const& init) +{ + // The new Headers(init) constructor steps are: + + auto headers = adopt_ref(*new Headers()); + + // 1. Set this’s guard to "none". + headers->m_guard = Guard::None; + + // 2. If init is given, then fill this with init. + if (init.has_value()) + TRY(headers->fill(*init)); + + return headers; +} + +// https://fetch.spec.whatwg.org/#dom-headers-append +DOM::ExceptionOr<void> Headers::append(String const& name_string, String const& value_string) +{ + // The append(name, value) method steps are to append (name, value) to this. + auto header = Infrastructure::Header { + .name = TRY_OR_RETURN_OOM(ByteBuffer::copy(name_string.bytes())), + .value = TRY_OR_RETURN_OOM(ByteBuffer::copy(value_string.bytes())), + }; + TRY(append(move(header))); + return {}; +} + +// https://fetch.spec.whatwg.org/#dom-headers-delete +DOM::ExceptionOr<void> Headers::delete_(String const& name_string) +{ + // The delete(name) method steps are: + auto name = name_string.bytes(); + + // 1. If name is not a header name, then throw a TypeError. + if (!Infrastructure::is_header_name(name)) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Invalid header name" }; + + // 2. If this’s guard is "immutable", then throw a TypeError. + if (m_guard == Guard::Immutable) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Headers object is immutable" }; + + // 3. Otherwise, if this’s guard is "request" and name is a forbidden header name, return. + if (m_guard == Guard::Request && Infrastructure::is_forbidden_header_name(name)) + return {}; + + // 4. Otherwise, if this’s guard is "request-no-cors", name is not a no-CORS-safelisted request-header name, and name is not a privileged no-CORS request-header name, return. + if (m_guard == Guard::RequestNoCORS && !Infrastructure::is_no_cors_safelisted_request_header_name(name) && !Infrastructure::is_privileged_no_cors_request_header_name(name)) + return {}; + + // 5. Otherwise, if this’s guard is "response" and name is a forbidden response-header name, return. + if (m_guard == Guard::Response && Infrastructure::is_forbidden_response_header_name(name)) + return {}; + + // 6. If this’s header list does not contain name, then return. + if (!m_header_list.contains(name)) + return {}; + + // 7. Delete name from this’s header list. + 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) + remove_privileged_no_cors_headers(); + + return {}; +} + +// https://fetch.spec.whatwg.org/#dom-headers-get +DOM::ExceptionOr<String> Headers::get(String const& name_string) +{ + // The get(name) method steps are: + auto name = name_string.bytes(); + + // 1. If name is not a header name, then throw a TypeError. + if (!Infrastructure::is_header_name(name)) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Invalid header name" }; + + // 2. Return the result of getting name from this’s header list. + auto byte_buffer = TRY_OR_RETURN_OOM(m_header_list.get(name)); + // FIXME: Teach WrapperGenerator about Optional<String> + return byte_buffer.has_value() ? String { byte_buffer->span() } : String {}; +} + +// https://fetch.spec.whatwg.org/#dom-headers-has +DOM::ExceptionOr<bool> Headers::has(String const& name_string) +{ + // The has(name) method steps are: + auto name = name_string.bytes(); + + // 1. If name is not a header name, then throw a TypeError. + if (!Infrastructure::is_header_name(name)) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Invalid header name" }; + + // 2. Return true if this’s header list contains name; otherwise false. + return m_header_list.contains(name); +} + +// https://fetch.spec.whatwg.org/#dom-headers-set +DOM::ExceptionOr<void> Headers::set(String const& name_string, String const& value_string) +{ + // The set(name, value) method steps are: + auto name = name_string.bytes(); + auto value = value_string.bytes(); + + // 1. Normalize value. + auto normalized_value = TRY_OR_RETURN_OOM(Infrastructure::normalize_header_value(value)); + + auto header = Infrastructure::Header { + .name = TRY_OR_RETURN_OOM(ByteBuffer::copy(name)), + .value = move(normalized_value), + }; + + // 2. If name is not a header name or value is not a header value, then throw a TypeError. + if (!Infrastructure::is_header_name(name)) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Invalid header name" }; + if (!Infrastructure::is_header_value(value)) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Invalid header value" }; + + // 3. If this’s guard is "immutable", then throw a TypeError. + if (m_guard == Guard::Immutable) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Headers object is immutable" }; + + // 4. Otherwise, if this’s guard is "request" and name is a forbidden header name, return. + if (m_guard == Guard::Request && Infrastructure::is_forbidden_header_name(name)) + return {}; + + // 5. Otherwise, if this’s guard is "request-no-cors" and name/value is not a no-CORS-safelisted request-header, return. + if (m_guard == Guard::RequestNoCORS && !Infrastructure::is_no_cors_safelisted_request_header(header)) + return {}; + + // 6. Otherwise, if this’s guard is "response" and name is a forbidden response-header name, return. + if (m_guard == Guard::Response && Infrastructure::is_forbidden_response_header_name(name)) + return {}; + + // 7. Set (name, value) in this’s header list. + TRY_OR_RETURN_OOM(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) + remove_privileged_no_cors_headers(); + + return {}; +} + +// https://webidl.spec.whatwg.org/#es-iterable, Step 4 +JS::ThrowCompletionOr<void> Headers::for_each(ForEachCallback callback) +{ + auto& global_object = wrapper()->global_object(); + auto& vm = global_object.vm(); + + // 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<Vector<Fetch::Infrastructure::Header>> { + auto headers_or_error = m_header_list.sort_and_combine(); + if (headers_or_error.is_error()) + return vm.throw_completion<JS::InternalError>(global_object, JS::ErrorType::NotEnoughMemoryToAllocate); + return headers_or_error.release_value(); + }; + + // 1-5. Are done in the generated wrapper code. + + // 6. Let pairs be idlObject’s list of value pairs to iterate over. + auto pairs = TRY(value_pairs_to_iterate_over()); + + // 7. Let i be 0. + size_t i = 0; + + // 8. While i < pairs’s size: + while (i < pairs.size()) { + // 1. Let pair be pairs[i]. + auto const& pair = pairs[i]; + + // 2. Invoke idlCallback with « pair’s value, pair’s key, idlObject » and with thisArg as the callback this value. + TRY(callback(StringView { pair.name }, StringView { pair.value })); + + // 3. Set pairs to idlObject’s current list of value pairs to iterate over. (It might have changed.) + pairs = TRY(value_pairs_to_iterate_over()); + + // 4. Set i to i + 1. + ++i; + } + + return {}; +} + +// https://fetch.spec.whatwg.org/#concept-headers-append +DOM::ExceptionOr<void> Headers::append(Infrastructure::Header header) +{ + // To append a header (name, value) to a Headers object headers, run these steps: + auto& [name, value] = header; + + // 1. Normalize value. + value = TRY_OR_RETURN_OOM(Infrastructure::normalize_header_value(value)); + + // 2. If name is not a header name or value is not a header value, then throw a TypeError. + if (!Infrastructure::is_header_name(name)) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Invalid header name" }; + if (!Infrastructure::is_header_value(value)) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Invalid header value" }; + + // 3. If headers’s guard is "immutable", then throw a TypeError. + if (m_guard == Guard::Immutable) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Headers object is immutable" }; + + // 4. Otherwise, if headers’s guard is "request" and name is a forbidden header name, return. + if (m_guard == Guard::Request && Infrastructure::is_forbidden_header_name(name)) + return {}; + + // 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(m_header_list.get(name)); + + // 2. If temporaryValue is null, then set temporaryValue to value. + if (!temporary_value.has_value()) { + temporary_value = TRY_OR_RETURN_OOM(ByteBuffer::copy(value)); + } + // 3. Otherwise, set temporaryValue to temporaryValue, followed by 0x2C 0x20, followed by value. + else { + TRY_OR_RETURN_OOM(temporary_value->try_append(0x2c)); + TRY_OR_RETURN_OOM(temporary_value->try_append(0x20)); + TRY_OR_RETURN_OOM(temporary_value->try_append(value)); + } + + auto temporary_header = Infrastructure::Header { + .name = TRY_OR_RETURN_OOM(ByteBuffer::copy(name)), + .value = temporary_value.release_value(), + }; + + // 4. If name/temporaryValue is not a no-CORS-safelisted request-header, then return. + if (!Infrastructure::is_no_cors_safelisted_request_header(temporary_header)) + return {}; + } + + // 6. Otherwise, if headers’s guard is "response" and name is a forbidden response-header name, return. + 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(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) + remove_privileged_no_cors_headers(); + + return {}; +} + +// https://fetch.spec.whatwg.org/#concept-headers-fill +DOM::ExceptionOr<void> Headers::fill(HeadersInit const& object) +{ + // To fill a Headers object headers with a given object object, run these steps: + return object.visit( + // 1. If object is a sequence, then for each header in object: + [this](Vector<Vector<String>> const& object) -> DOM::ExceptionOr<void> { + for (auto const& entry : object) { + // 1. If header does not contain exactly two items, then throw a TypeError. + if (entry.size() != 2) + return DOM::SimpleException { DOM::SimpleExceptionType::TypeError, "Array must contain header key/value pair" }; + + // 2. Append (header’s first item, header’s second item) to headers. + auto header = Fetch::Infrastructure::Header { + .name = TRY_OR_RETURN_OOM(ByteBuffer::copy(entry[0].bytes())), + .value = TRY_OR_RETURN_OOM(ByteBuffer::copy(entry[0].bytes())), + }; + TRY(append(move(header))); + } + return {}; + }, + // 2. Otherwise, object is a record, then for each key → value in object, append (key, value) to headers. + [this](OrderedHashMap<String, String> const& object) -> DOM::ExceptionOr<void> { + for (auto const& entry : object) { + auto header = Fetch::Infrastructure::Header { + .name = TRY_OR_RETURN_OOM(ByteBuffer::copy(entry.key.bytes())), + .value = TRY_OR_RETURN_OOM(ByteBuffer::copy(entry.value.bytes())), + }; + TRY(append(move(header))); + } + return {}; + }); +} + +// https://fetch.spec.whatwg.org/#concept-headers-remove-privileged-no-cors-request-headers +void Headers::remove_privileged_no_cors_headers() +{ + // To remove privileged no-CORS request headers from a Headers object (headers), run these steps: + + static constexpr Array privileged_no_cors_request_header_names = { + "Range"sv, + }; + + // 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()); + } +} + +} diff --git a/Userland/Libraries/LibWeb/Fetch/Headers.h b/Userland/Libraries/LibWeb/Fetch/Headers.h new file mode 100644 index 0000000000..ef5a7d1fc5 --- /dev/null +++ b/Userland/Libraries/LibWeb/Fetch/Headers.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/HashMap.h> +#include <AK/NonnullRefPtr.h> +#include <AK/String.h> +#include <AK/Variant.h> +#include <AK/Vector.h> +#include <LibWeb/Bindings/Wrappable.h> +#include <LibWeb/DOM/ExceptionOr.h> +#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h> + +namespace Web::Fetch { + +using HeadersInit = Variant<Vector<Vector<String>>, OrderedHashMap<String, String>>; + +// https://fetch.spec.whatwg.org/#headers-class +class Headers + : public Bindings::Wrappable + , public RefCounted<Headers> { +public: + using WrapperType = Bindings::HeadersWrapper; + + enum class Guard { + Immutable, + Request, + RequestNoCORS, + Response, + None, + }; + + static DOM::ExceptionOr<NonnullRefPtr<Headers>> create(Optional<HeadersInit> const&); + + static DOM::ExceptionOr<NonnullRefPtr<Headers>> create_with_global_object(Bindings::WindowObject&, Optional<HeadersInit> const& init) + { + return create(init); + } + + DOM::ExceptionOr<void> append(Infrastructure::Header); + DOM::ExceptionOr<void> append(String const& name, String const& value); + DOM::ExceptionOr<void> delete_(String const& name); + DOM::ExceptionOr<String> get(String const& name); + DOM::ExceptionOr<bool> has(String const& name); + DOM::ExceptionOr<void> set(String const& name, String const& value); + + using ForEachCallback = Function<JS::ThrowCompletionOr<void>(String const&, String const&)>; + JS::ThrowCompletionOr<void> for_each(ForEachCallback); + +private: + friend class HeadersIterator; + + Headers() = default; + + DOM::ExceptionOr<void> fill(HeadersInit const&); + 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. + 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". + Guard m_guard { Guard::None }; +}; + +} + +namespace Web::Bindings { + +HeadersWrapper* wrap(JS::GlobalObject&, Fetch::Headers&); + +} diff --git a/Userland/Libraries/LibWeb/Fetch/Headers.idl b/Userland/Libraries/LibWeb/Fetch/Headers.idl new file mode 100644 index 0000000000..f2dbd9e4c0 --- /dev/null +++ b/Userland/Libraries/LibWeb/Fetch/Headers.idl @@ -0,0 +1,13 @@ +typedef (sequence<sequence<ByteString>> or record<ByteString, ByteString>) HeadersInit; + +[Exposed=(Window,Worker)] +interface Headers { + constructor(optional HeadersInit init); + + undefined append(ByteString name, ByteString value); + undefined delete(ByteString name); + ByteString? get(ByteString name); + boolean has(ByteString name); + undefined set(ByteString name, ByteString value); + iterable<ByteString, ByteString>; +}; diff --git a/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp b/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp new file mode 100644 index 0000000000..f3163042d2 --- /dev/null +++ b/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibJS/Runtime/Array.h> +#include <LibJS/Runtime/IteratorOperations.h> +#include <LibWeb/Bindings/HeadersIteratorWrapper.h> +#include <LibWeb/Bindings/Wrapper.h> +#include <LibWeb/Fetch/HeadersIterator.h> + +namespace Web::Fetch { + +// https://webidl.spec.whatwg.org/#es-iterable, Step 2 +JS::ThrowCompletionOr<JS::Object*> HeadersIterator::next() +{ + auto& global_object = wrapper()->global_object(); + auto& vm = global_object.vm(); + + // 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<Vector<Fetch::Infrastructure::Header>> { + auto headers_or_error = m_headers.m_header_list.sort_and_combine(); + if (headers_or_error.is_error()) + return vm.throw_completion<JS::InternalError>(global_object, JS::ErrorType::NotEnoughMemoryToAllocate); + return headers_or_error.release_value(); + }; + + auto pairs = TRY(value_pairs_to_iterate_over()); + + if (m_index >= pairs.size()) + return create_iterator_result_object(global_object, JS::js_undefined(), true); + + auto const& pair = pairs[m_index++]; + + switch (m_iteration_kind) { + case JS::Object::PropertyKind::Key: + return create_iterator_result_object(global_object, JS::js_string(vm, StringView { pair.name }), false); + case JS::Object::PropertyKind::Value: + return create_iterator_result_object(global_object, JS::js_string(vm, StringView { pair.value }), false); + case JS::Object::PropertyKind::KeyAndValue: { + auto* array = JS::Array::create_from(global_object, { JS::js_string(vm, StringView { pair.name }), JS::js_string(vm, StringView { pair.value }) }); + return create_iterator_result_object(global_object, array, false); + } + default: + VERIFY_NOT_REACHED(); + } +} + +void HeadersIterator::visit_edges(JS::Cell::Visitor& visitor) +{ + visitor.visit(m_headers.wrapper()); +} + +} diff --git a/Userland/Libraries/LibWeb/Fetch/HeadersIterator.h b/Userland/Libraries/LibWeb/Fetch/HeadersIterator.h new file mode 100644 index 0000000000..a678abacb0 --- /dev/null +++ b/Userland/Libraries/LibWeb/Fetch/HeadersIterator.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibWeb/Bindings/Wrappable.h> +#include <LibWeb/Fetch/Headers.h> + +namespace Web::Fetch { + +class HeadersIterator + : public Bindings::Wrappable + , public RefCounted<HeadersIterator> { +public: + using WrapperType = Bindings::HeadersIteratorWrapper; + + static NonnullRefPtr<HeadersIterator> create(Headers const& headers, JS::Object::PropertyKind iteration_kind) + { + return adopt_ref(*new HeadersIterator(headers, iteration_kind)); + } + + JS::ThrowCompletionOr<JS::Object*> next(); + + void visit_edges(JS::Cell::Visitor&); + +private: + HeadersIterator(Headers const& headers, JS::Object::PropertyKind iteration_kind) + : m_headers(headers) + , m_iteration_kind(iteration_kind) + { + } + + Headers const& m_headers; + JS::Object::PropertyKind m_iteration_kind; + size_t m_index { 0 }; +}; + +} + +namespace Web::Bindings { + +HeadersIteratorWrapper* wrap(JS::GlobalObject&, Fetch::HeadersIterator&); + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 219a57d8ac..3decec6049 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -170,6 +170,11 @@ namespace Web::Encoding { class TextEncoder; } +namespace Web::Fetch { +class Headers; +class HeadersIterator; +} + namespace Web::Fetch::Infrastructure { class Body; struct Header; @@ -470,6 +475,8 @@ class EventListenerWrapper; class EventTargetWrapper; class EventWrapper; class FocusEventWrapper; +class HeadersWrapper; +class HeadersIteratorWrapper; class HistoryWrapper; class HTMLAnchorElementWrapper; class HTMLAreaElementWrapper; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index 3de3b944e4..8b0117ef5f 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -53,6 +53,7 @@ libweb_js_wrapper(DOM/TreeWalker) libweb_js_wrapper(DOMParsing/XMLSerializer) libweb_js_wrapper(Encoding/TextDecoder) libweb_js_wrapper(Encoding/TextEncoder) +libweb_js_wrapper(Fetch/Headers ITERABLE) libweb_js_wrapper(FileAPI/Blob) libweb_js_wrapper(Geometry/DOMPoint) libweb_js_wrapper(Geometry/DOMPointReadOnly) |