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