Browse Source

LibWeb: Add support for DOM::Document to XHR::send()

This patch adds support for posting a DOM::Document using XHR::send().
Kenneth Myhra 2 years ago
parent
commit
7831e62

+ 3 - 0
Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp

@@ -130,6 +130,9 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface)
     if (type.name() == "BufferSource")
         return { .name = "JS::Handle<JS::Object>", .sequence_storage_type = SequenceStorageType::MarkedVector };
 
+    if (type.name() == "XMLHttpRequestBodyInit")
+        return { .name = "Fetch::XMLHttpRequestBodyInit", .sequence_storage_type = SequenceStorageType::MarkedVector };
+
     if (type.name() == "sequence") {
         auto& parameterized_type = verify_cast<ParameterizedType>(type);
         auto& sequence_type = parameterized_type.parameters().first();

+ 21 - 8
Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp

@@ -396,7 +396,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::open(String const& method_string, Stri
 }
 
 // https://xhr.spec.whatwg.org/#dom-xmlhttprequest-send
-WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<Fetch::XMLHttpRequestBodyInit> body)
+WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<Variant<JS::Handle<DOM::Document>, Fetch::XMLHttpRequestBodyInit>> body)
 {
     auto& vm = this->vm();
     auto& realm = *vm.current_realm();
@@ -411,8 +411,15 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<Fetch::XMLHttpRequestBod
     if (m_method.is_one_of("GET"sv, "HEAD"sv))
         body = {};
 
-    auto body_with_type = body.has_value() ? TRY(Fetch::extract_body(realm, body.value())) : Optional<Fetch::Infrastructure::BodyWithType> {};
-
+    Optional<Fetch::Infrastructure::BodyWithType> body_with_type {};
+    Optional<ByteBuffer> serialized_document {};
+    if (body.has_value()) {
+        if (body->has<JS::Handle<DOM::Document>>()) {
+            serialized_document = body->get<JS::Handle<DOM::Document>>().cell()->serialize_fragment().to_byte_buffer();
+        } else {
+            body_with_type = TRY(Fetch::extract_body(realm, body.value().get<Fetch::XMLHttpRequestBodyInit>()));
+        }
+    }
     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);
 
@@ -432,7 +439,9 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<Fetch::XMLHttpRequestBod
 
     auto request = LoadRequest::create_for_url_on_page(request_url, m_window->page());
     request.set_method(m_method);
-    if (body_with_type.has_value()) {
+    if (serialized_document.has_value()) {
+        request.set_body(serialized_document.value());
+    } else if (body_with_type.has_value()) {
         TRY(body_with_type->body.source().visit(
             [&](ByteBuffer const& buffer) -> WebIDL::ExceptionOr<void> {
                 request.set_body(buffer);
@@ -446,10 +455,14 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<Fetch::XMLHttpRequestBod
             [](auto&) -> WebIDL::ExceptionOr<void> {
                 return {};
             }));
-        if (body_with_type->type.has_value()) {
-            // If type is non-null and this’s headers’s header list does not contain `Content-Type`, then append (`Content-Type`, type) to this’s headers.
-            if (!m_request_headers.contains("Content-Type"sv))
-                request.set_header("Content-Type", String { body_with_type->type->span() });
+    }
+
+    // If type is non-null and this’s headers’s header list does not contain `Content-Type`, then append (`Content-Type`, type) to this’s headers.
+    if (!m_request_headers.contains("Content-Type"sv)) {
+        if (body_with_type.has_value() && body_with_type->type.has_value()) {
+            request.set_header("Content-Type", String { body_with_type->type->span() });
+        } else if (body->has<JS::Handle<DOM::Document>>()) {
+            request.set_header("Content-Type", "text/html;charset=UTF-8");
         }
     }
     for (auto& it : m_request_headers)

+ 1 - 1
Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h

@@ -47,7 +47,7 @@ public:
 
     WebIDL::ExceptionOr<void> open(String const& method, String const& url);
     WebIDL::ExceptionOr<void> open(String const& method, String const& url, bool async, String const& username = {}, String const& password = {});
-    WebIDL::ExceptionOr<void> send(Optional<Fetch::XMLHttpRequestBodyInit> body);
+    WebIDL::ExceptionOr<void> send(Optional<Variant<JS::Handle<DOM::Document>, Fetch::XMLHttpRequestBodyInit>> body = {});
 
     WebIDL::ExceptionOr<void> set_request_header(String const& header, String const& value);
     void set_response_type(Bindings::XMLHttpRequestResponseType type) { m_response_type = type; }

+ 2 - 1
Userland/Libraries/LibWeb/XHR/XMLHttpRequest.idl

@@ -1,3 +1,4 @@
+#import <DOM/Document.idl>
 #import <DOM/EventHandler.idl>
 #import <Fetch/BodyInit.idl>
 #import <XHR/XMLHttpRequestEventTarget.idl>
@@ -33,7 +34,7 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
     undefined open(DOMString method, DOMString url);
     undefined open(ByteString method, USVString url, boolean async, optional USVString? username = {}, optional USVString? password = {});
     undefined setRequestHeader(DOMString name, DOMString value);
-    undefined send(optional XMLHttpRequestBodyInit? body = null);
+    undefined send(optional (Document or XMLHttpRequestBodyInit)? body = null);
 
     ByteString? getResponseHeader(ByteString name);
     ByteString getAllResponseHeaders();