Request.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. /*
  2. * Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/ScopeGuard.h>
  7. #include <AK/URLParser.h>
  8. #include <LibWeb/Bindings/Intrinsics.h>
  9. #include <LibWeb/DOM/AbortSignal.h>
  10. #include <LibWeb/Fetch/Enums.h>
  11. #include <LibWeb/Fetch/Headers.h>
  12. #include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
  13. #include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
  14. #include <LibWeb/Fetch/Infrastructure/HTTP/Methods.h>
  15. #include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
  16. #include <LibWeb/Fetch/Request.h>
  17. #include <LibWeb/HTML/Scripting/Environments.h>
  18. #include <LibWeb/ReferrerPolicy/ReferrerPolicy.h>
  19. namespace Web::Fetch {
  20. Request::Request(JS::Realm& realm, NonnullOwnPtr<Infrastructure::Request> request)
  21. : PlatformObject(realm)
  22. , m_request(move(request))
  23. {
  24. set_prototype(&Bindings::cached_web_prototype(realm, "Request"));
  25. }
  26. Request::~Request() = default;
  27. void Request::visit_edges(Cell::Visitor& visitor)
  28. {
  29. Base::visit_edges(visitor);
  30. visitor.visit(m_headers);
  31. visitor.visit(m_signal);
  32. }
  33. // https://fetch.spec.whatwg.org/#concept-body-mime-type
  34. // https://fetch.spec.whatwg.org/#ref-for-concept-body-mime-type%E2%91%A0
  35. Optional<MimeSniff::MimeType> Request::mime_type_impl() const
  36. {
  37. // Objects including the Body interface mixin need to define an associated MIME type algorithm which takes no arguments and returns failure or a MIME type.
  38. // A Request object’s MIME type is to return the result of extracting a MIME type from its request’s header list.
  39. return m_request->header_list()->extract_mime_type();
  40. }
  41. // https://fetch.spec.whatwg.org/#concept-body-body
  42. // https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A7
  43. Optional<Infrastructure::Body const&> Request::body_impl() const
  44. {
  45. // Objects including the Body interface mixin have an associated body (null or a body).
  46. // A Request object’s body is its request’s body.
  47. return m_request->body().visit(
  48. [](Infrastructure::Body const& b) -> Optional<Infrastructure::Body const&> { return b; },
  49. [](Empty) -> Optional<Infrastructure::Body const&> { return {}; },
  50. // A byte sequence will be safely extracted into a body early on in fetch.
  51. [](ByteBuffer const&) -> Optional<Infrastructure::Body const&> { VERIFY_NOT_REACHED(); });
  52. }
  53. // https://fetch.spec.whatwg.org/#concept-body-body
  54. // https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A7
  55. Optional<Infrastructure::Body&> Request::body_impl()
  56. {
  57. // Objects including the Body interface mixin have an associated body (null or a body).
  58. // A Request object’s body is its request’s body.
  59. return m_request->body().visit(
  60. [](Infrastructure::Body& b) -> Optional<Infrastructure::Body&> { return b; },
  61. [](Empty) -> Optional<Infrastructure::Body&> { return {}; },
  62. // A byte sequence will be safely extracted into a body early on in fetch.
  63. [](ByteBuffer&) -> Optional<Infrastructure::Body&> { VERIFY_NOT_REACHED(); });
  64. }
  65. // https://fetch.spec.whatwg.org/#request-create
  66. JS::NonnullGCPtr<Request> Request::create(NonnullOwnPtr<Infrastructure::Request> request, Headers::Guard guard, JS::Realm& realm)
  67. {
  68. // Copy a NonnullRefPtr to the request's header list before request is being move()'d.
  69. auto request_reader_list = request->header_list();
  70. // 1. Let requestObject be a new Request object with realm.
  71. // 2. Set requestObject’s request to request.
  72. auto* request_object = realm.heap().allocate<Request>(realm, realm, move(request));
  73. // 3. Set requestObject’s headers to a new Headers object with realm, whose headers list is request’s headers list and guard is guard.
  74. request_object->m_headers = realm.heap().allocate<Headers>(realm, realm);
  75. request_object->m_headers->set_header_list(move(request_reader_list));
  76. request_object->m_headers->set_guard(guard);
  77. // 4. Set requestObject’s signal to a new AbortSignal object with realm.
  78. request_object->m_signal = realm.heap().allocate<DOM::AbortSignal>(realm, realm);
  79. // 5. Return requestObject.
  80. return JS::NonnullGCPtr { *request_object };
  81. }
  82. // https://fetch.spec.whatwg.org/#dom-request
  83. WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm& realm, RequestInfo const& input, RequestInit const& init)
  84. {
  85. // Referred to as 'this' in the spec.
  86. auto request_object = JS::NonnullGCPtr { *realm.heap().allocate<Request>(realm, realm, make<Infrastructure::Request>()) };
  87. // 1. Let request be null.
  88. Infrastructure::Request const* input_request = nullptr;
  89. // Cleanup for the special case where we create a temporary Request ourselves
  90. // instead of just taking a pointer from something else.
  91. ArmedScopeGuard delete_input_request { [&] {
  92. delete input_request;
  93. } };
  94. // 2. Let fallbackMode be null.
  95. Optional<Infrastructure::Request::Mode> fallback_mode;
  96. // 3. Let baseURL be this’s relevant settings object’s API base URL.
  97. auto base_url = HTML::relevant_settings_object(*request_object).api_base_url();
  98. // 4. Let signal be null.
  99. DOM::AbortSignal const* input_signal = nullptr;
  100. // 5. If input is a string, then:
  101. if (input.has<String>()) {
  102. // 1. Let parsedURL be the result of parsing input with baseURL.
  103. auto parsed_url = URLParser::parse(input.get<String>(), &base_url);
  104. // 2. If parsedURL is failure, then throw a TypeError.
  105. if (!parsed_url.is_valid())
  106. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Input URL is not valid"sv };
  107. // 3. If parsedURL includes credentials, then throw a TypeError.
  108. if (parsed_url.includes_credentials())
  109. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Input URL must not include credentials"sv };
  110. // 4. Set request to a new request whose URL is parsedURL.
  111. auto* new_request = new Infrastructure::Request();
  112. new_request->set_url(move(parsed_url));
  113. input_request = new_request;
  114. // 5. Set fallbackMode to "cors".
  115. fallback_mode = Infrastructure::Request::Mode::CORS;
  116. }
  117. // 6. Otherwise:
  118. else {
  119. // 1. Assert: input is a Request object.
  120. VERIFY(input.has<JS::Handle<Request>>());
  121. // 2. Set request to input’s request.
  122. input_request = &input.get<JS::Handle<Request>>()->request();
  123. delete_input_request.disarm();
  124. // 3. Set signal to input’s signal.
  125. input_signal = input.get<JS::Handle<Request>>()->signal();
  126. }
  127. // 7. Let origin be this’s relevant settings object’s origin.
  128. auto const& origin = HTML::relevant_settings_object(*request_object).origin();
  129. // 8. Let window be "client".
  130. auto window = Infrastructure::Request::WindowType { Infrastructure::Request::Window::Client };
  131. // 9. If request’s window is an environment settings object and its origin is same origin with origin, then set window to request’s window.
  132. if (input_request->window().has<HTML::EnvironmentSettingsObject*>()) {
  133. auto* eso = input_request->window().get<HTML::EnvironmentSettingsObject*>();
  134. if (eso->origin().is_same_origin(origin))
  135. window = input_request->window();
  136. }
  137. // 10. If init["window"] exists and is non-null, then throw a TypeError.
  138. if (init.window.has_value() && !init.window->is_null())
  139. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "The 'window' property must be omitted or null"sv };
  140. // 11. If init["window"] exists, then set window to "no-window".
  141. if (init.window.has_value())
  142. window = Infrastructure::Request::Window::NoWindow;
  143. // 12. Set request to a new request with the following properties:
  144. // NOTE: This is done at the beginning as the 'this' value Request object
  145. // cannot exist with a null Infrastructure::Request.
  146. auto& request = request_object->request();
  147. // URL
  148. // request’s URL.
  149. request.set_url(input_request->url());
  150. // method
  151. // request’s method.
  152. request.set_method(TRY_OR_RETURN_OOM(realm, ByteBuffer::copy(request.method())));
  153. // header list
  154. // A copy of request’s header list.
  155. auto header_list_copy = make_ref_counted<Infrastructure::HeaderList>();
  156. for (auto& header : *request.header_list())
  157. TRY_OR_RETURN_OOM(realm, header_list_copy->append(header));
  158. request.set_header_list(move(header_list_copy));
  159. // unsafe-request flag
  160. // Set.
  161. request.set_unsafe_request(true);
  162. // client
  163. // This’s relevant settings object.
  164. request.set_client(HTML::relevant_settings_object(*request_object));
  165. // window
  166. // window.
  167. request.set_window(window);
  168. // priority
  169. // request’s priority.
  170. request.set_priority(input_request->priority());
  171. // origin
  172. // request’s origin. The propagation of the origin is only significant for navigation requests being handled by a service worker. In this scenario a request can have an origin that is different from the current client.
  173. request.set_origin(input_request->origin());
  174. // referrer
  175. // request’s referrer.
  176. request.set_referrer(input_request->referrer());
  177. // referrer policy
  178. // request’s referrer policy.
  179. request.set_referrer_policy(input_request->referrer_policy());
  180. // mode
  181. // request’s mode.
  182. request.set_mode(input_request->mode());
  183. // credentials mode
  184. // request’s credentials mode.
  185. request.set_credentials_mode(input_request->credentials_mode());
  186. // cache mode
  187. // request’s cache mode.
  188. request.set_cache_mode(input_request->cache_mode());
  189. // redirect mode
  190. // request’s redirect mode.
  191. request.set_redirect_mode(input_request->redirect_mode());
  192. // integrity metadata
  193. // request’s integrity metadata.
  194. request.set_integrity_metadata(input_request->integrity_metadata());
  195. // keepalive
  196. // request’s keepalive.
  197. request.set_keepalive(input_request->keepalive());
  198. // reload-navigation flag
  199. // request’s reload-navigation flag.
  200. request.set_reload_navigation(input_request->reload_navigation());
  201. // history-navigation flag
  202. // request’s history-navigation flag.
  203. request.set_history_navigation(input_request->history_navigation());
  204. // URL list
  205. // A clone of request’s URL list.
  206. request.set_url_list(input_request->url_list());
  207. // initiator type
  208. // "fetch".
  209. request.set_initiator_type(Infrastructure::Request::InitiatorType::Fetch);
  210. // 13. If init is not empty, then:
  211. if (!init.is_empty()) {
  212. // 1. If request’s mode is "navigate", then set it to "same-origin".
  213. if (request.mode() == Infrastructure::Request::Mode::Navigate)
  214. request.set_mode(Infrastructure::Request::Mode::SameOrigin);
  215. // 2. Unset request’s reload-navigation flag.
  216. request.set_reload_navigation(false);
  217. // 3. Unset request’s history-navigation flag.
  218. request.set_history_navigation(false);
  219. // 4. Set request’s origin to "client".
  220. request.set_origin(Infrastructure::Request::Origin::Client);
  221. // 5. Set request’s referrer to "client".
  222. request.set_referrer(Infrastructure::Request::Referrer::Client);
  223. // 6. Set request’s referrer policy to the empty string.
  224. request.set_referrer_policy({});
  225. // 7. Set request’s URL to request’s current URL.
  226. request.set_url(request.current_url());
  227. // 8. Set request’s URL list to « request’s URL ».
  228. // NOTE: This is done implicitly by assigning the initial URL above.
  229. }
  230. // 14. If init["referrer"] exists, then:
  231. if (init.referrer.has_value()) {
  232. // 1. Let referrer be init["referrer"].
  233. auto const& referrer = *init.referrer;
  234. // 2. If referrer is the empty string, then set request’s referrer to "no-referrer".
  235. if (referrer.is_empty()) {
  236. request.set_referrer(Infrastructure::Request::Referrer::NoReferrer);
  237. }
  238. // 3. Otherwise:
  239. else {
  240. // 1. Let parsedReferrer be the result of parsing referrer with baseURL.
  241. auto parsed_referrer = URLParser::parse(referrer, &base_url);
  242. // 2. If parsedReferrer is failure, then throw a TypeError.
  243. if (!parsed_referrer.is_valid())
  244. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Referrer must be a valid URL"sv };
  245. // 3. If one of the following is true
  246. // - parsedReferrer’s scheme is "about" and path is the string "client"
  247. // - parsedReferrer’s origin is not same origin with origin
  248. // then set request’s referrer to "client".
  249. // FIXME: Actually use the given origin once we have https://url.spec.whatwg.org/#concept-url-origin.
  250. if ((parsed_referrer.scheme() == "about"sv && parsed_referrer.path() == "client"sv) || !HTML::Origin().is_same_origin(origin)) {
  251. request.set_referrer(Infrastructure::Request::Referrer::Client);
  252. }
  253. // 4. Otherwise, set request’s referrer to parsedReferrer.
  254. else {
  255. request.set_referrer(move(parsed_referrer));
  256. }
  257. }
  258. }
  259. // 15. If init["referrerPolicy"] exists, then set request’s referrer policy to it.
  260. if (init.referrer_policy.has_value())
  261. request.set_referrer_policy(from_bindings_enum(*init.referrer_policy));
  262. // 16. Let mode be init["mode"] if it exists, and fallbackMode otherwise.
  263. auto mode = init.mode.has_value()
  264. ? from_bindings_enum(*init.mode)
  265. : fallback_mode;
  266. // 17. If mode is "navigate", then throw a TypeError.
  267. if (mode == Infrastructure::Request::Mode::Navigate)
  268. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Mode must not be 'navigate"sv };
  269. // 18. If mode is non-null, set request’s mode to mode.
  270. if (mode.has_value())
  271. request.set_mode(*mode);
  272. // 19. If init["credentials"] exists, then set request’s credentials mode to it.
  273. if (init.credentials.has_value())
  274. request.set_credentials_mode(from_bindings_enum(*init.credentials));
  275. // 20. If init["cache"] exists, then set request’s cache mode to it.
  276. if (init.cache.has_value())
  277. request.set_cache_mode(from_bindings_enum(*init.cache));
  278. // 21. If request’s cache mode is "only-if-cached" and request’s mode is not "same-origin", then throw a TypeError.
  279. if (request.cache_mode() == Infrastructure::Request::CacheMode::OnlyIfCached && request.mode() != Infrastructure::Request::Mode::SameOrigin)
  280. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Mode must be 'same-origin' when cache mode is 'only-if-cached'"sv };
  281. // 22. If init["redirect"] exists, then set request’s redirect mode to it.
  282. if (init.redirect.has_value())
  283. request.set_redirect_mode(from_bindings_enum(*init.redirect));
  284. // 23. If init["integrity"] exists, then set request’s integrity metadata to it.
  285. if (init.integrity.has_value())
  286. request.set_integrity_metadata(*init.integrity);
  287. // 24. If init["keepalive"] exists, then set request’s keepalive to it.
  288. if (init.keepalive.has_value())
  289. request.set_keepalive(*init.keepalive);
  290. // 25. If init["method"] exists, then:
  291. if (init.method.has_value()) {
  292. // 1. Let method be init["method"].
  293. auto method = *init.method;
  294. // 2. If method is not a method or method is a forbidden method, then throw a TypeError.
  295. if (!Infrastructure::is_method(method.bytes()))
  296. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method has invalid value"sv };
  297. if (Infrastructure::is_forbidden_method(method.bytes()))
  298. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must not be one of CONNECT, TRACE, or TRACK"sv };
  299. // 3. Normalize method.
  300. method = TRY_OR_RETURN_OOM(realm, Infrastructure::normalize_method(method.bytes()));
  301. // 4. Set request’s method to method.
  302. request.set_method(MUST(ByteBuffer::copy(method.bytes())));
  303. }
  304. // 26. If init["signal"] exists, then set signal to it.
  305. if (init.signal.has_value())
  306. input_signal = *init.signal;
  307. // 27. Set this’s request to request.
  308. // NOTE: This is done at the beginning as the 'this' value Request object
  309. // cannot exist with a null Infrastructure::Request.
  310. // 28. Set this’s signal to a new AbortSignal object with this’s relevant Realm.
  311. auto& this_relevant_realm = HTML::relevant_realm(*request_object);
  312. request_object->m_signal = realm.heap().allocate<DOM::AbortSignal>(this_relevant_realm, this_relevant_realm);
  313. // 29. If signal is not null, then make this’s signal follow signal.
  314. if (input_signal != nullptr) {
  315. // FIXME: Our AbortSignal doesn't support 'following' yet.
  316. }
  317. // 30. Set this’s headers to a new Headers object with this’s relevant Realm, whose header list is request’s header list and guard is "request".
  318. request_object->m_headers = realm.heap().allocate<Headers>(realm, realm);
  319. request_object->m_headers->set_header_list(request.header_list());
  320. request_object->m_headers->set_guard(Headers::Guard::Request);
  321. // 31. If this’s request’s mode is "no-cors", then:
  322. if (request_object->request().mode() == Infrastructure::Request::Mode::NoCORS) {
  323. // 1. If this’s request’s method is not a CORS-safelisted method, then throw a TypeError.
  324. if (!Infrastructure::is_cors_safelisted_method(request_object->request().method()))
  325. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must be one of GET, HEAD, or POST"sv };
  326. // 2. Set this’s headers’s guard to "request-no-cors".
  327. request_object->headers()->set_guard(Headers::Guard::RequestNoCORS);
  328. }
  329. // 32. If init is not empty, then:
  330. if (!init.is_empty()) {
  331. // 1. Let headers be a copy of this’s headers and its associated header list.
  332. auto headers = Variant<HeadersInit, NonnullRefPtr<Infrastructure::HeaderList>> { request_object->headers()->header_list() };
  333. // 2. If init["headers"] exists, then set headers to init["headers"].
  334. if (init.headers.has_value())
  335. headers = *init.headers;
  336. // 3. Empty this’s headers’s header list.
  337. request_object->headers()->header_list()->clear();
  338. // 4. If headers is a Headers object, then for each header in its header list, append (header’s name, header’s value) to this’s headers.
  339. if (headers.has<NonnullRefPtr<Infrastructure::HeaderList>>()) {
  340. auto& header_list = *headers.get<NonnullRefPtr<Infrastructure::HeaderList>>();
  341. for (auto& header : header_list)
  342. TRY(request_object->headers()->append(String::copy(header.name), String::copy(header.value)));
  343. }
  344. // 5. Otherwise, fill this’s headers with headers.
  345. else {
  346. request_object->headers()->fill(headers.get<HeadersInit>());
  347. }
  348. }
  349. // 33. Let inputBody be input’s request’s body if input is a Request object; otherwise null.
  350. auto const& input_body = input.has<JS::Handle<Request>>()
  351. ? input.get<JS::Handle<Request>>()->request().body().get<Infrastructure::Body>()
  352. : Optional<Infrastructure::Body> {};
  353. // 34. If either init["body"] exists and is non-null or inputBody is non-null, and request’s method is `GET` or `HEAD`, then throw a TypeError.
  354. if (((init.body.has_value() && (*init.body).has_value()) || input_body.has_value()) && StringView { request.method() }.is_one_of("GET"sv, "HEAD"sv))
  355. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must not be GET or HEAD when body is provided"sv };
  356. // 35. Let initBody be null.
  357. Optional<Infrastructure::Body> init_body;
  358. // 36. If init["body"] exists and is non-null, then:
  359. if (init.body.has_value() && (*init.body).has_value()) {
  360. // 1. Let bodyWithType be the result of extracting init["body"], with keepalive set to request’s keepalive.
  361. auto body_with_type = TRY(extract_body(realm, (*init.body).value(), request.keepalive()));
  362. // 2. Set initBody to bodyWithType’s body.
  363. init_body = move(body_with_type.body);
  364. // 3. Let type be bodyWithType’s type.
  365. auto const& type = body_with_type.type;
  366. // 4. 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.
  367. if (type.has_value() && !request_object->headers()->header_list()->contains("Content-Type"sv.bytes()))
  368. TRY(request_object->headers()->append("Content-Type"sv, String::copy(type->span())));
  369. }
  370. // 37. Let inputOrInitBody be initBody if it is non-null; otherwise inputBody.
  371. auto const& input_or_init_body = init_body.has_value() ? init_body : input_body;
  372. // 38. If inputOrInitBody is non-null and inputOrInitBody’s source is null, then:
  373. if (input_or_init_body.has_value() && input_or_init_body->source().has<Empty>()) {
  374. // 1. If initBody is non-null and init["duplex"] does not exist, then throw a TypeError.
  375. if (init_body.has_value() && !init.duplex.has_value())
  376. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Body without source requires 'duplex' value to be set"sv };
  377. // 2. If this’s request’s mode is neither "same-origin" nor "cors", then throw a TypeError.
  378. if (request_object->request().mode() != Infrastructure::Request::Mode::SameOrigin && request_object->request().mode() != Infrastructure::Request::Mode::CORS)
  379. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request mode must be 'same-origin' or 'cors'"sv };
  380. // 3. Set this’s request’s use-CORS-preflight flag.
  381. request_object->request().set_use_cors_preflight(true);
  382. }
  383. // 39. Let finalBody be inputOrInitBody.
  384. auto const& final_body = input_or_init_body;
  385. // 40. If initBody is null and inputBody is non-null, then:
  386. if (!init_body.has_value() && input_body.has_value()) {
  387. // 2. If input is unusable, then throw a TypeError.
  388. if (input.has<JS::Handle<Request>>() && input.get<JS::Handle<Request>>()->is_unusable())
  389. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request is unusable"sv };
  390. // FIXME: 2. Set finalBody to the result of creating a proxy for inputBody.
  391. }
  392. // 41. Set this’s request’s body to finalBody.
  393. if (final_body.has_value())
  394. request_object->request().set_body(*final_body);
  395. return JS::NonnullGCPtr { *request_object };
  396. }
  397. // https://fetch.spec.whatwg.org/#dom-request-method
  398. String Request::method() const
  399. {
  400. // The method getter steps are to return this’s request’s method.
  401. return String::copy(m_request->method());
  402. }
  403. // https://fetch.spec.whatwg.org/#dom-request-url
  404. String Request::url() const
  405. {
  406. // The url getter steps are to return this’s request’s URL, serialized.
  407. return m_request->url().serialize();
  408. }
  409. // https://fetch.spec.whatwg.org/#dom-request-headers
  410. JS::NonnullGCPtr<Headers> Request::headers() const
  411. {
  412. // The headers getter steps are to return this’s headers.
  413. return *m_headers;
  414. }
  415. // https://fetch.spec.whatwg.org/#dom-request-destination
  416. Bindings::RequestDestination Request::destination() const
  417. {
  418. // The destination getter are to return this’s request’s destination.
  419. return to_bindings_enum(m_request->destination());
  420. }
  421. // https://fetch.spec.whatwg.org/#dom-request-referrer
  422. String Request::referrer() const
  423. {
  424. return m_request->referrer().visit(
  425. [&](Infrastructure::Request::Referrer const& referrer) {
  426. switch (referrer) {
  427. // 1. If this’s request’s referrer is "no-referrer", then return the empty string.
  428. case Infrastructure::Request::Referrer::NoReferrer:
  429. return String::empty();
  430. // 2. If this’s request’s referrer is "client", then return "about:client".
  431. case Infrastructure::Request::Referrer::Client:
  432. return String { "about:client"sv };
  433. default:
  434. VERIFY_NOT_REACHED();
  435. }
  436. },
  437. [&](AK::URL const& url) {
  438. // 3. Return this’s request’s referrer, serialized.
  439. return url.serialize();
  440. });
  441. }
  442. // https://fetch.spec.whatwg.org/#dom-request-referrerpolicy
  443. Bindings::ReferrerPolicy Request::referrer_policy() const
  444. {
  445. // The referrerPolicy getter steps are to return this’s request’s referrer policy.
  446. return to_bindings_enum(m_request->referrer_policy());
  447. }
  448. // https://fetch.spec.whatwg.org/#dom-request-mode
  449. Bindings::RequestMode Request::mode() const
  450. {
  451. // The mode getter steps are to return this’s request’s mode.
  452. return to_bindings_enum(m_request->mode());
  453. }
  454. // https://fetch.spec.whatwg.org/#dom-request-credentials
  455. Bindings::RequestCredentials Request::credentials() const
  456. {
  457. // The credentials getter steps are to return this’s request’s credentials mode.
  458. return to_bindings_enum(m_request->credentials_mode());
  459. }
  460. // https://fetch.spec.whatwg.org/#dom-request-cache
  461. Bindings::RequestCache Request::cache() const
  462. {
  463. // The cache getter steps are to return this’s request’s cache mode.
  464. return to_bindings_enum(m_request->cache_mode());
  465. }
  466. // https://fetch.spec.whatwg.org/#dom-request-redirect
  467. Bindings::RequestRedirect Request::redirect() const
  468. {
  469. // The redirect getter steps are to return this’s request’s redirect mode.
  470. return to_bindings_enum(m_request->redirect_mode());
  471. }
  472. // https://fetch.spec.whatwg.org/#dom-request-integrity
  473. String Request::integrity() const
  474. {
  475. // The integrity getter steps are to return this’s request’s integrity metadata.
  476. return m_request->integrity_metadata();
  477. }
  478. // https://fetch.spec.whatwg.org/#dom-request-keepalive
  479. bool Request::keepalive() const
  480. {
  481. // The keepalive getter steps are to return this’s request’s keepalive.
  482. return m_request->keepalive();
  483. }
  484. // https://fetch.spec.whatwg.org/#dom-request-isreloadnavigation
  485. bool Request::is_reload_navigation() const
  486. {
  487. // The isReloadNavigation getter steps are to return true if this’s request’s reload-navigation flag is set; otherwise false.
  488. return m_request->reload_navigation();
  489. }
  490. // https://fetch.spec.whatwg.org/#dom-request-ishistorynavigation
  491. bool Request::is_history_navigation() const
  492. {
  493. // The isHistoryNavigation getter steps are to return true if this’s request’s history-navigation flag is set; otherwise false.
  494. return m_request->history_navigation();
  495. }
  496. // https://fetch.spec.whatwg.org/#dom-request-signal
  497. JS::NonnullGCPtr<DOM::AbortSignal> Request::signal() const
  498. {
  499. // The signal getter steps are to return this’s signal.
  500. return *m_signal;
  501. }
  502. // https://fetch.spec.whatwg.org/#dom-request-clone
  503. WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::clone() const
  504. {
  505. // 1. If this is unusable, then throw a TypeError.
  506. if (is_unusable())
  507. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request is unusable"sv };
  508. // 2. Let clonedRequest be the result of cloning this’s request.
  509. auto cloned_request = TRY(m_request->clone());
  510. // 3. Let clonedRequestObject be the result of creating a Request object, given clonedRequest, this’s headers’s guard, and this’s relevant Realm.
  511. auto cloned_request_object = Request::create(move(cloned_request), m_headers->guard(), HTML::relevant_realm(*this));
  512. // FIXME: 4. Make clonedRequestObject’s signal follow this’s signal.
  513. // 5. Return clonedRequestObject.
  514. return cloned_request_object;
  515. }
  516. }