Serenity Operating System
1/*
2 * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/ByteBuffer.h>
10#include <AK/Error.h>
11#include <AK/Forward.h>
12#include <AK/Optional.h>
13#include <AK/String.h>
14#include <AK/URL.h>
15#include <AK/Variant.h>
16#include <AK/Vector.h>
17#include <LibJS/Forward.h>
18#include <LibJS/Heap/Cell.h>
19#include <LibJS/Heap/GCPtr.h>
20#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
21#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
22#include <LibWeb/HTML/Origin.h>
23#include <LibWeb/HTML/PolicyContainers.h>
24#include <LibWeb/HTML/Scripting/Environments.h>
25
26namespace Web::Fetch::Infrastructure {
27
28// https://fetch.spec.whatwg.org/#concept-request
29class Request final : public JS::Cell {
30 JS_CELL(Request, JS::Cell);
31
32public:
33 enum class CacheMode {
34 Default,
35 NoStore,
36 Reload,
37 NoCache,
38 ForceCache,
39 OnlyIfCached,
40 };
41
42 enum class CredentialsMode {
43 Omit,
44 SameOrigin,
45 Include,
46 };
47
48 enum class Destination {
49 Audio,
50 AudioWorklet,
51 Document,
52 Embed,
53 Font,
54 Frame,
55 IFrame,
56 Image,
57 Manifest,
58 Object,
59 PaintWorklet,
60 Report,
61 Script,
62 ServiceWorker,
63 SharedWorker,
64 Style,
65 Track,
66 Video,
67 WebIdentity,
68 Worker,
69 XSLT,
70 };
71
72 enum class Initiator {
73 Download,
74 ImageSet,
75 Manifest,
76 Prefetch,
77 Prerender,
78 XSLT,
79 };
80
81 enum class InitiatorType {
82 Audio,
83 Beacon,
84 Body,
85 CSS,
86 EarlyHint,
87 Embed,
88 Fetch,
89 Font,
90 Frame,
91 IFrame,
92 Image,
93 IMG,
94 Input,
95 Link,
96 Object,
97 Ping,
98 Script,
99 Track,
100 Video,
101 XMLHttpRequest,
102 Other,
103 };
104
105 enum class Mode {
106 SameOrigin,
107 CORS,
108 NoCORS,
109 Navigate,
110 WebSocket,
111 };
112
113 enum class Origin {
114 Client,
115 };
116
117 enum class ParserMetadata {
118 ParserInserted,
119 NotParserInserted,
120 };
121
122 enum class PolicyContainer {
123 Client,
124 };
125
126 enum class RedirectMode {
127 Follow,
128 Error,
129 Manual,
130 };
131
132 enum class Referrer {
133 NoReferrer,
134 Client,
135 };
136
137 enum class ResponseTainting {
138 Basic,
139 CORS,
140 Opaque,
141 };
142
143 enum class ServiceWorkersMode {
144 All,
145 None,
146 };
147
148 enum class Window {
149 NoWindow,
150 Client,
151 };
152
153 // Members are implementation-defined
154 struct Priority { };
155
156 using BodyType = Variant<Empty, ByteBuffer, Body>;
157 using OriginType = Variant<Origin, HTML::Origin>;
158 using PolicyContainerType = Variant<PolicyContainer, HTML::PolicyContainer>;
159 using ReferrerType = Variant<Referrer, AK::URL>;
160 using ReservedClientType = Variant<Empty, HTML::Environment*, HTML::EnvironmentSettingsObject*>;
161 using WindowType = Variant<Window, HTML::EnvironmentSettingsObject*>;
162
163 [[nodiscard]] static JS::NonnullGCPtr<Request> create(JS::VM&);
164
165 [[nodiscard]] ReadonlyBytes method() const { return m_method; }
166 void set_method(ByteBuffer method) { m_method = move(method); }
167
168 [[nodiscard]] bool local_urls_only() const { return m_local_urls_only; }
169 void set_local_urls_only(bool local_urls_only) { m_local_urls_only = local_urls_only; }
170
171 [[nodiscard]] JS::NonnullGCPtr<HeaderList> header_list() const { return m_header_list; }
172 void set_header_list(JS::NonnullGCPtr<HeaderList> header_list) { m_header_list = header_list; }
173
174 [[nodiscard]] bool unsafe_request() const { return m_unsafe_request; }
175 void set_unsafe_request(bool unsafe_request) { m_unsafe_request = unsafe_request; }
176
177 [[nodiscard]] BodyType const& body() const { return m_body; }
178 [[nodiscard]] BodyType& body() { return m_body; }
179 void set_body(BodyType body) { m_body = move(body); }
180
181 [[nodiscard]] HTML::EnvironmentSettingsObject const* client() const { return m_client; }
182 [[nodiscard]] HTML::EnvironmentSettingsObject* client() { return m_client; }
183 void set_client(HTML::EnvironmentSettingsObject* client) { m_client = client; }
184
185 [[nodiscard]] ReservedClientType const& reserved_client() const { return m_reserved_client; }
186 [[nodiscard]] ReservedClientType& reserved_client() { return m_reserved_client; }
187 void set_reserved_client(ReservedClientType reserved_client) { m_reserved_client = move(reserved_client); }
188
189 [[nodiscard]] String const& replaces_client_id() const { return m_replaces_client_id; }
190 void set_replaces_client_id(String replaces_client_id) { m_replaces_client_id = move(replaces_client_id); }
191
192 [[nodiscard]] WindowType const& window() const { return m_window; }
193 void set_window(WindowType window) { m_window = move(window); }
194
195 [[nodiscard]] bool keepalive() const { return m_keepalive; }
196 void set_keepalive(bool keepalive) { m_keepalive = keepalive; }
197
198 [[nodiscard]] Optional<InitiatorType> const& initiator_type() const { return m_initiator_type; }
199 void set_initiator_type(Optional<InitiatorType> initiator_type) { m_initiator_type = move(initiator_type); }
200
201 [[nodiscard]] ServiceWorkersMode service_workers_mode() const { return m_service_workers_mode; }
202 void set_service_workers_mode(ServiceWorkersMode service_workers_mode) { m_service_workers_mode = service_workers_mode; }
203
204 [[nodiscard]] Optional<Initiator> const& initiator() const { return m_initiator; }
205 void set_initiator(Optional<Initiator> initiator) { m_initiator = move(initiator); }
206
207 [[nodiscard]] Optional<Destination> const& destination() const { return m_destination; }
208 void set_destination(Optional<Destination> destination) { m_destination = move(destination); }
209
210 [[nodiscard]] Optional<Priority> const& priority() const { return m_priority; }
211 void set_priority(Optional<Priority> priority) { m_priority = move(priority); }
212
213 [[nodiscard]] OriginType const& origin() const { return m_origin; }
214 void set_origin(OriginType origin) { m_origin = move(origin); }
215
216 [[nodiscard]] PolicyContainerType const& policy_container() const { return m_policy_container; }
217 void set_policy_container(PolicyContainerType policy_container) { m_policy_container = move(policy_container); }
218
219 [[nodiscard]] Mode mode() const { return m_mode; }
220 void set_mode(Mode mode) { m_mode = mode; }
221
222 [[nodiscard]] bool use_cors_preflight() const { return m_use_cors_preflight; }
223 void set_use_cors_preflight(bool use_cors_preflight) { m_use_cors_preflight = use_cors_preflight; }
224
225 [[nodiscard]] CredentialsMode credentials_mode() const { return m_credentials_mode; }
226 void set_credentials_mode(CredentialsMode credentials_mode) { m_credentials_mode = credentials_mode; }
227
228 [[nodiscard]] bool use_url_credentials() const { return m_use_url_credentials; }
229 void set_use_url_credentials(bool use_url_credentials) { m_use_url_credentials = use_url_credentials; }
230
231 [[nodiscard]] CacheMode cache_mode() const { return m_cache_mode; }
232 void set_cache_mode(CacheMode cache_mode) { m_cache_mode = cache_mode; }
233
234 [[nodiscard]] RedirectMode redirect_mode() const { return m_redirect_mode; }
235 void set_redirect_mode(RedirectMode redirect_mode) { m_redirect_mode = redirect_mode; }
236
237 [[nodiscard]] String const& integrity_metadata() const { return m_integrity_metadata; }
238 void set_integrity_metadata(String integrity_metadata) { m_integrity_metadata = move(integrity_metadata); }
239
240 [[nodiscard]] String const& cryptographic_nonce_metadata() const { return m_cryptographic_nonce_metadata; }
241 void set_cryptographic_nonce_metadata(String cryptographic_nonce_metadata) { m_cryptographic_nonce_metadata = move(cryptographic_nonce_metadata); }
242
243 [[nodiscard]] Optional<ParserMetadata> const& parser_metadata() const { return m_parser_metadata; }
244 void set_parser_metadata(Optional<ParserMetadata> parser_metadata) { m_parser_metadata = move(parser_metadata); }
245
246 [[nodiscard]] bool reload_navigation() const { return m_reload_navigation; }
247 void set_reload_navigation(bool reload_navigation) { m_reload_navigation = reload_navigation; }
248
249 [[nodiscard]] bool history_navigation() const { return m_history_navigation; }
250 void set_history_navigation(bool history_navigation) { m_history_navigation = history_navigation; }
251
252 [[nodiscard]] bool user_activation() const { return m_user_activation; }
253 void set_user_activation(bool user_activation) { m_user_activation = user_activation; }
254
255 [[nodiscard]] bool render_blocking() const { return m_render_blocking; }
256 void set_render_blocking(bool render_blocking) { m_render_blocking = render_blocking; }
257
258 [[nodiscard]] Vector<AK::URL> const& url_list() const { return m_url_list; }
259 [[nodiscard]] Vector<AK::URL>& url_list() { return m_url_list; }
260 void set_url_list(Vector<AK::URL> url_list) { m_url_list = move(url_list); }
261
262 [[nodiscard]] u8 redirect_count() const { return m_redirect_count; }
263 void set_redirect_count(u8 redirect_count) { m_redirect_count = redirect_count; }
264
265 [[nodiscard]] ReferrerType const& referrer() const { return m_referrer; }
266 void set_referrer(ReferrerType referrer) { m_referrer = move(referrer); }
267
268 [[nodiscard]] Optional<ReferrerPolicy::ReferrerPolicy> const& referrer_policy() const { return m_referrer_policy; }
269 void set_referrer_policy(Optional<ReferrerPolicy::ReferrerPolicy> referrer_policy) { m_referrer_policy = move(referrer_policy); }
270
271 [[nodiscard]] ResponseTainting response_tainting() const { return m_response_tainting; }
272 void set_response_tainting(ResponseTainting response_tainting) { m_response_tainting = response_tainting; }
273
274 [[nodiscard]] bool prevent_no_cache_cache_control_header_modification() const { return m_prevent_no_cache_cache_control_header_modification; }
275 void set_prevent_no_cache_cache_control_header_modification(bool prevent_no_cache_cache_control_header_modification) { m_prevent_no_cache_cache_control_header_modification = prevent_no_cache_cache_control_header_modification; }
276
277 [[nodiscard]] bool done() const { return m_done; }
278 void set_done(bool done) { m_done = done; }
279
280 [[nodiscard]] bool timing_allow_failed() const { return m_timing_allow_failed; }
281 void set_timing_allow_failed(bool timing_allow_failed) { m_timing_allow_failed = timing_allow_failed; }
282
283 [[nodiscard]] AK::URL& url();
284 [[nodiscard]] AK::URL const& url() const;
285 [[nodiscard]] AK::URL& current_url();
286 [[nodiscard]] AK::URL const& current_url() const;
287 void set_url(AK::URL url);
288
289 [[nodiscard]] bool destination_is_script_like() const;
290
291 [[nodiscard]] bool is_subresource_request() const;
292 [[nodiscard]] bool is_non_subresource_request() const;
293 [[nodiscard]] bool is_navigation_request() const;
294
295 [[nodiscard]] bool has_redirect_tainted_origin() const;
296
297 [[nodiscard]] ErrorOr<String> serialize_origin() const;
298 [[nodiscard]] ErrorOr<ByteBuffer> byte_serialize_origin() const;
299
300 [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> clone(JS::Realm&) const;
301
302 [[nodiscard]] ErrorOr<void> add_range_header(u64 first, Optional<u64> const& last);
303 [[nodiscard]] ErrorOr<void> add_origin_header();
304
305 [[nodiscard]] bool cross_origin_embedder_policy_allows_credentials() const;
306
307 // Non-standard
308 void add_pending_response(Badge<Fetching::PendingResponse>, JS::NonnullGCPtr<Fetching::PendingResponse> pending_response)
309 {
310 VERIFY(!m_pending_responses.contains_slow(pending_response));
311 m_pending_responses.append(pending_response);
312 }
313
314 void remove_pending_response(Badge<Fetching::PendingResponse>, JS::NonnullGCPtr<Fetching::PendingResponse> pending_response)
315 {
316 m_pending_responses.remove_first_matching([&](auto gc_ptr) { return gc_ptr == pending_response; });
317 }
318
319private:
320 explicit Request(JS::NonnullGCPtr<HeaderList>);
321
322 virtual void visit_edges(JS::Cell::Visitor&) override;
323
324 // https://fetch.spec.whatwg.org/#concept-request-method
325 // A request has an associated method (a method). Unless stated otherwise it is `GET`.
326 ByteBuffer m_method { ByteBuffer::copy("GET"sv.bytes()).release_value() };
327
328 // https://fetch.spec.whatwg.org/#local-urls-only-flag
329 // A request has an associated local-URLs-only flag. Unless stated otherwise it is unset.
330 bool m_local_urls_only { false };
331
332 // https://fetch.spec.whatwg.org/#concept-request-header-list
333 // A request has an associated header list (a header list). Unless stated otherwise it is empty.
334 JS::NonnullGCPtr<HeaderList> m_header_list;
335
336 // https://fetch.spec.whatwg.org/#unsafe-request-flag
337 // A request has an associated unsafe-request flag. Unless stated otherwise it is unset.
338 bool m_unsafe_request { false };
339
340 // https://fetch.spec.whatwg.org/#concept-request-body
341 // A request has an associated body (null, a byte sequence, or a body). Unless stated otherwise it is null.
342 BodyType m_body;
343
344 // https://fetch.spec.whatwg.org/#concept-request-client
345 // A request has an associated client (null or an environment settings object).
346 HTML::EnvironmentSettingsObject* m_client { nullptr };
347
348 // https://fetch.spec.whatwg.org/#concept-request-reserved-client
349 // A request has an associated reserved client (null, an environment, or an environment settings object). Unless
350 // stated otherwise it is null.
351 ReservedClientType m_reserved_client;
352
353 // https://fetch.spec.whatwg.org/#concept-request-replaces-client-id
354 // A request has an associated replaces client id (a string). Unless stated otherwise it is the empty string.
355 String m_replaces_client_id;
356
357 // https://fetch.spec.whatwg.org/#concept-request-window
358 // A request has an associated window ("no-window", "client", or an environment settings object whose global object
359 // is a Window object). Unless stated otherwise it is "client".
360 WindowType m_window { Window::Client };
361
362 // https://fetch.spec.whatwg.org/#request-keepalive-flag
363 // A request has an associated boolean keepalive. Unless stated otherwise it is false.
364 bool m_keepalive { false };
365
366 // https://fetch.spec.whatwg.org/#request-initiator-type
367 // A request has an associated initiator type, which is null, "audio", "beacon", "body", "css", "early-hint",
368 // "embed", "fetch", "font", "frame", "iframe", "image", "img", "input", "link", "object", "ping", "script",
369 // "track", "video", "xmlhttprequest", or "other". Unless stated otherwise it is null. [RESOURCE-TIMING]
370 Optional<InitiatorType> m_initiator_type;
371
372 // https://fetch.spec.whatwg.org/#request-service-workers-mode
373 // A request has an associated service-workers mode, that is "all" or "none". Unless stated otherwise it is "all".
374 ServiceWorkersMode m_service_workers_mode { ServiceWorkersMode::All };
375
376 // https://fetch.spec.whatwg.org/#concept-request-initiator
377 // A request has an associated initiator, which is the empty string, "download", "imageset", "manifest",
378 // "prefetch", "prerender", or "xslt". Unless stated otherwise it is the empty string.
379 Optional<Initiator> m_initiator;
380
381 // https://fetch.spec.whatwg.org/#concept-request-destination
382 // A request has an associated destination, which is the empty string, "audio", "audioworklet", "document",
383 // "embed", "font", "frame", "iframe", "image", "manifest", "object", "paintworklet", "report", "script",
384 // "serviceworker", "sharedworker", "style", "track", "video", "webidentity", "worker", or "xslt". Unless stated
385 // otherwise it is the empty string.
386 // NOTE: These are reflected on RequestDestination except for "serviceworker" and "webidentity" as fetches with
387 // those destinations skip service workers.
388 Optional<Destination> m_destination;
389
390 // https://fetch.spec.whatwg.org/#concept-request-priority
391 // A request has an associated priority (null or a user-agent-defined object). Unless otherwise stated it is null.
392 Optional<Priority> m_priority;
393
394 // https://fetch.spec.whatwg.org/#concept-request-origin
395 // A request has an associated origin, which is "client" or an origin. Unless stated otherwise it is "client".
396 OriginType m_origin { Origin::Client };
397
398 // https://fetch.spec.whatwg.org/#concept-request-policy-container
399 // A request has an associated policy container, which is "client" or a policy container. Unless stated otherwise
400 // it is "client".
401 PolicyContainerType m_policy_container { PolicyContainer::Client };
402
403 // https://fetch.spec.whatwg.org/#concept-request-referrer
404 // A request has an associated referrer, which is "no-referrer", "client", or a URL. Unless stated otherwise it is
405 // "client".
406 ReferrerType m_referrer { Referrer::Client };
407
408 // https://fetch.spec.whatwg.org/#concept-request-referrer-policy
409 // A request has an associated referrer policy, which is a referrer policy. Unless stated otherwise it is the empty
410 // string.
411 Optional<ReferrerPolicy::ReferrerPolicy> m_referrer_policy;
412
413 // https://fetch.spec.whatwg.org/#concept-request-mode
414 // A request has an associated mode, which is "same-origin", "cors", "no-cors", "navigate", or "websocket". Unless
415 // stated otherwise, it is "no-cors".
416 Mode m_mode { Mode::NoCORS };
417
418 // https://fetch.spec.whatwg.org/#use-cors-preflight-flag
419 // A request has an associated use-CORS-preflight flag. Unless stated otherwise, it is unset.
420 bool m_use_cors_preflight { false };
421
422 // https://fetch.spec.whatwg.org/#concept-request-credentials-mode
423 // A request has an associated credentials mode, which is "omit", "same-origin", or "include". Unless stated
424 // otherwise, it is "same-origin".
425 CredentialsMode m_credentials_mode { CredentialsMode::SameOrigin };
426
427 // https://fetch.spec.whatwg.org/#concept-request-use-url-credentials-flag
428 // A request has an associated use-URL-credentials flag. Unless stated otherwise, it is unset.
429 // NOTE: When this flag is set, when a request’s URL has a username and password, and there is an available
430 // authentication entry for the request, then the URL’s credentials are preferred over that of the
431 // authentication entry. Modern specifications avoid setting this flag, since putting credentials in URLs is
432 // discouraged, but some older features set it for compatibility reasons.
433 bool m_use_url_credentials { false };
434
435 // https://fetch.spec.whatwg.org/#concept-request-cache-mode
436 // A request has an associated cache mode, which is "default", "no-store", "reload", "no-cache", "force-cache", or
437 // "only-if-cached". Unless stated otherwise, it is "default".
438 CacheMode m_cache_mode { CacheMode::Default };
439
440 // https://fetch.spec.whatwg.org/#concept-request-redirect-mode
441 // A request has an associated redirect mode, which is "follow", "error", or "manual". Unless stated otherwise, it
442 // is "follow".
443 RedirectMode m_redirect_mode { RedirectMode::Follow };
444
445 // https://fetch.spec.whatwg.org/#concept-request-integrity-metadata
446 // A request has associated integrity metadata (a string). Unless stated otherwise, it is the empty string.
447 String m_integrity_metadata;
448
449 // https://fetch.spec.whatwg.org/#concept-request-nonce-metadata
450 // A request has associated cryptographic nonce metadata (a string). Unless stated otherwise, it is the empty
451 // string.
452 String m_cryptographic_nonce_metadata;
453
454 // https://fetch.spec.whatwg.org/#concept-request-parser-metadata
455 // A request has associated parser metadata which is the empty string, "parser-inserted", or
456 // "not-parser-inserted". Unless otherwise stated, it is the empty string.
457 Optional<ParserMetadata> m_parser_metadata;
458
459 // https://fetch.spec.whatwg.org/#concept-request-reload-navigation-flag
460 // A request has an associated reload-navigation flag. Unless stated otherwise, it is unset.
461 bool m_reload_navigation { false };
462
463 // https://fetch.spec.whatwg.org/#concept-request-history-navigation-flag
464 // A request has an associated history-navigation flag. Unless stated otherwise, it is unset.
465 bool m_history_navigation { false };
466
467 // https://fetch.spec.whatwg.org/#request-user-activation
468 // A request has an associated boolean user-activation. Unless stated otherwise, it is false.
469 bool m_user_activation { false };
470
471 // https://fetch.spec.whatwg.org/#request-render-blocking
472 // A request has an associated boolean render-blocking. Unless stated otherwise, it is false.
473 bool m_render_blocking { false };
474
475 // https://fetch.spec.whatwg.org/#concept-request-url-list
476 // A request has an associated URL list (a list of one or more URLs). Unless stated otherwise, it is a list
477 // containing a copy of request’s URL.
478 Vector<AK::URL> m_url_list;
479
480 // https://fetch.spec.whatwg.org/#concept-request-redirect-count
481 // A request has an associated redirect count. Unless stated otherwise, it is zero.
482 // NOTE: '4.4. HTTP-redirect fetch' infers a limit of 20.
483 u8 m_redirect_count { 0 };
484
485 // https://fetch.spec.whatwg.org/#concept-request-response-tainting
486 // A request has an associated response tainting, which is "basic", "cors", or "opaque". Unless stated otherwise,
487 // it is "basic".
488 ResponseTainting m_response_tainting { ResponseTainting::Basic };
489
490 // https://fetch.spec.whatwg.org/#no-cache-prevent-cache-control
491 // A request has an associated prevent no-cache cache-control header modification flag. Unless stated otherwise, it
492 // is unset.
493 bool m_prevent_no_cache_cache_control_header_modification { false };
494
495 // https://fetch.spec.whatwg.org/#done-flag
496 // A request has an associated done flag. Unless stated otherwise, it is unset.
497 bool m_done { false };
498
499 // https://fetch.spec.whatwg.org/#timing-allow-failed
500 // A request has an associated timing allow failed flag. Unless stated otherwise, it is unset.
501 bool m_timing_allow_failed { false };
502
503 // Non-standard
504 Vector<JS::NonnullGCPtr<Fetching::PendingResponse>> m_pending_responses;
505};
506
507}