Request.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "Request.h"
  6. #include "nsIURI.h"
  7. #include "nsNetUtil.h"
  8. #include "nsPIDOMWindow.h"
  9. #include "mozilla/ErrorResult.h"
  10. #include "mozilla/dom/Headers.h"
  11. #include "mozilla/dom/Fetch.h"
  12. #include "mozilla/dom/FetchUtil.h"
  13. #include "mozilla/dom/Promise.h"
  14. #include "mozilla/dom/URL.h"
  15. #include "mozilla/Unused.h"
  16. #include "WorkerPrivate.h"
  17. #include "WorkerRunnable.h"
  18. #include "WorkerScope.h"
  19. #include "Workers.h"
  20. namespace mozilla {
  21. namespace dom {
  22. using namespace workers;
  23. NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
  24. NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
  25. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner, mHeaders)
  26. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
  27. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  28. NS_INTERFACE_MAP_ENTRY(nsISupports)
  29. NS_INTERFACE_MAP_END
  30. Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest, AbortSignal* aSignal)
  31. : FetchBody<Request>()
  32. , mOwner(aOwner)
  33. , mRequest(aRequest)
  34. , mSignal(aSignal)
  35. {
  36. MOZ_ASSERT(aRequest->Headers()->Guard() == HeadersGuardEnum::Immutable ||
  37. aRequest->Headers()->Guard() == HeadersGuardEnum::Request ||
  38. aRequest->Headers()->Guard() == HeadersGuardEnum::Request_no_cors);
  39. SetMimeType();
  40. // aSignal can be null.
  41. }
  42. Request::~Request()
  43. {
  44. }
  45. // static
  46. bool
  47. Request::RequestContextEnabled(JSContext* aCx, JSObject* aObj)
  48. {
  49. if (NS_IsMainThread()) {
  50. return Preferences::GetBool("dom.requestcontext.enabled", false);
  51. }
  52. using namespace workers;
  53. // Otherwise, check the pref via the WorkerPrivate
  54. WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
  55. if (!workerPrivate) {
  56. return false;
  57. }
  58. return workerPrivate->RequestContextEnabled();
  59. }
  60. already_AddRefed<InternalRequest>
  61. Request::GetInternalRequest()
  62. {
  63. RefPtr<InternalRequest> r = mRequest;
  64. return r.forget();
  65. }
  66. namespace {
  67. already_AddRefed<nsIURI>
  68. ParseURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
  69. ErrorResult& aRv)
  70. {
  71. MOZ_ASSERT(aDocument);
  72. MOZ_ASSERT(NS_IsMainThread());
  73. nsCOMPtr<nsIURI> baseURI = aDocument->GetBaseURI();
  74. nsCOMPtr<nsIURI> resolvedURI;
  75. aRv = NS_NewURI(getter_AddRefs(resolvedURI), aInput, nullptr, baseURI);
  76. if (NS_WARN_IF(aRv.Failed())) {
  77. aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
  78. }
  79. return resolvedURI.forget();
  80. }
  81. void
  82. GetRequestURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
  83. nsAString& aRequestURL, nsACString& aURLfragment,
  84. ErrorResult& aRv)
  85. {
  86. nsCOMPtr<nsIURI> resolvedURI = ParseURLFromDocument(aDocument, aInput, aRv);
  87. if (aRv.Failed()) {
  88. return;
  89. }
  90. // This fails with URIs with weird protocols, even when they are valid,
  91. // so we ignore the failure
  92. nsAutoCString credentials;
  93. Unused << resolvedURI->GetUserPass(credentials);
  94. if (!credentials.IsEmpty()) {
  95. aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
  96. return;
  97. }
  98. nsCOMPtr<nsIURI> resolvedURIClone;
  99. // We use CloneIgnoringRef to strip away the fragment even if the original URI
  100. // is immutable.
  101. aRv = resolvedURI->CloneIgnoringRef(getter_AddRefs(resolvedURIClone));
  102. if (NS_WARN_IF(aRv.Failed())) {
  103. return;
  104. }
  105. nsAutoCString spec;
  106. aRv = resolvedURIClone->GetSpec(spec);
  107. if (NS_WARN_IF(aRv.Failed())) {
  108. return;
  109. }
  110. CopyUTF8toUTF16(spec, aRequestURL);
  111. // Get the fragment from nsIURI.
  112. aRv = resolvedURI->GetRef(aURLfragment);
  113. if (NS_WARN_IF(aRv.Failed())) {
  114. return;
  115. }
  116. }
  117. already_AddRefed<nsIURI>
  118. ParseURLFromChrome(const nsAString& aInput, ErrorResult& aRv)
  119. {
  120. MOZ_ASSERT(NS_IsMainThread());
  121. nsCOMPtr<nsIURI> uri;
  122. aRv = NS_NewURI(getter_AddRefs(uri), aInput, nullptr, nullptr);
  123. if (NS_WARN_IF(aRv.Failed())) {
  124. aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
  125. }
  126. return uri.forget();
  127. }
  128. void
  129. GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL,
  130. nsACString& aURLfragment, ErrorResult& aRv)
  131. {
  132. nsCOMPtr<nsIURI> uri = ParseURLFromChrome(aInput, aRv);
  133. if (aRv.Failed()) {
  134. return;
  135. }
  136. // This fails with URIs with weird protocols, even when they are valid,
  137. // so we ignore the failure
  138. nsAutoCString credentials;
  139. Unused << uri->GetUserPass(credentials);
  140. if (!credentials.IsEmpty()) {
  141. aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
  142. return;
  143. }
  144. nsCOMPtr<nsIURI> uriClone;
  145. // We use CloneIgnoringRef to strip away the fragment even if the original URI
  146. // is immutable.
  147. aRv = uri->CloneIgnoringRef(getter_AddRefs(uriClone));
  148. if (NS_WARN_IF(aRv.Failed())) {
  149. return;
  150. }
  151. nsAutoCString spec;
  152. aRv = uriClone->GetSpec(spec);
  153. if (NS_WARN_IF(aRv.Failed())) {
  154. return;
  155. }
  156. CopyUTF8toUTF16(spec, aRequestURL);
  157. // Get the fragment from nsIURI.
  158. aRv = uri->GetRef(aURLfragment);
  159. if (NS_WARN_IF(aRv.Failed())) {
  160. return;
  161. }
  162. }
  163. already_AddRefed<URL>
  164. ParseURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
  165. ErrorResult& aRv)
  166. {
  167. workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
  168. MOZ_ASSERT(worker);
  169. worker->AssertIsOnWorkerThread();
  170. NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref);
  171. RefPtr<URL> url = URL::WorkerConstructor(aGlobal, aInput, baseURL, aRv);
  172. if (NS_WARN_IF(aRv.Failed())) {
  173. aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
  174. }
  175. return url.forget();
  176. }
  177. void
  178. GetRequestURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
  179. nsAString& aRequestURL, nsACString& aURLfragment,
  180. ErrorResult& aRv)
  181. {
  182. RefPtr<URL> url = ParseURLFromWorker(aGlobal, aInput, aRv);
  183. if (aRv.Failed()) {
  184. return;
  185. }
  186. nsString username;
  187. url->GetUsername(username, aRv);
  188. if (NS_WARN_IF(aRv.Failed())) {
  189. return;
  190. }
  191. nsString password;
  192. url->GetPassword(password, aRv);
  193. if (NS_WARN_IF(aRv.Failed())) {
  194. return;
  195. }
  196. if (!username.IsEmpty() || !password.IsEmpty()) {
  197. aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
  198. return;
  199. }
  200. // Get the fragment from URL.
  201. nsAutoString fragment;
  202. url->GetHash(fragment, aRv);
  203. if (NS_WARN_IF(aRv.Failed())) {
  204. return;
  205. }
  206. // Note: URL::GetHash() includes the "#" and we want the fragment with out
  207. // the hash symbol.
  208. if (!fragment.IsEmpty()) {
  209. CopyUTF16toUTF8(Substring(fragment, 1), aURLfragment);
  210. }
  211. url->SetHash(EmptyString(), aRv);
  212. if (NS_WARN_IF(aRv.Failed())) {
  213. return;
  214. }
  215. url->Stringify(aRequestURL, aRv);
  216. if (NS_WARN_IF(aRv.Failed())) {
  217. return;
  218. }
  219. }
  220. class ReferrerSameOriginChecker final : public WorkerMainThreadRunnable
  221. {
  222. public:
  223. ReferrerSameOriginChecker(workers::WorkerPrivate* aWorkerPrivate,
  224. const nsAString& aReferrerURL,
  225. nsresult& aResult)
  226. : WorkerMainThreadRunnable(aWorkerPrivate,
  227. NS_LITERAL_CSTRING("Fetch :: Referrer same origin check")),
  228. mReferrerURL(aReferrerURL),
  229. mResult(aResult)
  230. {
  231. mWorkerPrivate->AssertIsOnWorkerThread();
  232. }
  233. bool
  234. MainThreadRun() override
  235. {
  236. nsCOMPtr<nsIURI> uri;
  237. if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), mReferrerURL))) {
  238. nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal();
  239. if (principal) {
  240. mResult = principal->CheckMayLoad(uri, /* report */ false,
  241. /* allowIfInheritsPrincipal */ false);
  242. }
  243. }
  244. return true;
  245. }
  246. private:
  247. const nsString mReferrerURL;
  248. nsresult& mResult;
  249. };
  250. } // namespace
  251. /*static*/ already_AddRefed<Request>
  252. Request::Constructor(const GlobalObject& aGlobal,
  253. const RequestOrUSVString& aInput,
  254. const RequestInit& aInit, ErrorResult& aRv)
  255. {
  256. nsCOMPtr<nsIInputStream> temporaryBody;
  257. RefPtr<InternalRequest> request;
  258. nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
  259. RefPtr<AbortSignal> signal;
  260. if (aInput.IsRequest()) {
  261. RefPtr<Request> inputReq = &aInput.GetAsRequest();
  262. nsCOMPtr<nsIInputStream> body;
  263. inputReq->GetBody(getter_AddRefs(body));
  264. if (inputReq->BodyUsed()) {
  265. aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
  266. return nullptr;
  267. }
  268. if (body) {
  269. temporaryBody = body;
  270. }
  271. request = inputReq->GetInternalRequest();
  272. signal = inputReq->GetOrCreateSignal();
  273. } else {
  274. // aInput is USVString.
  275. // We need to get url before we create a InternalRequest.
  276. nsAutoString input;
  277. input.Assign(aInput.GetAsUSVString());
  278. nsAutoString requestURL;
  279. nsCString fragment;
  280. if (NS_IsMainThread()) {
  281. nsIDocument* doc = GetEntryDocument();
  282. if (doc) {
  283. GetRequestURLFromDocument(doc, input, requestURL, fragment, aRv);
  284. } else {
  285. // If we don't have a document, we must assume that this is a full URL.
  286. GetRequestURLFromChrome(input, requestURL, fragment, aRv);
  287. }
  288. } else {
  289. GetRequestURLFromWorker(aGlobal, input, requestURL, fragment, aRv);
  290. }
  291. if (NS_WARN_IF(aRv.Failed())) {
  292. return nullptr;
  293. }
  294. request = new InternalRequest(NS_ConvertUTF16toUTF8(requestURL), fragment);
  295. }
  296. request = request->GetRequestConstructorCopy(global, aRv);
  297. if (NS_WARN_IF(aRv.Failed())) {
  298. return nullptr;
  299. }
  300. RequestMode fallbackMode = RequestMode::EndGuard_;
  301. RequestCredentials fallbackCredentials = RequestCredentials::EndGuard_;
  302. RequestCache fallbackCache = RequestCache::EndGuard_;
  303. if (aInput.IsUSVString()) {
  304. fallbackMode = RequestMode::Cors;
  305. fallbackCredentials = RequestCredentials::Same_origin;
  306. fallbackCache = RequestCache::Default;
  307. }
  308. RequestMode mode = aInit.mMode.WasPassed() ? aInit.mMode.Value() : fallbackMode;
  309. RequestCredentials credentials =
  310. aInit.mCredentials.WasPassed() ? aInit.mCredentials.Value()
  311. : fallbackCredentials;
  312. if (mode == RequestMode::Navigate ||
  313. (aInit.IsAnyMemberPresent() && request->Mode() == RequestMode::Navigate)) {
  314. mode = RequestMode::Same_origin;
  315. }
  316. if (aInit.IsAnyMemberPresent()) {
  317. request->SetReferrer(NS_LITERAL_STRING(kFETCH_CLIENT_REFERRER_STR));
  318. request->SetReferrerPolicy(ReferrerPolicy::_empty);
  319. }
  320. if (aInit.mReferrer.WasPassed()) {
  321. const nsString& referrer = aInit.mReferrer.Value();
  322. if (referrer.IsEmpty()) {
  323. request->SetReferrer(NS_LITERAL_STRING(""));
  324. } else {
  325. nsAutoString referrerURL;
  326. if (NS_IsMainThread()) {
  327. nsIDocument* doc = GetEntryDocument();
  328. nsCOMPtr<nsIURI> uri;
  329. if (doc) {
  330. uri = ParseURLFromDocument(doc, referrer, aRv);
  331. } else {
  332. // If we don't have a document, we must assume that this is a full URL.
  333. uri = ParseURLFromChrome(referrer, aRv);
  334. }
  335. if (NS_WARN_IF(aRv.Failed())) {
  336. aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
  337. return nullptr;
  338. }
  339. nsAutoCString spec;
  340. uri->GetSpec(spec);
  341. CopyUTF8toUTF16(spec, referrerURL);
  342. if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
  343. nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
  344. if (principal) {
  345. nsresult rv = principal->CheckMayLoad(uri, /* report */ false,
  346. /* allowIfInheritsPrincipal */ false);
  347. if (NS_FAILED(rv)) {
  348. referrerURL.AssignLiteral(kFETCH_CLIENT_REFERRER_STR);
  349. }
  350. }
  351. }
  352. } else {
  353. RefPtr<URL> url = ParseURLFromWorker(aGlobal, referrer, aRv);
  354. if (NS_WARN_IF(aRv.Failed())) {
  355. aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
  356. return nullptr;
  357. }
  358. url->Stringify(referrerURL, aRv);
  359. if (NS_WARN_IF(aRv.Failed())) {
  360. aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
  361. return nullptr;
  362. }
  363. if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
  364. workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
  365. nsresult rv = NS_OK;
  366. // ReferrerSameOriginChecker uses a sync loop to get the main thread
  367. // to perform the same-origin check. Overall, on Workers this method
  368. // can create 3 sync loops (two for constructing URLs and one here) so
  369. // in the future we may want to optimize it all by off-loading all of
  370. // this work in a single sync loop.
  371. RefPtr<ReferrerSameOriginChecker> checker =
  372. new ReferrerSameOriginChecker(worker, referrerURL, rv);
  373. IgnoredErrorResult error;
  374. checker->Dispatch(Terminating, error);
  375. if (error.Failed() || NS_FAILED(rv)) {
  376. referrerURL.AssignLiteral(kFETCH_CLIENT_REFERRER_STR);
  377. }
  378. }
  379. }
  380. request->SetReferrer(referrerURL);
  381. }
  382. }
  383. if (aInit.mReferrerPolicy.WasPassed()) {
  384. request->SetReferrerPolicy(aInit.mReferrerPolicy.Value());
  385. }
  386. if (aInit.mSignal.WasPassed()) {
  387. signal = aInit.mSignal.Value();
  388. }
  389. if (NS_IsMainThread()) {
  390. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
  391. if (window) {
  392. nsCOMPtr<nsIDocument> doc;
  393. doc = window->GetExtantDoc();
  394. if (doc) {
  395. request->SetEnvironmentReferrerPolicy(doc->GetReferrerPolicy());
  396. }
  397. }
  398. } else {
  399. workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
  400. if (worker) {
  401. worker->AssertIsOnWorkerThread();
  402. request->SetEnvironmentReferrerPolicy(worker->GetReferrerPolicy());
  403. }
  404. }
  405. if (mode != RequestMode::EndGuard_) {
  406. request->ClearCreatedByFetchEvent();
  407. request->SetMode(mode);
  408. }
  409. if (credentials != RequestCredentials::EndGuard_) {
  410. request->ClearCreatedByFetchEvent();
  411. request->SetCredentialsMode(credentials);
  412. }
  413. RequestCache cache = aInit.mCache.WasPassed() ?
  414. aInit.mCache.Value() : fallbackCache;
  415. if (cache != RequestCache::EndGuard_) {
  416. if (cache == RequestCache::Only_if_cached &&
  417. request->Mode() != RequestMode::Same_origin) {
  418. uint32_t t = static_cast<uint32_t>(request->Mode());
  419. NS_ConvertASCIItoUTF16 modeString(RequestModeValues::strings[t].value,
  420. RequestModeValues::strings[t].length);
  421. aRv.ThrowTypeError<MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN>(modeString);
  422. return nullptr;
  423. }
  424. request->ClearCreatedByFetchEvent();
  425. request->SetCacheMode(cache);
  426. }
  427. if (aInit.mRedirect.WasPassed()) {
  428. request->SetRedirectMode(aInit.mRedirect.Value());
  429. }
  430. if (aInit.mIntegrity.WasPassed()) {
  431. request->SetIntegrity(aInit.mIntegrity.Value());
  432. }
  433. // Request constructor step 14.
  434. if (aInit.mMethod.WasPassed()) {
  435. nsAutoCString method(aInit.mMethod.Value());
  436. // Step 14.1. Disallow forbidden methods, and anything that is not a HTTP
  437. // token, since HTTP states that Method may be any of the defined values or
  438. // a token (extension method).
  439. nsAutoCString outMethod;
  440. nsresult rv = FetchUtil::GetValidRequestMethod(method, outMethod);
  441. if (NS_FAILED(rv)) {
  442. NS_ConvertUTF8toUTF16 label(method);
  443. aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(label);
  444. return nullptr;
  445. }
  446. // Step 14.2
  447. request->ClearCreatedByFetchEvent();
  448. request->SetMethod(outMethod);
  449. }
  450. RefPtr<InternalHeaders> requestHeaders = request->Headers();
  451. RefPtr<InternalHeaders> headers;
  452. if (aInit.mHeaders.WasPassed()) {
  453. RefPtr<Headers> h = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv);
  454. if (aRv.Failed()) {
  455. return nullptr;
  456. }
  457. request->ClearCreatedByFetchEvent();
  458. headers = h->GetInternalHeaders();
  459. } else {
  460. headers = new InternalHeaders(*requestHeaders);
  461. }
  462. requestHeaders->Clear();
  463. // From "Let r be a new Request object associated with request and a new
  464. // Headers object whose guard is "request"."
  465. requestHeaders->SetGuard(HeadersGuardEnum::Request, aRv);
  466. MOZ_ASSERT(!aRv.Failed());
  467. if (request->Mode() == RequestMode::No_cors) {
  468. if (!request->HasSimpleMethod()) {
  469. nsAutoCString method;
  470. request->GetMethod(method);
  471. NS_ConvertUTF8toUTF16 label(method);
  472. aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(label);
  473. return nullptr;
  474. }
  475. if (!request->GetIntegrity().IsEmpty()) {
  476. aRv.ThrowTypeError<MSG_REQUEST_INTEGRITY_METADATA_NOT_EMPTY>();
  477. return nullptr;
  478. }
  479. requestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
  480. if (aRv.Failed()) {
  481. return nullptr;
  482. }
  483. }
  484. requestHeaders->Fill(*headers, aRv);
  485. if (aRv.Failed()) {
  486. return nullptr;
  487. }
  488. if ((aInit.mBody.WasPassed() && !aInit.mBody.Value().IsNull()) ||
  489. temporaryBody) {
  490. // HEAD and GET are not allowed to have a body.
  491. nsAutoCString method;
  492. request->GetMethod(method);
  493. // method is guaranteed to be uppercase due to step 14.2 above.
  494. if (method.EqualsLiteral("HEAD") || method.EqualsLiteral("GET")) {
  495. aRv.ThrowTypeError<MSG_NO_BODY_ALLOWED_FOR_GET_AND_HEAD>();
  496. return nullptr;
  497. }
  498. }
  499. if (aInit.mBody.WasPassed()) {
  500. const Nullable<OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& bodyInitNullable =
  501. aInit.mBody.Value();
  502. if (!bodyInitNullable.IsNull()) {
  503. const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit =
  504. bodyInitNullable.Value();
  505. nsCOMPtr<nsIInputStream> stream;
  506. nsAutoCString contentType;
  507. uint64_t contentLengthUnused;
  508. aRv = ExtractByteStreamFromBody(bodyInit,
  509. getter_AddRefs(stream),
  510. contentType,
  511. contentLengthUnused);
  512. if (NS_WARN_IF(aRv.Failed())) {
  513. return nullptr;
  514. }
  515. temporaryBody = stream;
  516. if (!contentType.IsVoid() &&
  517. !requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
  518. requestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
  519. contentType, aRv);
  520. }
  521. if (NS_WARN_IF(aRv.Failed())) {
  522. return nullptr;
  523. }
  524. request->ClearCreatedByFetchEvent();
  525. request->SetBody(temporaryBody);
  526. }
  527. }
  528. RefPtr<Request> domRequest = new Request(global, request, signal);
  529. domRequest->SetMimeType();
  530. if (aInput.IsRequest()) {
  531. RefPtr<Request> inputReq = &aInput.GetAsRequest();
  532. nsCOMPtr<nsIInputStream> body;
  533. inputReq->GetBody(getter_AddRefs(body));
  534. if (body) {
  535. inputReq->SetBody(nullptr);
  536. inputReq->SetBodyUsed();
  537. }
  538. }
  539. return domRequest.forget();
  540. }
  541. already_AddRefed<Request>
  542. Request::Clone(ErrorResult& aRv)
  543. {
  544. if (BodyUsed()) {
  545. aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
  546. return nullptr;
  547. }
  548. RefPtr<InternalRequest> ir = mRequest->Clone();
  549. if (!ir) {
  550. aRv.Throw(NS_ERROR_FAILURE);
  551. return nullptr;
  552. }
  553. RefPtr<Request> request = new Request(mOwner, ir, GetOrCreateSignal());
  554. return request.forget();
  555. }
  556. Headers*
  557. Request::Headers_()
  558. {
  559. if (!mHeaders) {
  560. mHeaders = new Headers(mOwner, mRequest->Headers());
  561. }
  562. return mHeaders;
  563. }
  564. AbortSignal*
  565. Request::GetOrCreateSignal()
  566. {
  567. if (!mSignal) {
  568. mSignal = new AbortSignal(false);
  569. }
  570. return mSignal;
  571. }
  572. AbortSignal*
  573. Request::GetSignal() const
  574. {
  575. return mSignal;
  576. }
  577. } // namespace dom
  578. } // namespace mozilla