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 : #ifndef mozilla_dom_InternalRequest_h
8 : #define mozilla_dom_InternalRequest_h
9 :
10 : #include "mozilla/dom/HeadersBinding.h"
11 : #include "mozilla/dom/InternalHeaders.h"
12 : #include "mozilla/dom/RequestBinding.h"
13 : #include "mozilla/LoadTainting.h"
14 : #include "mozilla/net/ReferrerPolicy.h"
15 :
16 : #include "nsIContentPolicy.h"
17 : #include "nsIInputStream.h"
18 : #include "nsISupportsImpl.h"
19 : #ifdef DEBUG
20 : #include "nsIURLParser.h"
21 : #include "nsNetCID.h"
22 : #include "nsServiceManagerUtils.h"
23 : #endif
24 :
25 : namespace mozilla {
26 :
27 : namespace ipc {
28 : class PrincipalInfo;
29 : } // namespace ipc
30 :
31 : namespace dom {
32 :
33 : /*
34 : * The mapping of RequestContext and nsContentPolicyType is currently as the
35 : * following. Note that this mapping is not perfect yet (see the TODO comments
36 : * below for examples).
37 : *
38 : * RequestContext | nsContentPolicyType
39 : * ------------------+--------------------
40 : * audio | TYPE_INTERNAL_AUDIO
41 : * beacon | TYPE_BEACON
42 : * cspreport | TYPE_CSP_REPORT
43 : * download |
44 : * embed | TYPE_INTERNAL_EMBED
45 : * eventsource |
46 : * favicon |
47 : * fetch | TYPE_FETCH
48 : * font | TYPE_FONT
49 : * form |
50 : * frame | TYPE_INTERNAL_FRAME
51 : * hyperlink |
52 : * iframe | TYPE_INTERNAL_IFRAME
53 : * image | TYPE_INTERNAL_IMAGE, TYPE_INTERNAL_IMAGE_PRELOAD, TYPE_INTERNAL_IMAGE_FAVICON
54 : * imageset | TYPE_IMAGESET
55 : * import | Not supported by Gecko
56 : * internal | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
57 : * location |
58 : * manifest | TYPE_WEB_MANIFEST
59 : * object | TYPE_INTERNAL_OBJECT
60 : * ping | TYPE_PING
61 : * plugin | TYPE_OBJECT_SUBREQUEST
62 : * prefetch |
63 : * script | TYPE_INTERNAL_SCRIPT, TYPE_INTERNAL_SCRIPT_PRELOAD
64 : * sharedworker | TYPE_INTERNAL_SHARED_WORKER
65 : * subresource | Not supported by Gecko
66 : * style | TYPE_INTERNAL_STYLESHEET, TYPE_INTERNAL_STYLESHEET_PRELOAD
67 : * track | TYPE_INTERNAL_TRACK
68 : * video | TYPE_INTERNAL_VIDEO
69 : * worker | TYPE_INTERNAL_WORKER
70 : * xmlhttprequest | TYPE_INTERNAL_XMLHTTPREQUEST
71 : * eventsource | TYPE_INTERNAL_EVENTSOURCE
72 : * xslt | TYPE_XSLT
73 : *
74 : * TODO: Figure out if TYPE_REFRESH maps to anything useful
75 : * TODO: Figure out if TYPE_DTD maps to anything useful
76 : * TODO: Figure out if TYPE_WEBSOCKET maps to anything useful
77 : * TODO: Add a content type for prefetch
78 : * TODO: Use the content type for manifest when it becomes available
79 : * TODO: Add a content type for location
80 : * TODO: Add a content type for hyperlink
81 : * TODO: Add a content type for form
82 : * TODO: Add a content type for favicon
83 : * TODO: Add a content type for download
84 : */
85 :
86 : class Request;
87 : class IPCInternalRequest;
88 :
89 : #define kFETCH_CLIENT_REFERRER_STR "about:client"
90 : class InternalRequest final
91 : {
92 : friend class Request;
93 : public:
94 12 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalRequest)
95 : InternalRequest(const nsACString& aURL, const nsACString& aFragment);
96 : InternalRequest(const nsACString& aURL,
97 : const nsACString& aFragment,
98 : const nsACString& aMethod,
99 : already_AddRefed<InternalHeaders> aHeaders,
100 : RequestCache aCacheMode,
101 : RequestMode aMode,
102 : RequestRedirect aRequestRedirect,
103 : RequestCredentials aRequestCredentials,
104 : const nsAString& aReferrer,
105 : ReferrerPolicy aReferrerPolicy,
106 : nsContentPolicyType aContentPolicyType,
107 : const nsAString& aIntegrity);
108 :
109 : explicit InternalRequest(const IPCInternalRequest& aIPCRequest);
110 :
111 : void ToIPC(IPCInternalRequest* aIPCRequest);
112 :
113 : already_AddRefed<InternalRequest> Clone();
114 :
115 : void
116 0 : GetMethod(nsCString& aMethod) const
117 : {
118 0 : aMethod.Assign(mMethod);
119 0 : }
120 :
121 : void
122 1 : SetMethod(const nsACString& aMethod)
123 : {
124 1 : mMethod.Assign(aMethod);
125 1 : }
126 :
127 : bool
128 0 : HasSimpleMethod() const
129 : {
130 0 : return mMethod.LowerCaseEqualsASCII("get") ||
131 0 : mMethod.LowerCaseEqualsASCII("post") ||
132 0 : mMethod.LowerCaseEqualsASCII("head");
133 : }
134 : // GetURL should get the request's current url with fragment. A request has
135 : // an associated current url. It is a pointer to the last fetch URL in
136 : // request's url list.
137 : void
138 1 : GetURL(nsACString& aURL) const
139 : {
140 1 : aURL.Assign(GetURLWithoutFragment());
141 1 : if (GetFragment().IsEmpty()) {
142 1 : return;
143 : }
144 0 : aURL.Append(NS_LITERAL_CSTRING("#"));
145 0 : aURL.Append(GetFragment());
146 : }
147 :
148 : const nsCString&
149 1 : GetURLWithoutFragment() const
150 : {
151 1 : MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(),
152 : "Internal Request's urlList should not be empty.");
153 :
154 1 : return mURLList.LastElement();
155 : }
156 : // AddURL should append the url into url list.
157 : // Normally we strip the fragment from the URL in Request::Constructor and
158 : // pass the fragment as the second argument into it.
159 : // If a fragment is present in the URL it must be stripped and passed in
160 : // separately.
161 : void
162 2 : AddURL(const nsACString& aURL, const nsACString& aFragment)
163 : {
164 2 : MOZ_ASSERT(!aURL.IsEmpty());
165 2 : MOZ_ASSERT(!aURL.Contains('#'));
166 :
167 2 : mURLList.AppendElement(aURL);
168 :
169 2 : mFragment.Assign(aFragment);
170 2 : }
171 : // Get the URL list without their fragments.
172 : void
173 1 : GetURLListWithoutFragment(nsTArray<nsCString>& aURLList)
174 : {
175 1 : aURLList.Assign(mURLList);
176 1 : }
177 : void
178 0 : GetReferrer(nsAString& aReferrer) const
179 : {
180 0 : aReferrer.Assign(mReferrer);
181 0 : }
182 :
183 : void
184 0 : SetReferrer(const nsAString& aReferrer)
185 : {
186 : #ifdef DEBUG
187 0 : bool validReferrer = false;
188 0 : if (aReferrer.IsEmpty() ||
189 0 : aReferrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
190 0 : validReferrer = true;
191 : } else {
192 0 : nsCOMPtr<nsIURLParser> parser = do_GetService(NS_STDURLPARSER_CONTRACTID);
193 0 : if (!parser) {
194 0 : NS_WARNING("Could not get parser to validate URL!");
195 : } else {
196 : uint32_t schemePos;
197 : int32_t schemeLen;
198 : uint32_t authorityPos;
199 : int32_t authorityLen;
200 : uint32_t pathPos;
201 : int32_t pathLen;
202 :
203 0 : NS_ConvertUTF16toUTF8 ref(aReferrer);
204 0 : nsresult rv = parser->ParseURL(ref.get(), ref.Length(),
205 : &schemePos, &schemeLen,
206 : &authorityPos, &authorityLen,
207 0 : &pathPos, &pathLen);
208 0 : if (NS_FAILED(rv)) {
209 0 : NS_WARNING("Invalid referrer URL!");
210 0 : } else if (schemeLen < 0 || authorityLen < 0) {
211 0 : NS_WARNING("Invalid referrer URL!");
212 : } else {
213 0 : validReferrer = true;
214 : }
215 : }
216 : }
217 :
218 0 : MOZ_ASSERT(validReferrer);
219 : #endif
220 :
221 0 : mReferrer.Assign(aReferrer);
222 0 : }
223 :
224 : ReferrerPolicy
225 0 : ReferrerPolicy_() const
226 : {
227 0 : return mReferrerPolicy;
228 : }
229 :
230 : void
231 0 : SetReferrerPolicy(ReferrerPolicy aReferrerPolicy)
232 : {
233 0 : mReferrerPolicy = aReferrerPolicy;
234 0 : }
235 :
236 : void
237 0 : SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
238 : {
239 0 : switch (aReferrerPolicy) {
240 : case net::RP_Unset:
241 0 : mReferrerPolicy = ReferrerPolicy::_empty;
242 0 : break;
243 : case net::RP_No_Referrer:
244 0 : mReferrerPolicy = ReferrerPolicy::No_referrer;
245 0 : break;
246 : case net::RP_No_Referrer_When_Downgrade:
247 0 : mReferrerPolicy = ReferrerPolicy::No_referrer_when_downgrade;
248 0 : break;
249 : case net::RP_Origin:
250 0 : mReferrerPolicy = ReferrerPolicy::Origin;
251 0 : break;
252 : case net::RP_Origin_When_Crossorigin:
253 0 : mReferrerPolicy = ReferrerPolicy::Origin_when_cross_origin;
254 0 : break;
255 : case net::RP_Unsafe_URL:
256 0 : mReferrerPolicy = ReferrerPolicy::Unsafe_url;
257 0 : break;
258 : case net::RP_Same_Origin:
259 0 : mReferrerPolicy = ReferrerPolicy::Same_origin;
260 0 : break;
261 : case net::RP_Strict_Origin:
262 0 : mReferrerPolicy = ReferrerPolicy::Strict_origin;
263 0 : break;
264 : case net::RP_Strict_Origin_When_Cross_Origin:
265 0 : mReferrerPolicy = ReferrerPolicy::Strict_origin_when_cross_origin;
266 0 : break;
267 : default:
268 0 : MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value");
269 : break;
270 : }
271 0 : }
272 :
273 : net::ReferrerPolicy
274 0 : GetReferrerPolicy()
275 : {
276 0 : switch (mReferrerPolicy) {
277 : case ReferrerPolicy::_empty:
278 0 : return net::RP_Unset;
279 : case ReferrerPolicy::No_referrer:
280 0 : return net::RP_No_Referrer;
281 : case ReferrerPolicy::No_referrer_when_downgrade:
282 0 : return net::RP_No_Referrer_When_Downgrade;
283 : case ReferrerPolicy::Origin:
284 0 : return net::RP_Origin;
285 : case ReferrerPolicy::Origin_when_cross_origin:
286 0 : return net::RP_Origin_When_Crossorigin;
287 : case ReferrerPolicy::Unsafe_url:
288 0 : return net::RP_Unsafe_URL;
289 : case ReferrerPolicy::Strict_origin:
290 0 : return net::RP_Strict_Origin;
291 : case ReferrerPolicy::Same_origin:
292 0 : return net::RP_Same_Origin;
293 : case ReferrerPolicy::Strict_origin_when_cross_origin:
294 0 : return net::RP_Strict_Origin_When_Cross_Origin;
295 : default:
296 0 : MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
297 : break;
298 : }
299 : return net::RP_Unset;
300 : }
301 :
302 : net::ReferrerPolicy
303 0 : GetEnvironmentReferrerPolicy() const
304 : {
305 0 : return mEnvironmentReferrerPolicy;
306 : }
307 :
308 : void
309 0 : SetEnvironmentReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
310 : {
311 0 : mEnvironmentReferrerPolicy = aReferrerPolicy;
312 0 : }
313 :
314 : bool
315 1 : SkipServiceWorker() const
316 : {
317 1 : return mSkipServiceWorker;
318 : }
319 :
320 : void
321 0 : SetSkipServiceWorker()
322 : {
323 0 : mSkipServiceWorker = true;
324 0 : }
325 :
326 : bool
327 1 : IsSynchronous() const
328 : {
329 1 : return mSynchronous;
330 : }
331 :
332 : RequestMode
333 4 : Mode() const
334 : {
335 4 : return mMode;
336 : }
337 :
338 : void
339 1 : SetMode(RequestMode aMode)
340 : {
341 1 : mMode = aMode;
342 1 : }
343 :
344 : RequestCredentials
345 2 : GetCredentialsMode() const
346 : {
347 2 : return mCredentialsMode;
348 : }
349 :
350 : void
351 1 : SetCredentialsMode(RequestCredentials aCredentialsMode)
352 : {
353 1 : mCredentialsMode = aCredentialsMode;
354 1 : }
355 :
356 : LoadTainting
357 1 : GetResponseTainting() const
358 : {
359 1 : return mResponseTainting;
360 : }
361 :
362 : void
363 1 : MaybeIncreaseResponseTainting(LoadTainting aTainting)
364 : {
365 1 : if (aTainting > mResponseTainting) {
366 0 : mResponseTainting = aTainting;
367 : }
368 1 : }
369 :
370 : RequestCache
371 0 : GetCacheMode() const
372 : {
373 0 : return mCacheMode;
374 : }
375 :
376 : void
377 1 : SetCacheMode(RequestCache aCacheMode)
378 : {
379 1 : mCacheMode = aCacheMode;
380 1 : }
381 :
382 : RequestRedirect
383 1 : GetRedirectMode() const
384 : {
385 1 : return mRedirectMode;
386 : }
387 :
388 : void
389 0 : SetRedirectMode(RequestRedirect aRedirectMode)
390 : {
391 0 : mRedirectMode = aRedirectMode;
392 0 : }
393 :
394 : const nsString&
395 5 : GetIntegrity() const
396 : {
397 5 : return mIntegrity;
398 : }
399 : void
400 0 : SetIntegrity(const nsAString& aIntegrity)
401 : {
402 0 : MOZ_ASSERT(mIntegrity.IsEmpty());
403 0 : mIntegrity.Assign(aIntegrity);
404 0 : }
405 : const nsCString&
406 1 : GetFragment() const
407 : {
408 1 : return mFragment;
409 : }
410 :
411 : nsContentPolicyType
412 1 : ContentPolicyType() const
413 : {
414 1 : return mContentPolicyType;
415 : }
416 : void
417 : SetContentPolicyType(nsContentPolicyType aContentPolicyType);
418 :
419 : void
420 : OverrideContentPolicyType(nsContentPolicyType aContentPolicyType);
421 :
422 : RequestContext
423 0 : Context() const
424 : {
425 0 : return MapContentPolicyTypeToRequestContext(mContentPolicyType);
426 : }
427 :
428 : bool
429 0 : UnsafeRequest() const
430 : {
431 0 : return mUnsafeRequest;
432 : }
433 :
434 : void
435 1 : SetUnsafeRequest()
436 : {
437 1 : mUnsafeRequest = true;
438 1 : }
439 :
440 : InternalHeaders*
441 8 : Headers()
442 : {
443 8 : return mHeaders;
444 : }
445 :
446 : bool
447 0 : ForceOriginHeader()
448 : {
449 0 : return mForceOriginHeader;
450 : }
451 :
452 : bool
453 : SameOriginDataURL() const
454 : {
455 : return mSameOriginDataURL;
456 : }
457 :
458 : void
459 : UnsetSameOriginDataURL()
460 : {
461 : mSameOriginDataURL = false;
462 : }
463 :
464 : void
465 0 : SetBody(nsIInputStream* aStream)
466 : {
467 : // A request's body may not be reset once set.
468 0 : MOZ_ASSERT_IF(aStream, !mBodyStream);
469 0 : mBodyStream = aStream;
470 0 : }
471 :
472 : // Will return the original stream!
473 : // Use a tee or copy if you don't want to erase the original.
474 : void
475 0 : GetBody(nsIInputStream** aStream)
476 : {
477 0 : nsCOMPtr<nsIInputStream> s = mBodyStream;
478 0 : s.forget(aStream);
479 0 : }
480 :
481 : // The global is used as the client for the new object.
482 : already_AddRefed<InternalRequest>
483 : GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const;
484 :
485 : bool
486 1 : WasCreatedByFetchEvent() const
487 : {
488 1 : return mCreatedByFetchEvent;
489 : }
490 :
491 : void
492 0 : SetCreatedByFetchEvent()
493 : {
494 0 : mCreatedByFetchEvent = true;
495 0 : }
496 :
497 : void
498 3 : ClearCreatedByFetchEvent()
499 : {
500 3 : mCreatedByFetchEvent = false;
501 3 : }
502 :
503 : bool
504 : IsNavigationRequest() const;
505 :
506 : bool
507 : IsWorkerRequest() const;
508 :
509 : bool
510 : IsClientRequest() const;
511 :
512 : void
513 : MaybeSkipCacheIfPerformingRevalidation();
514 :
515 : bool
516 0 : IsContentPolicyTypeOverridden() const
517 : {
518 0 : return mContentPolicyTypeOverridden;
519 : }
520 :
521 : static RequestMode
522 : MapChannelToRequestMode(nsIChannel* aChannel);
523 :
524 : static RequestCredentials
525 : MapChannelToRequestCredentials(nsIChannel* aChannel);
526 :
527 : // Takes ownership of the principal info.
528 : void
529 : SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo);
530 :
531 : const UniquePtr<mozilla::ipc::PrincipalInfo>&
532 0 : GetPrincipalInfo() const
533 : {
534 0 : return mPrincipalInfo;
535 : }
536 :
537 : private:
538 : // Does not copy mBodyStream. Use fallible Clone() for complete copy.
539 : explicit InternalRequest(const InternalRequest& aOther);
540 :
541 : ~InternalRequest();
542 :
543 : static RequestContext
544 : MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType);
545 :
546 : static bool
547 : IsNavigationContentPolicy(nsContentPolicyType aContentPolicyType);
548 :
549 : static bool
550 : IsWorkerContentPolicy(nsContentPolicyType aContentPolicyType);
551 :
552 : nsCString mMethod;
553 : // mURLList: a list of one or more fetch URLs
554 : nsTArray<nsCString> mURLList;
555 : RefPtr<InternalHeaders> mHeaders;
556 : nsCOMPtr<nsIInputStream> mBodyStream;
557 :
558 : nsContentPolicyType mContentPolicyType;
559 :
560 : // Empty string: no-referrer
561 : // "about:client": client (default)
562 : // URL: an URL
563 : nsString mReferrer;
564 : ReferrerPolicy mReferrerPolicy;
565 :
566 : // This will be used for request created from Window or Worker contexts
567 : // In case there's no Referrer Policy in Request, this will be passed to
568 : // channel.
569 : // The Environment Referrer Policy should be net::ReferrerPolicy so that it
570 : // could be associated with nsIHttpChannel.
571 : net::ReferrerPolicy mEnvironmentReferrerPolicy;
572 : RequestMode mMode;
573 : RequestCredentials mCredentialsMode;
574 : MOZ_INIT_OUTSIDE_CTOR LoadTainting mResponseTainting;
575 : RequestCache mCacheMode;
576 : RequestRedirect mRedirectMode;
577 : nsString mIntegrity;
578 : nsCString mFragment;
579 : MOZ_INIT_OUTSIDE_CTOR bool mAuthenticationFlag;
580 : MOZ_INIT_OUTSIDE_CTOR bool mForceOriginHeader;
581 : MOZ_INIT_OUTSIDE_CTOR bool mPreserveContentCodings;
582 : MOZ_INIT_OUTSIDE_CTOR bool mSameOriginDataURL;
583 : MOZ_INIT_OUTSIDE_CTOR bool mSkipServiceWorker;
584 : MOZ_INIT_OUTSIDE_CTOR bool mSynchronous;
585 : MOZ_INIT_OUTSIDE_CTOR bool mUnsafeRequest;
586 : MOZ_INIT_OUTSIDE_CTOR bool mUseURLCredentials;
587 : // This is only set when a Request object is created by a fetch event. We
588 : // use it to check if Service Workers are simply fetching intercepted Request
589 : // objects without modifying them.
590 : bool mCreatedByFetchEvent = false;
591 : // This is only set when Request.overrideContentPolicyType() has been set.
592 : // It is illegal to pass such a Request object to a fetch() method unless
593 : // if the caller has chrome privileges.
594 : bool mContentPolicyTypeOverridden = false;
595 :
596 : UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
597 : };
598 :
599 : } // namespace dom
600 : } // namespace mozilla
601 :
602 : #endif // mozilla_dom_InternalRequest_h
|