no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / dom / fetch / Request.cpp
blobf1ae053b9877ba25569566eb805cb69cad879ef8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "Request.h"
9 #include "js/Value.h"
10 #include "nsIURI.h"
11 #include "nsNetUtil.h"
12 #include "nsPIDOMWindow.h"
14 #include "mozilla/ErrorResult.h"
15 #include "mozilla/StaticPrefs_network.h"
16 #include "mozilla/dom/Headers.h"
17 #include "mozilla/dom/Fetch.h"
18 #include "mozilla/dom/FetchUtil.h"
19 #include "mozilla/dom/Promise.h"
20 #include "mozilla/dom/URL.h"
21 #include "mozilla/dom/WorkerPrivate.h"
22 #include "mozilla/dom/WorkerRunnable.h"
23 #include "mozilla/dom/WindowContext.h"
24 #include "mozilla/ipc/PBackgroundSharedTypes.h"
25 #include "mozilla/Unused.h"
27 #include "mozilla/dom/ReadableStreamDefaultReader.h"
29 namespace mozilla::dom {
31 NS_IMPL_ADDREF_INHERITED(Request, FetchBody<Request>)
32 NS_IMPL_RELEASE_INHERITED(Request, FetchBody<Request>)
34 // Can't use _INHERITED macro here because FetchBody<Request> is abstract.
35 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Request)
37 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Request, FetchBody<Request>)
38 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
39 NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
40 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
41 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchStreamReader)
42 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
43 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
45 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Request, FetchBody<Request>)
46 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
47 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
48 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
49 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchStreamReader)
50 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
52 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
53 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
54 NS_INTERFACE_MAP_END_INHERITING(FetchBody<Request>)
56 Request::Request(nsIGlobalObject* aOwner, SafeRefPtr<InternalRequest> aRequest,
57 AbortSignal* aSignal)
58 : FetchBody<Request>(aOwner), mRequest(std::move(aRequest)) {
59 MOZ_ASSERT(mRequest->Headers()->Guard() == HeadersGuardEnum::Immutable ||
60 mRequest->Headers()->Guard() == HeadersGuardEnum::Request ||
61 mRequest->Headers()->Guard() == HeadersGuardEnum::Request_no_cors);
62 if (aSignal) {
63 // If we don't have a signal as argument, we will create it when required by
64 // content, otherwise the Request's signal must follow what has been passed.
65 JS::Rooted<JS::Value> reason(RootingCx(), aSignal->RawReason());
66 mSignal = new AbortSignal(aOwner, aSignal->Aborted(), reason);
67 if (!mSignal->Aborted()) {
68 mSignal->Follow(aSignal);
73 Request::~Request() = default;
75 SafeRefPtr<InternalRequest> Request::GetInternalRequest() {
76 return mRequest.clonePtr();
79 namespace {
80 already_AddRefed<nsIURI> ParseURLFromDocument(Document* aDocument,
81 const nsACString& aInput,
82 ErrorResult& aRv) {
83 MOZ_ASSERT(aDocument);
84 MOZ_ASSERT(NS_IsMainThread());
86 nsCOMPtr<nsIURI> resolvedURI;
87 nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), aInput, nullptr,
88 aDocument->GetBaseURI());
89 if (NS_WARN_IF(NS_FAILED(rv))) {
90 aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
92 return resolvedURI.forget();
94 void GetRequestURLFromDocument(Document* aDocument, const nsACString& aInput,
95 nsACString& aRequestURL,
96 nsACString& aURLfragment, ErrorResult& aRv) {
97 nsCOMPtr<nsIURI> resolvedURI = ParseURLFromDocument(aDocument, aInput, aRv);
98 if (aRv.Failed()) {
99 return;
101 // This fails with URIs with weird protocols, even when they are valid,
102 // so we ignore the failure
103 nsAutoCString credentials;
104 Unused << resolvedURI->GetUserPass(credentials);
105 if (!credentials.IsEmpty()) {
106 aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
107 return;
110 nsCOMPtr<nsIURI> resolvedURIClone;
111 aRv = NS_GetURIWithoutRef(resolvedURI, getter_AddRefs(resolvedURIClone));
112 if (NS_WARN_IF(aRv.Failed())) {
113 return;
115 aRv = resolvedURIClone->GetSpec(aRequestURL);
116 if (NS_WARN_IF(aRv.Failed())) {
117 return;
120 // Get the fragment from nsIURI.
121 aRv = resolvedURI->GetRef(aURLfragment);
122 if (NS_WARN_IF(aRv.Failed())) {
123 return;
126 already_AddRefed<nsIURI> ParseURLFromChrome(const nsACString& aInput,
127 ErrorResult& aRv) {
128 MOZ_ASSERT(NS_IsMainThread());
130 nsCOMPtr<nsIURI> uri;
131 nsresult rv = NS_NewURI(getter_AddRefs(uri), aInput);
132 if (NS_FAILED(rv)) {
133 aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
135 return uri.forget();
137 void GetRequestURLFromChrome(const nsACString& aInput, nsACString& aRequestURL,
138 nsACString& aURLfragment, ErrorResult& aRv) {
139 nsCOMPtr<nsIURI> uri = ParseURLFromChrome(aInput, aRv);
140 if (aRv.Failed()) {
141 return;
143 // This fails with URIs with weird protocols, even when they are valid,
144 // so we ignore the failure
145 nsAutoCString credentials;
146 Unused << uri->GetUserPass(credentials);
147 if (!credentials.IsEmpty()) {
148 aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
149 return;
152 nsCOMPtr<nsIURI> uriClone;
153 aRv = NS_GetURIWithoutRef(uri, getter_AddRefs(uriClone));
154 if (NS_WARN_IF(aRv.Failed())) {
155 return;
157 aRv = uriClone->GetSpec(aRequestURL);
158 if (NS_WARN_IF(aRv.Failed())) {
159 return;
162 // Get the fragment from nsIURI.
163 aRv = uri->GetRef(aURLfragment);
164 if (NS_WARN_IF(aRv.Failed())) {
165 return;
168 already_AddRefed<URL> ParseURLFromWorker(nsIGlobalObject* aGlobal,
169 const nsACString& aInput,
170 ErrorResult& aRv) {
171 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
172 MOZ_ASSERT(worker);
173 worker->AssertIsOnWorkerThread();
175 const auto& baseURL = worker->GetLocationInfo().mHref;
176 RefPtr<URL> url = URL::Constructor(aGlobal, aInput, baseURL, aRv);
177 if (NS_WARN_IF(aRv.Failed())) {
178 aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
180 return url.forget();
182 void GetRequestURLFromWorker(nsIGlobalObject* aGlobal, const nsACString& aInput,
183 nsACString& aRequestURL, nsACString& aURLfragment,
184 ErrorResult& aRv) {
185 RefPtr<URL> url = ParseURLFromWorker(aGlobal, aInput, aRv);
186 if (aRv.Failed()) {
187 return;
189 nsCString username;
190 url->GetUsername(username);
192 nsCString password;
193 url->GetPassword(password);
195 if (!username.IsEmpty() || !password.IsEmpty()) {
196 aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
197 return;
200 // Get the fragment from URL.
201 nsAutoCString fragment;
202 url->GetHash(fragment);
204 // Note: URL::GetHash() includes the "#" and we want the fragment with out
205 // the hash symbol.
206 if (!fragment.IsEmpty()) {
207 aURLfragment = Substring(fragment, 1);
210 url->SetHash(""_ns);
211 url->GetHref(aRequestURL);
214 class ReferrerSameOriginChecker final : public WorkerMainThreadRunnable {
215 public:
216 ReferrerSameOriginChecker(WorkerPrivate* aWorkerPrivate,
217 const nsACString& aReferrerURL, nsresult& aResult)
218 : WorkerMainThreadRunnable(aWorkerPrivate,
219 "Fetch :: Referrer same origin check"_ns),
220 mReferrerURL(aReferrerURL),
221 mResult(aResult) {
222 mWorkerPrivate->AssertIsOnWorkerThread();
225 bool MainThreadRun() override {
226 nsCOMPtr<nsIURI> uri;
227 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), mReferrerURL))) {
228 if (nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal()) {
229 mResult = principal->CheckMayLoad(uri,
230 /* allowIfInheritsPrincipal */ false);
233 return true;
236 private:
237 const nsCString mReferrerURL;
238 nsresult& mResult;
241 } // namespace
243 /*static*/
244 SafeRefPtr<Request> Request::Constructor(const GlobalObject& aGlobal,
245 const RequestOrUTF8String& aInput,
246 const RequestInit& aInit,
247 ErrorResult& aRv) {
248 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
249 return Constructor(global, aGlobal.Context(), aInput, aInit,
250 aGlobal.CallerType(), aRv);
253 /*static*/
254 SafeRefPtr<Request> Request::Constructor(
255 nsIGlobalObject* aGlobal, JSContext* aCx, const RequestOrUTF8String& aInput,
256 const RequestInit& aInit, CallerType aCallerType, ErrorResult& aRv) {
257 bool hasCopiedBody = false;
258 SafeRefPtr<InternalRequest> request;
260 RefPtr<AbortSignal> signal;
261 bool bodyFromInit = false;
263 if (aInput.IsRequest()) {
264 RefPtr<Request> inputReq = &aInput.GetAsRequest();
265 nsCOMPtr<nsIInputStream> body;
267 if (aInit.mBody.WasPassed() && !aInit.mBody.Value().IsNull()) {
268 bodyFromInit = true;
269 hasCopiedBody = true;
270 } else {
271 inputReq->GetBody(getter_AddRefs(body));
272 if (inputReq->BodyUsed()) {
273 aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
274 return nullptr;
277 // The body will be copied when GetRequestConstructorCopy() is executed.
278 if (body) {
279 hasCopiedBody = true;
283 request = inputReq->GetInternalRequest();
284 signal = inputReq->GetOrCreateSignal();
285 } else {
286 // aInput is UTF8String.
287 // We need to get url before we create a InternalRequest.
288 const nsACString& input = aInput.GetAsUTF8String();
289 nsAutoCString requestURL;
290 nsCString fragment;
291 if (NS_IsMainThread()) {
292 nsCOMPtr<nsPIDOMWindowInner> inner(do_QueryInterface(aGlobal));
293 Document* doc = inner ? inner->GetExtantDoc() : nullptr;
294 if (doc) {
295 GetRequestURLFromDocument(doc, input, requestURL, fragment, aRv);
296 } else {
297 // If we don't have a document, we must assume that this is a full URL.
298 GetRequestURLFromChrome(input, requestURL, fragment, aRv);
300 } else {
301 GetRequestURLFromWorker(aGlobal, input, requestURL, fragment, aRv);
303 if (aRv.Failed()) {
304 return nullptr;
306 request = MakeSafeRefPtr<InternalRequest>(requestURL, fragment);
308 request = request->GetRequestConstructorCopy(aGlobal, aRv);
309 if (NS_WARN_IF(aRv.Failed())) {
310 return nullptr;
312 Maybe<RequestMode> mode;
313 if (aInit.mMode.WasPassed()) {
314 if (aInit.mMode.Value() == RequestMode::Navigate) {
315 aRv.ThrowTypeError<MSG_INVALID_REQUEST_MODE>("navigate");
316 return nullptr;
319 mode.emplace(aInit.mMode.Value());
321 Maybe<RequestCredentials> credentials;
322 if (aInit.mCredentials.WasPassed()) {
323 credentials.emplace(aInit.mCredentials.Value());
325 Maybe<RequestCache> cache;
326 if (aInit.mCache.WasPassed()) {
327 cache.emplace(aInit.mCache.Value());
329 if (aInput.IsUTF8String()) {
330 if (mode.isNothing()) {
331 mode.emplace(RequestMode::Cors);
333 if (credentials.isNothing()) {
334 if (aCallerType == CallerType::System &&
335 StaticPrefs::network_fetch_systemDefaultsToOmittingCredentials()) {
336 credentials.emplace(RequestCredentials::Omit);
337 } else {
338 credentials.emplace(RequestCredentials::Same_origin);
341 if (cache.isNothing()) {
342 cache.emplace(RequestCache::Default);
346 if (aInit.IsAnyMemberPresent() && request->Mode() == RequestMode::Navigate) {
347 mode = Some(RequestMode::Same_origin);
350 if (aInit.IsAnyMemberPresent()) {
351 request->SetReferrer(nsLiteralCString(kFETCH_CLIENT_REFERRER_STR));
352 request->SetReferrerPolicy(ReferrerPolicy::_empty);
354 if (aInit.mReferrer.WasPassed()) {
355 const nsCString& referrer = aInit.mReferrer.Value();
356 if (referrer.IsEmpty()) {
357 request->SetReferrer(""_ns);
358 } else {
359 nsAutoCString referrerURL;
360 if (NS_IsMainThread()) {
361 nsCOMPtr<nsPIDOMWindowInner> inner(do_QueryInterface(aGlobal));
362 Document* doc = inner ? inner->GetExtantDoc() : nullptr;
363 nsCOMPtr<nsIURI> uri;
364 if (doc) {
365 uri = ParseURLFromDocument(doc, referrer, aRv);
366 } else {
367 // If we don't have a document, we must assume that this is a full
368 // URL.
369 uri = ParseURLFromChrome(referrer, aRv);
371 if (NS_WARN_IF(aRv.Failed())) {
372 aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
373 return nullptr;
375 uri->GetSpec(referrerURL);
376 if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
377 nsCOMPtr<nsIPrincipal> principal = aGlobal->PrincipalOrNull();
378 if (principal) {
379 nsresult rv =
380 principal->CheckMayLoad(uri,
381 /* allowIfInheritsPrincipal */ false);
382 if (NS_FAILED(rv)) {
383 referrerURL.AssignLiteral(kFETCH_CLIENT_REFERRER_STR);
387 } else {
388 RefPtr<URL> url = ParseURLFromWorker(aGlobal, referrer, aRv);
389 if (NS_WARN_IF(aRv.Failed())) {
390 aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
391 return nullptr;
393 url->GetHref(referrerURL);
394 if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
395 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
396 nsresult rv = NS_OK;
397 // ReferrerSameOriginChecker uses a sync loop to get the main thread
398 // to perform the same-origin check. Overall, on Workers this method
399 // can create 3 sync loops (two for constructing URLs and one here) so
400 // in the future we may want to optimize it all by off-loading all of
401 // this work in a single sync loop.
402 RefPtr<ReferrerSameOriginChecker> checker =
403 new ReferrerSameOriginChecker(worker, referrerURL, rv);
404 IgnoredErrorResult error;
405 checker->Dispatch(Canceling, error);
406 if (error.Failed() || NS_FAILED(rv)) {
407 referrerURL.AssignLiteral(kFETCH_CLIENT_REFERRER_STR);
411 request->SetReferrer(referrerURL);
415 if (aInit.mReferrerPolicy.WasPassed()) {
416 request->SetReferrerPolicy(aInit.mReferrerPolicy.Value());
419 if (aInit.mSignal.WasPassed()) {
420 signal = aInit.mSignal.Value();
423 // https://fetch.spec.whatwg.org/#dom-global-fetch
424 // https://fetch.spec.whatwg.org/#dom-request
425 // The priority of init overrides input's priority.
426 if (aInit.mPriority.WasPassed()) {
427 request->SetPriorityMode(aInit.mPriority.Value());
430 UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo;
431 nsILoadInfo::CrossOriginEmbedderPolicy coep =
432 nsILoadInfo::EMBEDDER_POLICY_NULL;
434 if (NS_IsMainThread()) {
435 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
436 if (window) {
437 nsCOMPtr<Document> doc;
438 doc = window->GetExtantDoc();
439 if (doc) {
440 request->SetEnvironmentReferrerPolicy(doc->GetReferrerPolicy());
442 principalInfo.reset(new mozilla::ipc::PrincipalInfo());
443 nsresult rv =
444 PrincipalToPrincipalInfo(doc->NodePrincipal(), principalInfo.get());
445 if (NS_WARN_IF(NS_FAILED(rv))) {
446 aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
447 return nullptr;
450 if (window->GetWindowContext()) {
451 coep = window->GetWindowContext()->GetEmbedderPolicy();
454 } else {
455 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
456 if (worker) {
457 worker->AssertIsOnWorkerThread();
458 request->SetEnvironmentReferrerPolicy(worker->GetReferrerPolicy());
459 principalInfo =
460 MakeUnique<mozilla::ipc::PrincipalInfo>(worker->GetPrincipalInfo());
461 coep = worker->GetEmbedderPolicy();
462 // For dedicated worker, the response must respect the owner's COEP.
463 if (coep == nsILoadInfo::EMBEDDER_POLICY_NULL &&
464 worker->IsDedicatedWorker()) {
465 coep = worker->GetOwnerEmbedderPolicy();
470 request->SetPrincipalInfo(std::move(principalInfo));
471 request->SetEmbedderPolicy(coep);
473 if (mode.isSome()) {
474 request->SetMode(mode.value());
477 if (credentials.isSome()) {
478 request->SetCredentialsMode(credentials.value());
481 if (cache.isSome()) {
482 if (cache.value() == RequestCache::Only_if_cached &&
483 request->Mode() != RequestMode::Same_origin) {
484 aRv.ThrowTypeError<MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN>(
485 GetEnumString(request->Mode()));
486 return nullptr;
488 request->SetCacheMode(cache.value());
491 if (aInit.mRedirect.WasPassed()) {
492 request->SetRedirectMode(aInit.mRedirect.Value());
495 if (aInit.mIntegrity.WasPassed()) {
496 request->SetIntegrity(aInit.mIntegrity.Value());
499 if (aInit.mKeepalive.WasPassed()) {
500 request->SetKeepalive(aInit.mKeepalive.Value());
503 if (aInit.mMozErrors.WasPassed() && aInit.mMozErrors.Value()) {
504 request->SetMozErrors();
507 // Request constructor step 14.
508 if (aInit.mMethod.WasPassed()) {
509 nsAutoCString method(aInit.mMethod.Value());
511 // Step 14.1. Disallow forbidden methods, and anything that is not a HTTP
512 // token, since HTTP states that Method may be any of the defined values or
513 // a token (extension method).
514 nsAutoCString outMethod;
515 nsresult rv = FetchUtil::GetValidRequestMethod(method, outMethod);
516 if (NS_FAILED(rv)) {
517 aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(method);
518 return nullptr;
521 // Step 14.2
522 request->SetMethod(outMethod);
525 RefPtr<InternalHeaders> requestHeaders = request->Headers();
527 RefPtr<InternalHeaders> headers;
528 if (aInit.mHeaders.WasPassed()) {
529 RefPtr<Headers> h = Headers::Create(aGlobal, aInit.mHeaders.Value(), aRv);
530 if (aRv.Failed()) {
531 return nullptr;
533 headers = h->GetInternalHeaders();
534 } else {
535 headers = new InternalHeaders(*requestHeaders);
538 requestHeaders->Clear();
539 // From "Let r be a new Request object associated with request and a new
540 // Headers object whose guard is "request"."
541 requestHeaders->SetGuard(HeadersGuardEnum::Request, aRv);
542 MOZ_ASSERT(!aRv.Failed());
544 if (request->Mode() == RequestMode::No_cors) {
545 if (!request->HasSimpleMethod()) {
546 nsAutoCString method;
547 request->GetMethod(method);
548 aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(method);
549 return nullptr;
552 requestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
553 if (aRv.Failed()) {
554 return nullptr;
558 requestHeaders->Fill(*headers, aRv);
559 if (aRv.Failed()) {
560 return nullptr;
563 if ((aInit.mBody.WasPassed() && !aInit.mBody.Value().IsNull()) ||
564 hasCopiedBody) {
565 // HEAD and GET are not allowed to have a body.
566 nsAutoCString method;
567 request->GetMethod(method);
568 // method is guaranteed to be uppercase due to step 14.2 above.
569 if (method.EqualsLiteral("HEAD") || method.EqualsLiteral("GET")) {
570 aRv.ThrowTypeError("HEAD or GET Request cannot have a body.");
571 return nullptr;
575 if (aInit.mBody.WasPassed()) {
576 const Nullable<fetch::OwningBodyInit>& bodyInitNullable =
577 aInit.mBody.Value();
578 if (!bodyInitNullable.IsNull()) {
579 const fetch::OwningBodyInit& bodyInit = bodyInitNullable.Value();
580 nsCOMPtr<nsIInputStream> stream;
581 nsAutoCString contentTypeWithCharset;
582 uint64_t contentLength = 0;
583 aRv = ExtractByteStreamFromBody(bodyInit, getter_AddRefs(stream),
584 contentTypeWithCharset, contentLength);
585 if (NS_WARN_IF(aRv.Failed())) {
586 return nullptr;
589 nsCOMPtr<nsIInputStream> temporaryBody = stream;
591 if (!contentTypeWithCharset.IsVoid() &&
592 !requestHeaders->Has("Content-Type"_ns, aRv)) {
593 requestHeaders->Append("Content-Type"_ns, contentTypeWithCharset, aRv);
596 if (NS_WARN_IF(aRv.Failed())) {
597 return nullptr;
600 if (hasCopiedBody) {
601 request->SetBody(nullptr, 0);
604 request->SetBody(temporaryBody, contentLength);
608 auto domRequest =
609 MakeSafeRefPtr<Request>(aGlobal, std::move(request), signal);
611 if (aInput.IsRequest() && !bodyFromInit) {
612 RefPtr<Request> inputReq = &aInput.GetAsRequest();
613 nsCOMPtr<nsIInputStream> body;
614 inputReq->GetBody(getter_AddRefs(body));
615 if (body) {
616 inputReq->SetBody(nullptr, 0);
617 inputReq->SetBodyUsed(aCx, aRv);
618 if (NS_WARN_IF(aRv.Failed())) {
619 return nullptr;
623 return domRequest;
626 SafeRefPtr<Request> Request::Clone(ErrorResult& aRv) {
627 if (BodyUsed()) {
628 aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
629 return nullptr;
632 SafeRefPtr<InternalRequest> ir = mRequest->Clone();
633 if (!ir) {
634 aRv.Throw(NS_ERROR_FAILURE);
635 return nullptr;
638 return MakeSafeRefPtr<Request>(mOwner, std::move(ir), GetOrCreateSignal());
641 Headers* Request::Headers_() {
642 if (!mHeaders) {
643 mHeaders = new Headers(mOwner, mRequest->Headers());
646 return mHeaders;
649 AbortSignal* Request::GetOrCreateSignal() {
650 if (!mSignal) {
651 mSignal = new AbortSignal(mOwner, false, JS::UndefinedHandleValue);
654 return mSignal;
657 AbortSignalImpl* Request::GetSignalImpl() const { return mSignal; }
659 AbortSignalImpl* Request::GetSignalImplToConsumeBody() const {
660 // This is a hack, see Response::GetSignalImplToConsumeBody.
661 return nullptr;
664 } // namespace mozilla::dom