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