/src/serenity/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2022, Kenneth Myhra <kennethmyhra@serenityos.org> |
4 | | * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> |
5 | | * |
6 | | * SPDX-License-Identifier: BSD-2-Clause |
7 | | */ |
8 | | |
9 | | #pragma once |
10 | | |
11 | | #include <AK/ByteBuffer.h> |
12 | | #include <AK/RefCounted.h> |
13 | | #include <AK/Weakable.h> |
14 | | #include <LibURL/URL.h> |
15 | | #include <LibWeb/DOM/EventTarget.h> |
16 | | #include <LibWeb/DOMURL/URLSearchParams.h> |
17 | | #include <LibWeb/Fetch/BodyInit.h> |
18 | | #include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h> |
19 | | #include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h> |
20 | | #include <LibWeb/Fetch/Infrastructure/HTTP/Statuses.h> |
21 | | #include <LibWeb/HTML/Window.h> |
22 | | #include <LibWeb/MimeSniff/MimeType.h> |
23 | | #include <LibWeb/WebIDL/ExceptionOr.h> |
24 | | #include <LibWeb/XHR/XMLHttpRequestEventTarget.h> |
25 | | |
26 | | namespace Web::XHR { |
27 | | |
28 | | // https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit |
29 | | using DocumentOrXMLHttpRequestBodyInit = Variant<JS::Handle<Web::DOM::Document>, JS::Handle<Web::FileAPI::Blob>, JS::Handle<WebIDL::BufferSource>, JS::Handle<XHR::FormData>, JS::Handle<Web::DOMURL::URLSearchParams>, AK::String>; |
30 | | |
31 | | class XMLHttpRequest final : public XMLHttpRequestEventTarget { |
32 | | WEB_PLATFORM_OBJECT(XMLHttpRequest, XMLHttpRequestEventTarget); |
33 | | JS_DECLARE_ALLOCATOR(XMLHttpRequest); |
34 | | |
35 | | public: |
36 | | enum class State : u16 { |
37 | | Unsent = 0, |
38 | | Opened = 1, |
39 | | HeadersReceived = 2, |
40 | | Loading = 3, |
41 | | Done = 4, |
42 | | }; |
43 | | |
44 | | static WebIDL::ExceptionOr<JS::NonnullGCPtr<XMLHttpRequest>> construct_impl(JS::Realm&); |
45 | | |
46 | | virtual ~XMLHttpRequest() override; |
47 | | |
48 | 0 | State ready_state() const { return m_state; } |
49 | | Fetch::Infrastructure::Status status() const; |
50 | | WebIDL::ExceptionOr<String> status_text() const; |
51 | | WebIDL::ExceptionOr<String> response_text() const; |
52 | | WebIDL::ExceptionOr<JS::GCPtr<DOM::Document>> response_xml(); |
53 | | WebIDL::ExceptionOr<JS::Value> response(); |
54 | 0 | Bindings::XMLHttpRequestResponseType response_type() const { return m_response_type; } |
55 | | String response_url(); |
56 | | |
57 | | WebIDL::ExceptionOr<void> open(String const& method, String const& url); |
58 | | WebIDL::ExceptionOr<void> open(String const& method, String const& url, bool async, Optional<String> const& username = Optional<String> {}, Optional<String> const& password = Optional<String> {}); |
59 | | WebIDL::ExceptionOr<void> send(Optional<DocumentOrXMLHttpRequestBodyInit> body); |
60 | | |
61 | | WebIDL::ExceptionOr<void> set_request_header(String const& header, String const& value); |
62 | | WebIDL::ExceptionOr<void> set_response_type(Bindings::XMLHttpRequestResponseType); |
63 | | |
64 | | WebIDL::ExceptionOr<Optional<String>> get_response_header(String const& name) const; |
65 | | WebIDL::ExceptionOr<String> get_all_response_headers() const; |
66 | | |
67 | | WebIDL::CallbackType* onreadystatechange(); |
68 | | void set_onreadystatechange(WebIDL::CallbackType*); |
69 | | |
70 | | WebIDL::ExceptionOr<void> override_mime_type(String const& mime); |
71 | | |
72 | | u32 timeout() const; |
73 | | WebIDL::ExceptionOr<void> set_timeout(u32 timeout); |
74 | | |
75 | | bool with_credentials() const; |
76 | | WebIDL::ExceptionOr<void> set_with_credentials(bool); |
77 | | |
78 | | void abort(); |
79 | | |
80 | | JS::NonnullGCPtr<XMLHttpRequestUpload> upload() const; |
81 | | |
82 | | private: |
83 | | virtual void initialize(JS::Realm&) override; |
84 | | virtual void visit_edges(Cell::Visitor&) override; |
85 | | virtual bool must_survive_garbage_collection() const override; |
86 | | |
87 | | [[nodiscard]] MimeSniff::MimeType get_response_mime_type() const; |
88 | | [[nodiscard]] Optional<StringView> get_final_encoding() const; |
89 | | [[nodiscard]] MimeSniff::MimeType get_final_mime_type() const; |
90 | | |
91 | | String get_text_response() const; |
92 | | void set_document_response(); |
93 | | |
94 | | WebIDL::ExceptionOr<void> handle_response_end_of_body(); |
95 | | WebIDL::ExceptionOr<void> handle_errors(); |
96 | | JS::ThrowCompletionOr<void> request_error_steps(FlyString const& event_name, JS::GCPtr<WebIDL::DOMException> exception = nullptr); |
97 | | |
98 | | XMLHttpRequest(JS::Realm&, XMLHttpRequestUpload&, Fetch::Infrastructure::HeaderList&, Fetch::Infrastructure::Response&, Fetch::Infrastructure::FetchController&); |
99 | | |
100 | | // https://xhr.spec.whatwg.org/#upload-object |
101 | | // upload object |
102 | | // An XMLHttpRequestUpload object. |
103 | | JS::NonnullGCPtr<XMLHttpRequestUpload> m_upload_object; |
104 | | |
105 | | // https://xhr.spec.whatwg.org/#concept-xmlhttprequest-state |
106 | | // state |
107 | | // One of unsent, opened, headers received, loading, and done; initially unsent. |
108 | | State m_state { State::Unsent }; |
109 | | |
110 | | // https://xhr.spec.whatwg.org/#send-flag |
111 | | // send() flag |
112 | | // A flag, initially unset. |
113 | | bool m_send { false }; |
114 | | |
115 | | // https://xhr.spec.whatwg.org/#timeout |
116 | | // timeout |
117 | | // An unsigned integer, initially 0. |
118 | | u32 m_timeout { 0 }; |
119 | | |
120 | | // https://xhr.spec.whatwg.org/#cross-origin-credentials |
121 | | // cross-origin credentials |
122 | | // A boolean, initially false. |
123 | | bool m_cross_origin_credentials { false }; |
124 | | |
125 | | // https://xhr.spec.whatwg.org/#request-method |
126 | | // request method |
127 | | // A method. |
128 | | ByteString m_request_method; |
129 | | |
130 | | // https://xhr.spec.whatwg.org/#request-url |
131 | | // request URL |
132 | | // A URL. |
133 | | URL::URL m_request_url; |
134 | | |
135 | | // https://xhr.spec.whatwg.org/#author-request-headers |
136 | | // author request headers |
137 | | // A header list, initially empty. |
138 | | JS::NonnullGCPtr<Fetch::Infrastructure::HeaderList> m_author_request_headers; |
139 | | |
140 | | // https://xhr.spec.whatwg.org/#request-body |
141 | | // request body |
142 | | // Initially null. |
143 | | JS::GCPtr<Fetch::Infrastructure::Body> m_request_body; |
144 | | |
145 | | // https://xhr.spec.whatwg.org/#synchronous-flag |
146 | | // synchronous flag |
147 | | // A flag, initially unset. |
148 | | bool m_synchronous { false }; |
149 | | |
150 | | // https://xhr.spec.whatwg.org/#upload-complete-flag |
151 | | // upload complete flag |
152 | | // A flag, initially unset. |
153 | | bool m_upload_complete { false }; |
154 | | |
155 | | // https://xhr.spec.whatwg.org/#upload-listener-flag |
156 | | // upload listener flag |
157 | | // A flag, initially unset. |
158 | | bool m_upload_listener { false }; |
159 | | |
160 | | // https://xhr.spec.whatwg.org/#timed-out-flag |
161 | | // timed out flag |
162 | | // A flag, initially unset. |
163 | | bool m_timed_out { false }; |
164 | | |
165 | | // https://xhr.spec.whatwg.org/#response |
166 | | // response |
167 | | // A response, initially a network error. |
168 | | JS::NonnullGCPtr<Fetch::Infrastructure::Response> m_response; |
169 | | |
170 | | // https://xhr.spec.whatwg.org/#received-bytes |
171 | | // received bytes |
172 | | // A byte sequence, initially the empty byte sequence. |
173 | | ByteBuffer m_received_bytes; |
174 | | |
175 | | // https://xhr.spec.whatwg.org/#response-type |
176 | | // response type |
177 | | // One of the empty string, "arraybuffer", "blob", "document", "json", and "text"; initially the empty string. |
178 | | Bindings::XMLHttpRequestResponseType m_response_type; |
179 | | |
180 | | enum class Failure { |
181 | | /// ???? |
182 | | }; |
183 | | |
184 | | // https://xhr.spec.whatwg.org/#response-object |
185 | | // response object |
186 | | // An object, failure, or null, initially null. |
187 | | // NOTE: This needs to be a JS::Value as the JSON response might not actually be an object. |
188 | | Variant<JS::NonnullGCPtr<JS::Object>, Failure, Empty> m_response_object; |
189 | | |
190 | | // https://xhr.spec.whatwg.org/#xmlhttprequest-fetch-controller |
191 | | // fetch controller |
192 | | // A fetch controller, initially a new fetch controller. |
193 | | // NOTE: The send() method sets it to a useful fetch controller, but for simplicity it always holds a fetch controller. |
194 | | JS::NonnullGCPtr<Fetch::Infrastructure::FetchController> m_fetch_controller; |
195 | | |
196 | | // https://xhr.spec.whatwg.org/#override-mime-type |
197 | | // override MIME type |
198 | | // A MIME type or null, initially null. |
199 | | // NOTE: Can get a value when overrideMimeType() is invoked. |
200 | | Optional<MimeSniff::MimeType> m_override_mime_type; |
201 | | |
202 | | // Non-standard, see async path in `send()` |
203 | | u64 m_request_body_transmitted { 0 }; |
204 | | }; |
205 | | |
206 | | } |