diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index d8356938fa..71c94e0fdc 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -123,6 +123,7 @@ set(SOURCES Dump.cpp Encoding/TextDecoder.cpp Encoding/TextEncoder.cpp + Fetch/BodyInit.cpp Fetch/Headers.cpp Fetch/HeadersIterator.cpp Fetch/Infrastructure/HTTP.cpp diff --git a/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp b/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp new file mode 100644 index 0000000000..20eda60e52 --- /dev/null +++ b/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022, Linus Groh + * Copyright (c) 2022, Kenneth Myhra + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace Web::Fetch { + +// https://fetch.spec.whatwg.org/#concept-bodyinit-extract +// FIXME: The parameter 'body_init' should be 'typedef (ReadableStream or XMLHttpRequestBodyInit) BodyInit'. For now we just let it be 'XMLHttpRequestBodyInit'. +ErrorOr extract_body(JS::Realm& realm, XMLHttpRequestBodyInit const& body_init) +{ + auto& window = verify_cast(realm.global_object()); + + // FIXME: 1. Let stream be object if object is a ReadableStream object. Otherwise, let stream be a new ReadableStream, and set up stream. + auto* stream = realm.heap().allocate(realm, window); + // FIXME: 2. Let action be null. + // 3. Let source be null. + Infrastructure::Body::SourceType source {}; + // 4. Let length be null. + Optional length {}; + // 5. Let type be null. + Optional type {}; + + // 6. Switch on object. + // FIXME: Still need to support BufferSource and FormData + TRY(body_init.visit( + [&](JS::Handle const& blob) -> ErrorOr { + // FIXME: Set action to this step: read object. + // Set source to object. + source = blob; + // Set length to object’s size. + length = blob->size(); + // If object’s type attribute is not the empty byte sequence, set type to its value. + if (!blob->type().is_empty()) + type = blob->type().to_byte_buffer(); + return {}; + }, + [&](JS::Handle const& buffer_source) -> ErrorOr { + // Set source to a copy of the bytes held by object. + source = TRY(Bindings::IDL::get_buffer_source_copy(*buffer_source.cell())); + return {}; + }, + [&](JS::Handle const& url_search_params) -> ErrorOr { + // Set source to the result of running the application/x-www-form-urlencoded serializer with object’s list. + source = url_search_params->to_string().to_byte_buffer(); + // Set type to `application/x-www-form-urlencoded;charset=UTF-8`. + type = TRY(ByteBuffer::copy("application/x-www-form-urlencoded;charset=UTF-8"sv.bytes())); + return {}; + }, + [&](String const& scalar_value_string) -> ErrorOr { + // NOTE: AK::String is always UTF-8. + // Set source to the UTF-8 encoding of object. + source = scalar_value_string.to_byte_buffer(); + // Set type to `text/plain;charset=UTF-8`. + type = TRY(ByteBuffer::copy("text/plain;charset=UTF-8"sv.bytes())); + return {}; + })); + + // FIXME: 7. If source is a byte sequence, then set action to a step that returns source and length to source’s length. + // FIXME: 8. If action is non-null, then run these steps in in parallel: + + // 9. Let body be a body whose stream is stream, source is source, and length is length. + auto body = Infrastructure::Body { JS::make_handle(stream), move(source), move(length) }; + // 10. Return (body, type). + return Infrastructure::BodyWithType { .body = move(body), .type = move(type) }; +} + +} diff --git a/Userland/Libraries/LibWeb/Fetch/BodyInit.h b/Userland/Libraries/LibWeb/Fetch/BodyInit.h index e8ce881f50..24dc2f244c 100644 --- a/Userland/Libraries/LibWeb/Fetch/BodyInit.h +++ b/Userland/Libraries/LibWeb/Fetch/BodyInit.h @@ -16,4 +16,6 @@ namespace Web::Fetch { // https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit using XMLHttpRequestBodyInit = Variant, JS::Handle, JS::Handle, String>; +ErrorOr extract_body(JS::Realm&, XMLHttpRequestBodyInit const&); + } diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 94fde4f6cd..2ad2adad09 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -189,6 +189,7 @@ class HeadersIterator; namespace Web::Fetch::Infrastructure { class Body; +struct BodyWithType; struct Header; class HeaderList; class Request; diff --git a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp index d67b89fb5c..31cd8da00e 100644 --- a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp +++ b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -24,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -268,66 +268,6 @@ Optional XMLHttpRequest::get_final_encoding() const return encoding; } -// https://fetch.spec.whatwg.org/#concept-bodyinit-extract -// FIXME: The parameter 'body_init' should be 'typedef (ReadableStream or XMLHttpRequestBodyInit) BodyInit'. For now we just let it be 'XMLHttpRequestBodyInit'. -static ErrorOr extract_body(JS::Realm& realm, Fetch::XMLHttpRequestBodyInit const& body_init) -{ - auto& window = verify_cast(realm.global_object()); - - // FIXME: 1. Let stream be object if object is a ReadableStream object. Otherwise, let stream be a new ReadableStream, and set up stream. - auto* stream = realm.heap().allocate(realm, window); - // FIXME: 2. Let action be null. - // 3. Let source be null. - Fetch::Infrastructure::Body::SourceType source {}; - // 4. Let length be null. - Optional length {}; - // 5. Let type be null. - Optional type {}; - - // 6. Switch on object. - // FIXME: Still need to support BufferSource and FormData - TRY(body_init.visit( - [&](JS::Handle const& blob) -> ErrorOr { - // FIXME: Set action to this step: read object. - // Set source to object. - source = blob; - // Set length to object’s size. - length = blob->size(); - // If object’s type attribute is not the empty byte sequence, set type to its value. - if (!blob->type().is_empty()) - type = blob->type().to_byte_buffer(); - return {}; - }, - [&](JS::Handle const& buffer_source) -> ErrorOr { - // Set source to a copy of the bytes held by object. - source = TRY(Bindings::IDL::get_buffer_source_copy(*buffer_source.cell())); - return {}; - }, - [&](JS::Handle const& url_search_params) -> ErrorOr { - // Set source to the result of running the application/x-www-form-urlencoded serializer with object’s list. - source = url_search_params->to_string().to_byte_buffer(); - // Set type to `application/x-www-form-urlencoded;charset=UTF-8`. - type = TRY(ByteBuffer::copy("application/x-www-form-urlencoded;charset=UTF-8"sv.bytes())); - return {}; - }, - [&](String const& scalar_value_string) -> ErrorOr { - // NOTE: AK::String is always UTF-8. - // Set source to the UTF-8 encoding of object. - source = scalar_value_string.to_byte_buffer(); - // Set type to `text/plain;charset=UTF-8`. - type = TRY(ByteBuffer::copy("text/plain;charset=UTF-8"sv.bytes())); - return {}; - })); - - // FIXME: 7. If source is a byte sequence, then set action to a step that returns source and length to source’s length. - // FIXME: 8. If action is non-null, then run these steps in in parallel: - - // 9. Let body be a body whose stream is stream, source is source, and length is length. - auto body = Fetch::Infrastructure::Body { JS::make_handle(stream), move(source), move(length) }; - // 10. Return (body, type). - return Fetch::Infrastructure::BodyWithType { .body = move(body), .type = move(type) }; -} - // https://xhr.spec.whatwg.org/#dom-xmlhttprequest-setrequestheader DOM::ExceptionOr XMLHttpRequest::set_request_header(String const& name_string, String const& value_string) { @@ -470,7 +410,7 @@ DOM::ExceptionOr XMLHttpRequest::send(Optional {}; + auto body_with_type = body.has_value() ? TRY_OR_RETURN_OOM(global_object(), Fetch::extract_body(realm, body.value())) : Optional {}; AK::URL request_url = m_window->associated_document().parse_url(m_url.to_string()); dbgln("XHR send from {} to {}", m_window->associated_document().url(), request_url);