Serenity Operating System
at master 507 lines 22 kB view raw
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}