Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / fetch / Request.cpp
blob62041cdc10a9d9cb545abf4e64082606a0a115e7
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 "nsIURI.h"
10 #include "nsNetUtil.h"
11 #include "nsPIDOMWindow.h"
13 #include "mozilla/ErrorResult.h"
14 #include "mozilla/dom/Headers.h"
15 #include "mozilla/dom/Fetch.h"
16 #include "mozilla/dom/FetchUtil.h"
17 #include "mozilla/dom/Promise.h"
18 #include "mozilla/dom/URL.h"
19 #include "mozilla/dom/WorkerPrivate.h"
20 #include "mozilla/dom/WorkerRunnable.h"
21 #include "mozilla/dom/WindowContext.h"
22 #include "mozilla/Unused.h"
24 namespace mozilla::dom {
26 NS_IMPL_ADDREF_INHERITED(Request, FetchBody<Request>)
27 NS_IMPL_RELEASE_INHERITED(Request, FetchBody<Request>)
29 NS_IMPL_CYCLE_COLLECTION_CLASS(Request)
31 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Request, FetchBody<Request>)
32 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
33 NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
34 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
35 AbortFollower::Unlink(static_cast<AbortFollower*>(tmp));
36 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
37 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Request, FetchBody<Request>)
40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
43 AbortFollower::Traverse(static_cast<AbortFollower*>(tmp), cb);
44 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
46 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Request, FetchBody<Request>)
47 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamBody)
48 MOZ_DIAGNOSTIC_ASSERT(!tmp->mReadableStreamReader);
49 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamReader)
50 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
51 NS_IMPL_CYCLE_COLLECTION_TRACE_END
53 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
54 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
55 NS_INTERFACE_MAP_END_INHERITING(FetchBody<Request>)
57 Request::Request(nsIGlobalObject* aOwner, SafeRefPtr<InternalRequest> aRequest,
58 AbortSignal* aSignal)
59 : FetchBody<Request>(aOwner), mRequest(std::move(aRequest)) {
60 MOZ_ASSERT(mRequest->Headers()->Guard() == HeadersGuardEnum::Immutable ||
61 mRequest->Headers()->Guard() == HeadersGuardEnum::Request ||
62 mRequest->Headers()->Guard() == HeadersGuardEnum::Request_no_cors);
63 if (aSignal) {
64 // If we don't have a signal as argument, we will create it when required by
65 // content, otherwise the Request's signal must follow what has been passed.
66 mSignal = new AbortSignal(aOwner, aSignal->Aborted());
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 nsAString& aInput,
82 ErrorResult& aRv) {
83 MOZ_ASSERT(aDocument);
84 MOZ_ASSERT(NS_IsMainThread());
86 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
87 nsAutoCString input;
88 if (!AppendUTF16toUTF8(aInput, input, fallible)) {
89 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
90 return nullptr;
93 nsCOMPtr<nsIURI> resolvedURI;
94 nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), input, nullptr,
95 aDocument->GetBaseURI());
96 if (NS_WARN_IF(NS_FAILED(rv))) {
97 aRv.ThrowTypeError<MSG_INVALID_URL>(input);
99 return resolvedURI.forget();
101 void GetRequestURLFromDocument(Document* aDocument, const nsAString& aInput,
102 nsAString& aRequestURL, nsACString& aURLfragment,
103 ErrorResult& aRv) {
104 nsCOMPtr<nsIURI> resolvedURI = ParseURLFromDocument(aDocument, aInput, aRv);
105 if (aRv.Failed()) {
106 return;
108 // This fails with URIs with weird protocols, even when they are valid,
109 // so we ignore the failure
110 nsAutoCString credentials;
111 Unused << resolvedURI->GetUserPass(credentials);
112 if (!credentials.IsEmpty()) {
113 aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(NS_ConvertUTF16toUTF8(aInput));
114 return;
117 nsCOMPtr<nsIURI> resolvedURIClone;
118 aRv = NS_GetURIWithoutRef(resolvedURI, getter_AddRefs(resolvedURIClone));
119 if (NS_WARN_IF(aRv.Failed())) {
120 return;
122 nsAutoCString spec;
123 aRv = resolvedURIClone->GetSpec(spec);
124 if (NS_WARN_IF(aRv.Failed())) {
125 return;
127 CopyUTF8toUTF16(spec, aRequestURL);
129 // Get the fragment from nsIURI.
130 aRv = resolvedURI->GetRef(aURLfragment);
131 if (NS_WARN_IF(aRv.Failed())) {
132 return;
135 already_AddRefed<nsIURI> ParseURLFromChrome(const nsAString& aInput,
136 ErrorResult& aRv) {
137 MOZ_ASSERT(NS_IsMainThread());
138 // Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
139 nsAutoCString input;
140 if (!AppendUTF16toUTF8(aInput, input, fallible)) {
141 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
142 return nullptr;
145 nsCOMPtr<nsIURI> uri;
146 nsresult rv = NS_NewURI(getter_AddRefs(uri), input);
147 if (NS_FAILED(rv)) {
148 aRv.ThrowTypeError<MSG_INVALID_URL>(input);
150 return uri.forget();
152 void GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL,
153 nsACString& aURLfragment, ErrorResult& aRv) {
154 nsCOMPtr<nsIURI> uri = ParseURLFromChrome(aInput, aRv);
155 if (aRv.Failed()) {
156 return;
158 // This fails with URIs with weird protocols, even when they are valid,
159 // so we ignore the failure
160 nsAutoCString credentials;
161 Unused << uri->GetUserPass(credentials);
162 if (!credentials.IsEmpty()) {
163 aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(NS_ConvertUTF16toUTF8(aInput));
164 return;
167 nsCOMPtr<nsIURI> uriClone;
168 aRv = NS_GetURIWithoutRef(uri, getter_AddRefs(uriClone));
169 if (NS_WARN_IF(aRv.Failed())) {
170 return;
172 nsAutoCString spec;
173 aRv = uriClone->GetSpec(spec);
174 if (NS_WARN_IF(aRv.Failed())) {
175 return;
177 CopyUTF8toUTF16(spec, aRequestURL);
179 // Get the fragment from nsIURI.
180 aRv = uri->GetRef(aURLfragment);
181 if (NS_WARN_IF(aRv.Failed())) {
182 return;
185 already_AddRefed<URL> ParseURLFromWorker(nsIGlobalObject* aGlobal,
186 const nsAString& aInput,
187 ErrorResult& aRv) {
188 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
189 MOZ_ASSERT(worker);
190 worker->AssertIsOnWorkerThread();
192 NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref);
193 RefPtr<URL> url = URL::Constructor(aGlobal, aInput, baseURL, aRv);
194 if (NS_WARN_IF(aRv.Failed())) {
195 aRv.ThrowTypeError<MSG_INVALID_URL>(NS_ConvertUTF16toUTF8(aInput));
197 return url.forget();
199 void GetRequestURLFromWorker(nsIGlobalObject* aGlobal, const nsAString& aInput,
200 nsAString& aRequestURL, nsACString& aURLfragment,
201 ErrorResult& aRv) {
202 RefPtr<URL> url = ParseURLFromWorker(aGlobal, aInput, aRv);
203 if (aRv.Failed()) {
204 return;
206 nsString username;
207 url->GetUsername(username);
209 nsString password;
210 url->GetPassword(password);
212 if (!username.IsEmpty() || !password.IsEmpty()) {
213 aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(NS_ConvertUTF16toUTF8(aInput));
214 return;
217 // Get the fragment from URL.
218 nsAutoString fragment;
219 url->GetHash(fragment);
221 // Note: URL::GetHash() includes the "#" and we want the fragment with out
222 // the hash symbol.
223 if (!fragment.IsEmpty()) {
224 CopyUTF16toUTF8(Substring(fragment, 1), aURLfragment);
227 url->SetHash(u""_ns);
228 url->GetHref(aRequestURL);
231 class ReferrerSameOriginChecker final : public WorkerMainThreadRunnable {
232 public:
233 ReferrerSameOriginChecker(WorkerPrivate* aWorkerPrivate,
234 const nsAString& aReferrerURL, nsresult& aResult)
235 : WorkerMainThreadRunnable(aWorkerPrivate,
236 "Fetch :: Referrer same origin check"_ns),
237 mReferrerURL(aReferrerURL),
238 mResult(aResult) {
239 mWorkerPrivate->AssertIsOnWorkerThread();
242 bool MainThreadRun() override {
243 nsCOMPtr<nsIURI> uri;
244 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), mReferrerURL))) {
245 nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal();
246 if (principal) {
247 mResult = principal->CheckMayLoad(uri,
248 /* allowIfInheritsPrincipal */ false);
251 return true;
254 private:
255 const nsString mReferrerURL;
256 nsresult& mResult;
259 } // namespace
261 /*static*/
262 SafeRefPtr<Request> Request::Constructor(const GlobalObject& aGlobal,
263 const RequestOrUSVString& aInput,
264 const RequestInit& aInit,
265 ErrorResult& aRv) {
266 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
267 return Constructor(global, aGlobal.Context(), aInput, aInit, aRv);
270 /*static*/
271 SafeRefPtr<Request> Request::Constructor(nsIGlobalObject* aGlobal,
272 JSContext* aCx,
273 const RequestOrUSVString& aInput,
274 const RequestInit& aInit,
275 ErrorResult& aRv) {
276 bool hasCopiedBody = false;
277 SafeRefPtr<InternalRequest> request;
279 RefPtr<AbortSignal> signal;
281 if (aInput.IsRequest()) {
282 RefPtr<Request> inputReq = &aInput.GetAsRequest();
283 nsCOMPtr<nsIInputStream> body;
284 inputReq->GetBody(getter_AddRefs(body));
285 bool used = inputReq->GetBodyUsed(aRv);
286 if (NS_WARN_IF(aRv.Failed())) {
287 return nullptr;
289 if (used) {
290 aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
291 return nullptr;
294 // The body will be copied when GetRequestConstructorCopy() is executed.
295 if (body) {
296 hasCopiedBody = true;
299 request = inputReq->GetInternalRequest();
300 signal = inputReq->GetOrCreateSignal();
301 } else {
302 // aInput is USVString.
303 // We need to get url before we create a InternalRequest.
304 nsAutoString input;
305 input.Assign(aInput.GetAsUSVString());
306 nsAutoString requestURL;
307 nsCString fragment;
308 if (NS_IsMainThread()) {
309 nsCOMPtr<nsPIDOMWindowInner> inner(do_QueryInterface(aGlobal));
310 Document* doc = inner ? inner->GetExtantDoc() : nullptr;
311 if (doc) {
312 GetRequestURLFromDocument(doc, input, requestURL, fragment, aRv);
313 } else {
314 // If we don't have a document, we must assume that this is a full URL.
315 GetRequestURLFromChrome(input, requestURL, fragment, aRv);
317 } else {
318 GetRequestURLFromWorker(aGlobal, input, requestURL, fragment, aRv);
320 if (aRv.Failed()) {
321 return nullptr;
323 request = MakeSafeRefPtr<InternalRequest>(NS_ConvertUTF16toUTF8(requestURL),
324 fragment);
326 request = request->GetRequestConstructorCopy(aGlobal, aRv);
327 if (NS_WARN_IF(aRv.Failed())) {
328 return nullptr;
330 RequestMode fallbackMode = RequestMode::EndGuard_;
331 RequestCredentials fallbackCredentials = RequestCredentials::EndGuard_;
332 RequestCache fallbackCache = RequestCache::EndGuard_;
333 if (aInput.IsUSVString()) {
334 fallbackMode = RequestMode::Cors;
335 fallbackCredentials = RequestCredentials::Same_origin;
336 fallbackCache = RequestCache::Default;
339 RequestMode mode =
340 aInit.mMode.WasPassed() ? aInit.mMode.Value() : fallbackMode;
341 RequestCredentials credentials = aInit.mCredentials.WasPassed()
342 ? aInit.mCredentials.Value()
343 : fallbackCredentials;
345 if (mode == RequestMode::Navigate) {
346 aRv.ThrowTypeError<MSG_INVALID_REQUEST_MODE>("navigate");
347 return nullptr;
349 if (aInit.IsAnyMemberPresent() && request->Mode() == RequestMode::Navigate) {
350 mode = RequestMode::Same_origin;
353 if (aInit.IsAnyMemberPresent()) {
354 request->SetReferrer(
355 NS_LITERAL_STRING_FROM_CSTRING(kFETCH_CLIENT_REFERRER_STR));
356 request->SetReferrerPolicy(ReferrerPolicy::_empty);
358 if (aInit.mReferrer.WasPassed()) {
359 const nsString& referrer = aInit.mReferrer.Value();
360 if (referrer.IsEmpty()) {
361 request->SetReferrer(u""_ns);
362 } else {
363 nsAutoString referrerURL;
364 if (NS_IsMainThread()) {
365 nsCOMPtr<nsPIDOMWindowInner> inner(do_QueryInterface(aGlobal));
366 Document* doc = inner ? inner->GetExtantDoc() : nullptr;
367 nsCOMPtr<nsIURI> uri;
368 if (doc) {
369 uri = ParseURLFromDocument(doc, referrer, aRv);
370 } else {
371 // If we don't have a document, we must assume that this is a full
372 // URL.
373 uri = ParseURLFromChrome(referrer, aRv);
375 if (NS_WARN_IF(aRv.Failed())) {
376 aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(
377 NS_ConvertUTF16toUTF8(referrer));
378 return nullptr;
380 nsAutoCString spec;
381 uri->GetSpec(spec);
382 CopyUTF8toUTF16(spec, referrerURL);
383 if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
384 nsCOMPtr<nsIPrincipal> principal = aGlobal->PrincipalOrNull();
385 if (principal) {
386 nsresult rv =
387 principal->CheckMayLoad(uri,
388 /* allowIfInheritsPrincipal */ false);
389 if (NS_FAILED(rv)) {
390 referrerURL.AssignLiteral(kFETCH_CLIENT_REFERRER_STR);
394 } else {
395 RefPtr<URL> url = ParseURLFromWorker(aGlobal, referrer, aRv);
396 if (NS_WARN_IF(aRv.Failed())) {
397 aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(
398 NS_ConvertUTF16toUTF8(referrer));
399 return nullptr;
401 url->GetHref(referrerURL);
402 if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
403 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
404 nsresult rv = NS_OK;
405 // ReferrerSameOriginChecker uses a sync loop to get the main thread
406 // to perform the same-origin check. Overall, on Workers this method
407 // can create 3 sync loops (two for constructing URLs and one here) so
408 // in the future we may want to optimize it all by off-loading all of
409 // this work in a single sync loop.
410 RefPtr<ReferrerSameOriginChecker> checker =
411 new ReferrerSameOriginChecker(worker, referrerURL, rv);
412 IgnoredErrorResult error;
413 checker->Dispatch(Canceling, error);
414 if (error.Failed() || NS_FAILED(rv)) {
415 referrerURL.AssignLiteral(kFETCH_CLIENT_REFERRER_STR);
419 request->SetReferrer(referrerURL);
423 if (aInit.mReferrerPolicy.WasPassed()) {
424 request->SetReferrerPolicy(aInit.mReferrerPolicy.Value());
427 if (aInit.mSignal.WasPassed()) {
428 signal = aInit.mSignal.Value();
431 UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo;
432 nsILoadInfo::CrossOriginEmbedderPolicy coep =
433 nsILoadInfo::EMBEDDER_POLICY_NULL;
435 if (NS_IsMainThread()) {
436 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
437 if (window) {
438 nsCOMPtr<Document> doc;
439 doc = window->GetExtantDoc();
440 if (doc) {
441 request->SetEnvironmentReferrerPolicy(doc->GetReferrerPolicy());
443 principalInfo.reset(new mozilla::ipc::PrincipalInfo());
444 nsresult rv =
445 PrincipalToPrincipalInfo(doc->NodePrincipal(), principalInfo.get());
446 if (NS_WARN_IF(NS_FAILED(rv))) {
447 aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
448 return nullptr;
451 if (window->GetWindowContext()) {
452 coep = window->GetWindowContext()->GetEmbedderPolicy();
455 } else {
456 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
457 if (worker) {
458 worker->AssertIsOnWorkerThread();
459 request->SetEnvironmentReferrerPolicy(worker->GetReferrerPolicy());
460 principalInfo =
461 MakeUnique<mozilla::ipc::PrincipalInfo>(worker->GetPrincipalInfo());
462 coep = worker->GetEmbedderPolicy();
463 // For dedicated worker, the response must respect the owner's COEP.
464 if (coep == nsILoadInfo::EMBEDDER_POLICY_NULL &&
465 worker->IsDedicatedWorker()) {
466 coep = worker->GetOwnerEmbedderPolicy();
471 request->SetPrincipalInfo(std::move(principalInfo));
472 request->SetEmbedderPolicy(coep);
474 if (mode != RequestMode::EndGuard_) {
475 request->SetMode(mode);
478 if (credentials != RequestCredentials::EndGuard_) {
479 request->SetCredentialsMode(credentials);
482 RequestCache cache =
483 aInit.mCache.WasPassed() ? aInit.mCache.Value() : fallbackCache;
484 if (cache != RequestCache::EndGuard_) {
485 if (cache == RequestCache::Only_if_cached &&
486 request->Mode() != RequestMode::Same_origin) {
487 nsCString modeString(RequestModeValues::GetString(request->Mode()));
488 aRv.ThrowTypeError<MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN>(modeString);
489 return nullptr;
491 request->SetCacheMode(cache);
494 if (aInit.mRedirect.WasPassed()) {
495 request->SetRedirectMode(aInit.mRedirect.Value());
498 if (aInit.mIntegrity.WasPassed()) {
499 request->SetIntegrity(aInit.mIntegrity.Value());
502 if (aInit.mMozErrors.WasPassed() && aInit.mMozErrors.Value()) {
503 request->SetMozErrors();
506 // Request constructor step 14.
507 if (aInit.mMethod.WasPassed()) {
508 nsAutoCString method(aInit.mMethod.Value());
510 // Step 14.1. Disallow forbidden methods, and anything that is not a HTTP
511 // token, since HTTP states that Method may be any of the defined values or
512 // a token (extension method).
513 nsAutoCString outMethod;
514 nsresult rv = FetchUtil::GetValidRequestMethod(method, outMethod);
515 if (NS_FAILED(rv)) {
516 aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(method);
517 return nullptr;
520 // Step 14.2
521 request->SetMethod(outMethod);
524 RefPtr<InternalHeaders> requestHeaders = request->Headers();
526 RefPtr<InternalHeaders> headers;
527 if (aInit.mHeaders.WasPassed()) {
528 RefPtr<Headers> h = Headers::Create(aGlobal, aInit.mHeaders.Value(), aRv);
529 if (aRv.Failed()) {
530 return nullptr;
532 headers = h->GetInternalHeaders();
533 } else {
534 headers = new InternalHeaders(*requestHeaders);
537 requestHeaders->Clear();
538 // From "Let r be a new Request object associated with request and a new
539 // Headers object whose guard is "request"."
540 requestHeaders->SetGuard(HeadersGuardEnum::Request, aRv);
541 MOZ_ASSERT(!aRv.Failed());
543 if (request->Mode() == RequestMode::No_cors) {
544 if (!request->HasSimpleMethod()) {
545 nsAutoCString method;
546 request->GetMethod(method);
547 aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(method);
548 return nullptr;
551 requestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
552 if (aRv.Failed()) {
553 return nullptr;
557 requestHeaders->Fill(*headers, aRv);
558 if (aRv.Failed()) {
559 return nullptr;
562 if ((aInit.mBody.WasPassed() && !aInit.mBody.Value().IsNull()) ||
563 hasCopiedBody) {
564 // HEAD and GET are not allowed to have a body.
565 nsAutoCString method;
566 request->GetMethod(method);
567 // method is guaranteed to be uppercase due to step 14.2 above.
568 if (method.EqualsLiteral("HEAD") || method.EqualsLiteral("GET")) {
569 aRv.ThrowTypeError("HEAD or GET Request cannot have a body.");
570 return nullptr;
574 if (aInit.mBody.WasPassed()) {
575 const Nullable<fetch::OwningBodyInit>& bodyInitNullable =
576 aInit.mBody.Value();
577 if (!bodyInitNullable.IsNull()) {
578 const fetch::OwningBodyInit& bodyInit = bodyInitNullable.Value();
579 nsCOMPtr<nsIInputStream> stream;
580 nsAutoCString contentTypeWithCharset;
581 uint64_t contentLength = 0;
582 aRv = ExtractByteStreamFromBody(bodyInit, getter_AddRefs(stream),
583 contentTypeWithCharset, contentLength);
584 if (NS_WARN_IF(aRv.Failed())) {
585 return nullptr;
588 nsCOMPtr<nsIInputStream> temporaryBody = stream;
590 if (!contentTypeWithCharset.IsVoid() &&
591 !requestHeaders->Has("Content-Type"_ns, aRv)) {
592 requestHeaders->Append("Content-Type"_ns, contentTypeWithCharset, aRv);
595 if (NS_WARN_IF(aRv.Failed())) {
596 return nullptr;
599 if (hasCopiedBody) {
600 request->SetBody(nullptr, 0);
603 request->SetBody(temporaryBody, contentLength);
607 auto domRequest =
608 MakeSafeRefPtr<Request>(aGlobal, std::move(request), signal);
610 if (aInput.IsRequest()) {
611 RefPtr<Request> inputReq = &aInput.GetAsRequest();
612 nsCOMPtr<nsIInputStream> body;
613 inputReq->GetBody(getter_AddRefs(body));
614 if (body) {
615 inputReq->SetBody(nullptr, 0);
616 inputReq->SetBodyUsed(aCx, aRv);
617 if (NS_WARN_IF(aRv.Failed())) {
618 return nullptr;
622 return domRequest;
625 SafeRefPtr<Request> Request::Clone(ErrorResult& aRv) {
626 bool used = GetBodyUsed(aRv);
627 if (NS_WARN_IF(aRv.Failed())) {
628 return nullptr;
630 if (used) {
631 aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
632 return nullptr;
635 SafeRefPtr<InternalRequest> ir = mRequest->Clone();
636 if (!ir) {
637 aRv.Throw(NS_ERROR_FAILURE);
638 return nullptr;
641 return MakeSafeRefPtr<Request>(mOwner, std::move(ir), GetOrCreateSignal());
644 Headers* Request::Headers_() {
645 if (!mHeaders) {
646 mHeaders = new Headers(mOwner, mRequest->Headers());
649 return mHeaders;
652 AbortSignal* Request::GetOrCreateSignal() {
653 if (!mSignal) {
654 mSignal = new AbortSignal(mOwner, false);
657 return mSignal;
660 AbortSignalImpl* Request::GetSignalImpl() const { return mSignal; }
662 } // namespace mozilla::dom