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