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 "InternalRequest.h"
8 
9 #include "nsIContentPolicy.h"
10 #include "nsIDocument.h"
11 #include "nsStreamUtils.h"
12 
13 #include "mozilla/ErrorResult.h"
14 #include "mozilla/dom/FetchTypes.h"
15 #include "mozilla/dom/ScriptSettings.h"
16 
17 #include "mozilla/dom/WorkerCommon.h"
18 #include "mozilla/dom/WorkerPrivate.h"
19 
20 namespace mozilla {
21 namespace dom {
22 // The global is used to extract the principal.
GetRequestConstructorCopy(nsIGlobalObject * aGlobal,ErrorResult & aRv) const23 already_AddRefed<InternalRequest> InternalRequest::GetRequestConstructorCopy(
24     nsIGlobalObject* aGlobal, ErrorResult& aRv) const {
25   MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(),
26                      "Internal Request's urlList should not be empty when "
27                      "copied from constructor.");
28   RefPtr<InternalRequest> copy =
29       new InternalRequest(mURLList.LastElement(), mFragment);
30   copy->SetMethod(mMethod);
31   copy->mHeaders = new InternalHeaders(*mHeaders);
32   copy->SetUnsafeRequest();
33   copy->mBodyStream = mBodyStream;
34   copy->mBodyLength = mBodyLength;
35   copy->mForceOriginHeader = true;
36   // The "client" is not stored in our implementation. Fetch API users should
37   // use the appropriate window/document/principal and other Gecko security
38   // mechanisms as appropriate.
39   copy->mSameOriginDataURL = true;
40   copy->mPreserveContentCodings = true;
41   copy->mReferrer = mReferrer;
42   copy->mReferrerPolicy = mReferrerPolicy;
43   copy->mEnvironmentReferrerPolicy = mEnvironmentReferrerPolicy;
44   copy->mIntegrity = mIntegrity;
45   copy->mMozErrors = mMozErrors;
46 
47   copy->mContentPolicyType = mContentPolicyTypeOverridden
48                                  ? mContentPolicyType
49                                  : nsIContentPolicy::TYPE_FETCH;
50   copy->mMode = mMode;
51   copy->mCredentialsMode = mCredentialsMode;
52   copy->mCacheMode = mCacheMode;
53   copy->mRedirectMode = mRedirectMode;
54   copy->mCreatedByFetchEvent = mCreatedByFetchEvent;
55   copy->mContentPolicyTypeOverridden = mContentPolicyTypeOverridden;
56 
57   copy->mPreferredAlternativeDataType = mPreferredAlternativeDataType;
58   return copy.forget();
59 }
60 
Clone()61 already_AddRefed<InternalRequest> InternalRequest::Clone() {
62   RefPtr<InternalRequest> clone = new InternalRequest(*this);
63 
64   if (!mBodyStream) {
65     return clone.forget();
66   }
67 
68   nsCOMPtr<nsIInputStream> clonedBody;
69   nsCOMPtr<nsIInputStream> replacementBody;
70 
71   nsresult rv = NS_CloneInputStream(mBodyStream, getter_AddRefs(clonedBody),
72                                     getter_AddRefs(replacementBody));
73   if (NS_WARN_IF(NS_FAILED(rv))) {
74     return nullptr;
75   }
76 
77   clone->mBodyStream.swap(clonedBody);
78   if (replacementBody) {
79     mBodyStream.swap(replacementBody);
80   }
81   return clone.forget();
82 }
InternalRequest(const nsACString & aURL,const nsACString & aFragment)83 InternalRequest::InternalRequest(const nsACString& aURL,
84                                  const nsACString& aFragment)
85     : mMethod("GET"),
86       mHeaders(new InternalHeaders(HeadersGuardEnum::None)),
87       mBodyLength(InternalResponse::UNKNOWN_BODY_SIZE),
88       mContentPolicyType(nsIContentPolicy::TYPE_FETCH),
89       mReferrer(NS_LITERAL_STRING(kFETCH_CLIENT_REFERRER_STR)),
90       mReferrerPolicy(ReferrerPolicy::_empty),
91       mEnvironmentReferrerPolicy(net::RP_Unset),
92       mMode(RequestMode::No_cors),
93       mCredentialsMode(RequestCredentials::Omit),
94       mResponseTainting(LoadTainting::Basic),
95       mCacheMode(RequestCache::Default),
96       mRedirectMode(RequestRedirect::Follow),
97       mMozErrors(false),
98       mAuthenticationFlag(false),
99       mForceOriginHeader(false),
100       mPreserveContentCodings(false)
101       // FIXME(nsm): This should be false by default, but will lead to the
102       // algorithm never loading data: URLs right now. See Bug 1018872 about
103       // how certain contexts will override it to set it to true. Fetch
104       // specification does not handle this yet.
105       ,
106       mSameOriginDataURL(true),
107       mSkipServiceWorker(false),
108       mSynchronous(false),
109       mUnsafeRequest(false),
110       mUseURLCredentials(false) {
111   MOZ_ASSERT(!aURL.IsEmpty());
112   AddURL(aURL, aFragment);
113 }
InternalRequest(const nsACString & aURL,const nsACString & aFragment,const nsACString & aMethod,already_AddRefed<InternalHeaders> aHeaders,RequestCache aCacheMode,RequestMode aMode,RequestRedirect aRequestRedirect,RequestCredentials aRequestCredentials,const nsAString & aReferrer,ReferrerPolicy aReferrerPolicy,nsContentPolicyType aContentPolicyType,const nsAString & aIntegrity)114 InternalRequest::InternalRequest(
115     const nsACString& aURL, const nsACString& aFragment,
116     const nsACString& aMethod, already_AddRefed<InternalHeaders> aHeaders,
117     RequestCache aCacheMode, RequestMode aMode,
118     RequestRedirect aRequestRedirect, RequestCredentials aRequestCredentials,
119     const nsAString& aReferrer, ReferrerPolicy aReferrerPolicy,
120     nsContentPolicyType aContentPolicyType, const nsAString& aIntegrity)
121     : mMethod(aMethod),
122       mHeaders(aHeaders),
123       mContentPolicyType(aContentPolicyType),
124       mReferrer(aReferrer),
125       mReferrerPolicy(aReferrerPolicy),
126       mEnvironmentReferrerPolicy(net::RP_Unset),
127       mMode(aMode),
128       mCredentialsMode(aRequestCredentials),
129       mResponseTainting(LoadTainting::Basic),
130       mCacheMode(aCacheMode),
131       mRedirectMode(aRequestRedirect),
132       mIntegrity(aIntegrity),
133       mMozErrors(false),
134       mAuthenticationFlag(false),
135       mForceOriginHeader(false),
136       mPreserveContentCodings(false)
137       // FIXME See the above comment in the default constructor.
138       ,
139       mSameOriginDataURL(true),
140       mSkipServiceWorker(false),
141       mSynchronous(false),
142       mUnsafeRequest(false),
143       mUseURLCredentials(false) {
144   MOZ_ASSERT(!aURL.IsEmpty());
145   AddURL(aURL, aFragment);
146 }
InternalRequest(const InternalRequest & aOther)147 InternalRequest::InternalRequest(const InternalRequest& aOther)
148     : mMethod(aOther.mMethod),
149       mURLList(aOther.mURLList),
150       mHeaders(new InternalHeaders(*aOther.mHeaders)),
151       mBodyLength(InternalResponse::UNKNOWN_BODY_SIZE),
152       mContentPolicyType(aOther.mContentPolicyType),
153       mReferrer(aOther.mReferrer),
154       mReferrerPolicy(aOther.mReferrerPolicy),
155       mEnvironmentReferrerPolicy(aOther.mEnvironmentReferrerPolicy),
156       mMode(aOther.mMode),
157       mCredentialsMode(aOther.mCredentialsMode),
158       mResponseTainting(aOther.mResponseTainting),
159       mCacheMode(aOther.mCacheMode),
160       mRedirectMode(aOther.mRedirectMode),
161       mIntegrity(aOther.mIntegrity),
162       mMozErrors(aOther.mMozErrors),
163       mFragment(aOther.mFragment),
164       mAuthenticationFlag(aOther.mAuthenticationFlag),
165       mForceOriginHeader(aOther.mForceOriginHeader),
166       mPreserveContentCodings(aOther.mPreserveContentCodings),
167       mSameOriginDataURL(aOther.mSameOriginDataURL),
168       mSkipServiceWorker(aOther.mSkipServiceWorker),
169       mSynchronous(aOther.mSynchronous),
170       mUnsafeRequest(aOther.mUnsafeRequest),
171       mUseURLCredentials(aOther.mUseURLCredentials),
172       mCreatedByFetchEvent(aOther.mCreatedByFetchEvent),
173       mContentPolicyTypeOverridden(aOther.mContentPolicyTypeOverridden) {
174   // NOTE: does not copy body stream... use the fallible Clone() for that
175 }
176 
InternalRequest(const IPCInternalRequest & aIPCRequest)177 InternalRequest::InternalRequest(const IPCInternalRequest& aIPCRequest)
178     : mMethod(aIPCRequest.method()),
179       mURLList(aIPCRequest.urls()),
180       mHeaders(new InternalHeaders(aIPCRequest.headers(),
181                                    aIPCRequest.headersGuard())),
182       mContentPolicyType(aIPCRequest.contentPolicyType()),
183       mReferrer(aIPCRequest.referrer()),
184       mReferrerPolicy(aIPCRequest.referrerPolicy()),
185       mMode(aIPCRequest.mode()),
186       mCredentialsMode(aIPCRequest.credentials()),
187       mCacheMode(aIPCRequest.requestCache()),
188       mRedirectMode(aIPCRequest.requestRedirect()) {
189   MOZ_ASSERT(!mURLList.IsEmpty());
190 }
191 
~InternalRequest()192 InternalRequest::~InternalRequest() {}
193 
ToIPC(IPCInternalRequest * aIPCRequest)194 void InternalRequest::ToIPC(IPCInternalRequest* aIPCRequest) {
195   MOZ_ASSERT(aIPCRequest);
196   MOZ_ASSERT(!mURLList.IsEmpty());
197   aIPCRequest->urls() = mURLList;
198   aIPCRequest->method() = mMethod;
199 
200   mHeaders->ToIPC(aIPCRequest->headers(), aIPCRequest->headersGuard());
201 
202   aIPCRequest->referrer() = mReferrer;
203   aIPCRequest->referrerPolicy() = mReferrerPolicy;
204   aIPCRequest->mode() = mMode;
205   aIPCRequest->credentials() = mCredentialsMode;
206   aIPCRequest->contentPolicyType() = mContentPolicyType;
207   aIPCRequest->requestCache() = mCacheMode;
208   aIPCRequest->requestRedirect() = mRedirectMode;
209 }
210 
SetContentPolicyType(nsContentPolicyType aContentPolicyType)211 void InternalRequest::SetContentPolicyType(
212     nsContentPolicyType aContentPolicyType) {
213   mContentPolicyType = aContentPolicyType;
214 }
215 
OverrideContentPolicyType(nsContentPolicyType aContentPolicyType)216 void InternalRequest::OverrideContentPolicyType(
217     nsContentPolicyType aContentPolicyType) {
218   SetContentPolicyType(aContentPolicyType);
219   mContentPolicyTypeOverridden = true;
220 }
221 
222 /* static */
MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType)223 RequestContext InternalRequest::MapContentPolicyTypeToRequestContext(
224     nsContentPolicyType aContentPolicyType) {
225   RequestContext context = RequestContext::Internal;
226   switch (aContentPolicyType) {
227     case nsIContentPolicy::TYPE_OTHER:
228       context = RequestContext::Internal;
229       break;
230     case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
231     case nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD:
232     case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
233     case nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS:
234       context = RequestContext::Script;
235       break;
236     case nsIContentPolicy::TYPE_INTERNAL_WORKER:
237       context = RequestContext::Worker;
238       break;
239     case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
240       context = RequestContext::Sharedworker;
241       break;
242     case nsIContentPolicy::TYPE_INTERNAL_IMAGE:
243     case nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD:
244     case nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON:
245       context = RequestContext::Image;
246       break;
247     case nsIContentPolicy::TYPE_INTERNAL_STYLESHEET:
248     case nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD:
249       context = RequestContext::Style;
250       break;
251     case nsIContentPolicy::TYPE_INTERNAL_OBJECT:
252       context = RequestContext::Object;
253       break;
254     case nsIContentPolicy::TYPE_INTERNAL_EMBED:
255       context = RequestContext::Embed;
256       break;
257     case nsIContentPolicy::TYPE_DOCUMENT:
258       context = RequestContext::Internal;
259       break;
260     case nsIContentPolicy::TYPE_INTERNAL_IFRAME:
261       context = RequestContext::Iframe;
262       break;
263     case nsIContentPolicy::TYPE_INTERNAL_FRAME:
264       context = RequestContext::Frame;
265       break;
266     case nsIContentPolicy::TYPE_REFRESH:
267       context = RequestContext::Internal;
268       break;
269     case nsIContentPolicy::TYPE_XBL:
270       context = RequestContext::Internal;
271       break;
272     case nsIContentPolicy::TYPE_PING:
273       context = RequestContext::Ping;
274       break;
275     case nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST:
276       context = RequestContext::Xmlhttprequest;
277       break;
278     case nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE:
279       context = RequestContext::Eventsource;
280       break;
281     case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST:
282       context = RequestContext::Plugin;
283       break;
284     case nsIContentPolicy::TYPE_DTD:
285       context = RequestContext::Internal;
286       break;
287     case nsIContentPolicy::TYPE_FONT:
288       context = RequestContext::Font;
289       break;
290     case nsIContentPolicy::TYPE_INTERNAL_AUDIO:
291       context = RequestContext::Audio;
292       break;
293     case nsIContentPolicy::TYPE_INTERNAL_VIDEO:
294       context = RequestContext::Video;
295       break;
296     case nsIContentPolicy::TYPE_INTERNAL_TRACK:
297       context = RequestContext::Track;
298       break;
299     case nsIContentPolicy::TYPE_WEBSOCKET:
300       context = RequestContext::Internal;
301       break;
302     case nsIContentPolicy::TYPE_CSP_REPORT:
303       context = RequestContext::Cspreport;
304       break;
305     case nsIContentPolicy::TYPE_XSLT:
306       context = RequestContext::Xslt;
307       break;
308     case nsIContentPolicy::TYPE_BEACON:
309       context = RequestContext::Beacon;
310       break;
311     case nsIContentPolicy::TYPE_FETCH:
312       context = RequestContext::Fetch;
313       break;
314     case nsIContentPolicy::TYPE_IMAGESET:
315       context = RequestContext::Imageset;
316       break;
317     case nsIContentPolicy::TYPE_WEB_MANIFEST:
318       context = RequestContext::Manifest;
319       break;
320     case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD:
321       context = RequestContext::Internal;
322       break;
323     default:
324       MOZ_ASSERT(false, "Unhandled nsContentPolicyType value");
325       break;
326   }
327   return context;
328 }
329 
330 // static
IsNavigationContentPolicy(nsContentPolicyType aContentPolicyType)331 bool InternalRequest::IsNavigationContentPolicy(
332     nsContentPolicyType aContentPolicyType) {
333   // https://fetch.spec.whatwg.org/#navigation-request-context
334   //
335   // A navigation request context is one of "form", "frame", "hyperlink",
336   // "iframe", "internal" (as long as context frame type is not "none"),
337   // "location", "metarefresh", and "prerender".
338   //
339   // Note, all of these request types are effectively initiated by nsDocShell.
340   //
341   // The TYPE_REFRESH is used in some code paths for metarefresh, but will not
342   // be seen during the actual load.  Instead the new load gets a normal
343   // nsDocShell policy type.  We include it here in case this utility method
344   // is called before the load starts.
345   return aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
346          aContentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT ||
347          aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME ||
348          aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
349          aContentPolicyType == nsIContentPolicy::TYPE_REFRESH;
350 }
351 
352 // static
IsWorkerContentPolicy(nsContentPolicyType aContentPolicyType)353 bool InternalRequest::IsWorkerContentPolicy(
354     nsContentPolicyType aContentPolicyType) {
355   // https://fetch.spec.whatwg.org/#worker-request-context
356   //
357   // A worker request context is one of "serviceworker", "sharedworker", and
358   // "worker".
359   //
360   // Note, service workers are not included here because currently there is
361   // no way to generate a Request with a "serviceworker" RequestContext.
362   // ServiceWorker scripts cannot be intercepted.
363   return aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
364          aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
365 }
366 
IsNavigationRequest() const367 bool InternalRequest::IsNavigationRequest() const {
368   return IsNavigationContentPolicy(mContentPolicyType);
369 }
370 
IsWorkerRequest() const371 bool InternalRequest::IsWorkerRequest() const {
372   return IsWorkerContentPolicy(mContentPolicyType);
373 }
374 
IsClientRequest() const375 bool InternalRequest::IsClientRequest() const {
376   return IsNavigationRequest() || IsWorkerRequest();
377 }
378 
379 // static
MapChannelToRequestMode(nsIChannel * aChannel)380 RequestMode InternalRequest::MapChannelToRequestMode(nsIChannel* aChannel) {
381   MOZ_ASSERT(aChannel);
382 
383   nsCOMPtr<nsILoadInfo> loadInfo;
384   MOZ_ALWAYS_SUCCEEDS(aChannel->GetLoadInfo(getter_AddRefs(loadInfo)));
385 
386   nsContentPolicyType contentPolicy = loadInfo->InternalContentPolicyType();
387   if (IsNavigationContentPolicy(contentPolicy)) {
388     return RequestMode::Navigate;
389   }
390 
391   // TODO: remove the worker override once securityMode is fully implemented
392   // (bug 1189945)
393   if (IsWorkerContentPolicy(contentPolicy)) {
394     return RequestMode::Same_origin;
395   }
396 
397   uint32_t securityMode = loadInfo->GetSecurityMode();
398 
399   switch (securityMode) {
400     case nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS:
401     case nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED:
402       return RequestMode::Same_origin;
403     case nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS:
404     case nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL:
405       return RequestMode::No_cors;
406     case nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS:
407       // TODO: Check additional flag force-preflight after bug 1199693 (bug
408       // 1189945)
409       return RequestMode::Cors;
410     default:
411       MOZ_ASSERT_UNREACHABLE("Unexpected security mode!");
412       return RequestMode::Same_origin;
413   }
414 }
415 
416 // static
MapChannelToRequestCredentials(nsIChannel * aChannel)417 RequestCredentials InternalRequest::MapChannelToRequestCredentials(
418     nsIChannel* aChannel) {
419   MOZ_ASSERT(aChannel);
420 
421   nsCOMPtr<nsILoadInfo> loadInfo;
422   MOZ_ALWAYS_SUCCEEDS(aChannel->GetLoadInfo(getter_AddRefs(loadInfo)));
423 
424   uint32_t cookiePolicy = loadInfo->GetCookiePolicy();
425 
426   if (cookiePolicy == nsILoadInfo::SEC_COOKIES_INCLUDE) {
427     return RequestCredentials::Include;
428   } else if (cookiePolicy == nsILoadInfo::SEC_COOKIES_OMIT) {
429     return RequestCredentials::Omit;
430   } else if (cookiePolicy == nsILoadInfo::SEC_COOKIES_SAME_ORIGIN) {
431     return RequestCredentials::Same_origin;
432   }
433 
434   MOZ_ASSERT_UNREACHABLE("Unexpected cookie policy!");
435   return RequestCredentials::Same_origin;
436 }
437 
MaybeSkipCacheIfPerformingRevalidation()438 void InternalRequest::MaybeSkipCacheIfPerformingRevalidation() {
439   if (mCacheMode == RequestCache::Default &&
440       mHeaders->HasRevalidationHeaders()) {
441     mCacheMode = RequestCache::No_store;
442   }
443 }
444 
SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo)445 void InternalRequest::SetPrincipalInfo(
446     UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo) {
447   mPrincipalInfo = Move(aPrincipalInfo);
448 }
449 
450 }  // namespace dom
451 }  // namespace mozilla
452