/* * Copyright (c) 2020-2021, Andreas Kling * Copyright (c) 2022, Kenneth Myhra * Copyright (c) 2023, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::XHR { // https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit using DocumentOrXMLHttpRequestBodyInit = Variant, GC::Root, GC::Root, GC::Root, GC::Root, AK::String>; class XMLHttpRequest final : public XMLHttpRequestEventTarget { WEB_PLATFORM_OBJECT(XMLHttpRequest, XMLHttpRequestEventTarget); GC_DECLARE_ALLOCATOR(XMLHttpRequest); public: enum class State : u16 { Unsent = 0, Opened = 1, HeadersReceived = 2, Loading = 3, Done = 4, }; static WebIDL::ExceptionOr> construct_impl(JS::Realm&); virtual ~XMLHttpRequest() override; State ready_state() const { return m_state; } Fetch::Infrastructure::Status status() const; WebIDL::ExceptionOr status_text() const; WebIDL::ExceptionOr response_text() const; WebIDL::ExceptionOr> response_xml(); WebIDL::ExceptionOr response(); Bindings::XMLHttpRequestResponseType response_type() const { return m_response_type; } String response_url(); WebIDL::ExceptionOr open(String const& method, String const& url); WebIDL::ExceptionOr open(String const& method, String const& url, bool async, Optional const& username = Optional {}, Optional const& password = Optional {}); WebIDL::ExceptionOr send(Optional body); WebIDL::ExceptionOr set_request_header(String const& header, String const& value); WebIDL::ExceptionOr set_response_type(Bindings::XMLHttpRequestResponseType); Optional get_response_header(String const& name) const; String get_all_response_headers() const; WebIDL::CallbackType* onreadystatechange(); void set_onreadystatechange(WebIDL::CallbackType*); WebIDL::ExceptionOr override_mime_type(String const& mime); u32 timeout() const; WebIDL::ExceptionOr set_timeout(u32 timeout); bool with_credentials() const; WebIDL::ExceptionOr set_with_credentials(bool); void abort(); GC::Ref upload() const; private: virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; virtual bool must_survive_garbage_collection() const override; [[nodiscard]] MimeSniff::MimeType get_response_mime_type() const; [[nodiscard]] Optional get_final_encoding() const; [[nodiscard]] MimeSniff::MimeType get_final_mime_type() const; String get_text_response() const; void set_document_response(); WebIDL::ExceptionOr handle_response_end_of_body(); WebIDL::ExceptionOr handle_errors(); JS::ThrowCompletionOr request_error_steps(FlyString const& event_name, GC::Ptr exception = nullptr); XMLHttpRequest(JS::Realm&, XMLHttpRequestUpload&, Fetch::Infrastructure::HeaderList&, Fetch::Infrastructure::Response&, Fetch::Infrastructure::FetchController&); // https://xhr.spec.whatwg.org/#upload-object // upload object // An XMLHttpRequestUpload object. GC::Ref m_upload_object; // https://xhr.spec.whatwg.org/#concept-xmlhttprequest-state // state // One of unsent, opened, headers received, loading, and done; initially unsent. State m_state { State::Unsent }; // https://xhr.spec.whatwg.org/#send-flag // send() flag // A flag, initially unset. bool m_send { false }; // https://xhr.spec.whatwg.org/#timeout // timeout // An unsigned integer, initially 0. u32 m_timeout { 0 }; // https://xhr.spec.whatwg.org/#cross-origin-credentials // cross-origin credentials // A boolean, initially false. bool m_cross_origin_credentials { false }; // https://xhr.spec.whatwg.org/#request-method // request method // A method. ByteString m_request_method; // https://xhr.spec.whatwg.org/#request-url // request URL // A URL. URL::URL m_request_url; // https://xhr.spec.whatwg.org/#author-request-headers // author request headers // A header list, initially empty. GC::Ref m_author_request_headers; // https://xhr.spec.whatwg.org/#request-body // request body // Initially null. GC::Ptr m_request_body; // https://xhr.spec.whatwg.org/#synchronous-flag // synchronous flag // A flag, initially unset. bool m_synchronous { false }; // https://xhr.spec.whatwg.org/#upload-complete-flag // upload complete flag // A flag, initially unset. bool m_upload_complete { false }; // https://xhr.spec.whatwg.org/#upload-listener-flag // upload listener flag // A flag, initially unset. bool m_upload_listener { false }; // https://xhr.spec.whatwg.org/#timed-out-flag // timed out flag // A flag, initially unset. bool m_timed_out { false }; // https://xhr.spec.whatwg.org/#response // response // A response, initially a network error. GC::Ref m_response; // https://xhr.spec.whatwg.org/#received-bytes // received bytes // A byte sequence, initially the empty byte sequence. ByteBuffer m_received_bytes; // https://xhr.spec.whatwg.org/#response-type // response type // One of the empty string, "arraybuffer", "blob", "document", "json", and "text"; initially the empty string. Bindings::XMLHttpRequestResponseType m_response_type; enum class Failure { /// ???? }; // https://xhr.spec.whatwg.org/#response-object // response object // An object, failure, or null, initially null. // NOTE: This needs to be a JS::Value as the JSON response might not actually be an object. Variant, Failure, Empty> m_response_object; // https://xhr.spec.whatwg.org/#xmlhttprequest-fetch-controller // fetch controller // A fetch controller, initially a new fetch controller. // NOTE: The send() method sets it to a useful fetch controller, but for simplicity it always holds a fetch controller. GC::Ref m_fetch_controller; // https://xhr.spec.whatwg.org/#override-mime-type // override MIME type // A MIME type or null, initially null. // NOTE: Can get a value when overrideMimeType() is invoked. Optional m_override_mime_type; // Non-standard, see async path in `send()` u64 m_request_body_transmitted { 0 }; }; }