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   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
GetMethod(nsCString & aMethod)116   GetMethod(nsCString& aMethod) const
117   {
118     aMethod.Assign(mMethod);
119   }
120 
121   void
SetMethod(const nsACString & aMethod)122   SetMethod(const nsACString& aMethod)
123   {
124     mMethod.Assign(aMethod);
125   }
126 
127   bool
HasSimpleMethod()128   HasSimpleMethod() const
129   {
130     return mMethod.LowerCaseEqualsASCII("get") ||
131            mMethod.LowerCaseEqualsASCII("post") ||
132            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
GetURL(nsACString & aURL)138   GetURL(nsACString& aURL) const
139   {
140     aURL.Assign(GetURLWithoutFragment());
141     if (GetFragment().IsEmpty()) {
142       return;
143     }
144     aURL.Append(NS_LITERAL_CSTRING("#"));
145     aURL.Append(GetFragment());
146   }
147 
148   const nsCString&
GetURLWithoutFragment()149   GetURLWithoutFragment() const
150   {
151     MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(),
152                        "Internal Request's urlList should not be empty.");
153 
154     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
AddURL(const nsACString & aURL,const nsACString & aFragment)162   AddURL(const nsACString& aURL, const nsACString& aFragment)
163   {
164     MOZ_ASSERT(!aURL.IsEmpty());
165     MOZ_ASSERT(!aURL.Contains('#'));
166 
167     mURLList.AppendElement(aURL);
168 
169     mFragment.Assign(aFragment);
170   }
171   // Get the URL list without their fragments.
172   void
GetURLListWithoutFragment(nsTArray<nsCString> & aURLList)173   GetURLListWithoutFragment(nsTArray<nsCString>& aURLList)
174   {
175     aURLList.Assign(mURLList);
176   }
177   void
GetReferrer(nsAString & aReferrer)178   GetReferrer(nsAString& aReferrer) const
179   {
180     aReferrer.Assign(mReferrer);
181   }
182 
183   void
SetReferrer(const nsAString & aReferrer)184   SetReferrer(const nsAString& aReferrer)
185   {
186 #ifdef DEBUG
187     bool validReferrer = false;
188     if (aReferrer.IsEmpty() ||
189         aReferrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
190       validReferrer = true;
191     } else {
192       nsCOMPtr<nsIURLParser> parser = do_GetService(NS_STDURLPARSER_CONTRACTID);
193       if (!parser) {
194         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         NS_ConvertUTF16toUTF8 ref(aReferrer);
204         nsresult rv = parser->ParseURL(ref.get(), ref.Length(),
205                                        &schemePos, &schemeLen,
206                                        &authorityPos, &authorityLen,
207                                        &pathPos, &pathLen);
208         if (NS_FAILED(rv)) {
209           NS_WARNING("Invalid referrer URL!");
210         } else if (schemeLen < 0 || authorityLen < 0) {
211           NS_WARNING("Invalid referrer URL!");
212         } else {
213           validReferrer = true;
214         }
215       }
216     }
217 
218     MOZ_ASSERT(validReferrer);
219 #endif
220 
221     mReferrer.Assign(aReferrer);
222   }
223 
224   ReferrerPolicy
ReferrerPolicy_()225   ReferrerPolicy_() const
226   {
227     return mReferrerPolicy;
228   }
229 
230   void
SetReferrerPolicy(ReferrerPolicy aReferrerPolicy)231   SetReferrerPolicy(ReferrerPolicy aReferrerPolicy)
232   {
233     mReferrerPolicy = aReferrerPolicy;
234   }
235 
236   net::ReferrerPolicy
GetEnvironmentReferrerPolicy()237   GetEnvironmentReferrerPolicy() const
238   {
239     return mEnvironmentReferrerPolicy;
240   }
241 
242   void
SetEnvironmentReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)243   SetEnvironmentReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
244   {
245     mEnvironmentReferrerPolicy = aReferrerPolicy;
246   }
247 
248   bool
SkipServiceWorker()249   SkipServiceWorker() const
250   {
251     return mSkipServiceWorker;
252   }
253 
254   void
SetSkipServiceWorker()255   SetSkipServiceWorker()
256   {
257     mSkipServiceWorker = true;
258   }
259 
260   bool
IsSynchronous()261   IsSynchronous() const
262   {
263     return mSynchronous;
264   }
265 
266   RequestMode
Mode()267   Mode() const
268   {
269     return mMode;
270   }
271 
272   void
SetMode(RequestMode aMode)273   SetMode(RequestMode aMode)
274   {
275     mMode = aMode;
276   }
277 
278   RequestCredentials
GetCredentialsMode()279   GetCredentialsMode() const
280   {
281     return mCredentialsMode;
282   }
283 
284   void
SetCredentialsMode(RequestCredentials aCredentialsMode)285   SetCredentialsMode(RequestCredentials aCredentialsMode)
286   {
287     mCredentialsMode = aCredentialsMode;
288   }
289 
290   LoadTainting
GetResponseTainting()291   GetResponseTainting() const
292   {
293     return mResponseTainting;
294   }
295 
296   void
MaybeIncreaseResponseTainting(LoadTainting aTainting)297   MaybeIncreaseResponseTainting(LoadTainting aTainting)
298   {
299     if (aTainting > mResponseTainting) {
300       mResponseTainting = aTainting;
301     }
302   }
303 
304   RequestCache
GetCacheMode()305   GetCacheMode() const
306   {
307     return mCacheMode;
308   }
309 
310   void
SetCacheMode(RequestCache aCacheMode)311   SetCacheMode(RequestCache aCacheMode)
312   {
313     mCacheMode = aCacheMode;
314   }
315 
316   RequestRedirect
GetRedirectMode()317   GetRedirectMode() const
318   {
319     return mRedirectMode;
320   }
321 
322   void
SetRedirectMode(RequestRedirect aRedirectMode)323   SetRedirectMode(RequestRedirect aRedirectMode)
324   {
325     mRedirectMode = aRedirectMode;
326   }
327 
328   const nsString&
GetIntegrity()329   GetIntegrity() const
330   {
331     return mIntegrity;
332   }
333   void
SetIntegrity(const nsAString & aIntegrity)334   SetIntegrity(const nsAString& aIntegrity)
335   {
336     MOZ_ASSERT(mIntegrity.IsEmpty());
337     mIntegrity.Assign(aIntegrity);
338   }
339   const nsCString&
GetFragment()340   GetFragment() const
341   {
342     return mFragment;
343   }
344 
345   nsContentPolicyType
ContentPolicyType()346   ContentPolicyType() const
347   {
348     return mContentPolicyType;
349   }
350   void
351   SetContentPolicyType(nsContentPolicyType aContentPolicyType);
352 
353   void
354   OverrideContentPolicyType(nsContentPolicyType aContentPolicyType);
355 
356   RequestContext
Context()357   Context() const
358   {
359     return MapContentPolicyTypeToRequestContext(mContentPolicyType);
360   }
361 
362   bool
UnsafeRequest()363   UnsafeRequest() const
364   {
365     return mUnsafeRequest;
366   }
367 
368   void
SetUnsafeRequest()369   SetUnsafeRequest()
370   {
371     mUnsafeRequest = true;
372   }
373 
374   InternalHeaders*
Headers()375   Headers()
376   {
377     return mHeaders;
378   }
379 
380   bool
ForceOriginHeader()381   ForceOriginHeader()
382   {
383     return mForceOriginHeader;
384   }
385 
386   bool
SameOriginDataURL()387   SameOriginDataURL() const
388   {
389     return mSameOriginDataURL;
390   }
391 
392   void
UnsetSameOriginDataURL()393   UnsetSameOriginDataURL()
394   {
395     mSameOriginDataURL = false;
396   }
397 
398   void
SetBody(nsIInputStream * aStream)399   SetBody(nsIInputStream* aStream)
400   {
401     // A request's body may not be reset once set.
402     MOZ_ASSERT_IF(aStream, !mBodyStream);
403     mBodyStream = aStream;
404   }
405 
406   // Will return the original stream!
407   // Use a tee or copy if you don't want to erase the original.
408   void
GetBody(nsIInputStream ** aStream)409   GetBody(nsIInputStream** aStream)
410   {
411     nsCOMPtr<nsIInputStream> s = mBodyStream;
412     s.forget(aStream);
413   }
414 
415   // The global is used as the client for the new object.
416   already_AddRefed<InternalRequest>
417   GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const;
418 
419   bool
WasCreatedByFetchEvent()420   WasCreatedByFetchEvent() const
421   {
422     return mCreatedByFetchEvent;
423   }
424 
425   void
SetCreatedByFetchEvent()426   SetCreatedByFetchEvent()
427   {
428     mCreatedByFetchEvent = true;
429   }
430 
431   void
ClearCreatedByFetchEvent()432   ClearCreatedByFetchEvent()
433   {
434     mCreatedByFetchEvent = false;
435   }
436 
437   bool
438   IsNavigationRequest() const;
439 
440   bool
441   IsWorkerRequest() const;
442 
443   bool
444   IsClientRequest() const;
445 
446   void
447   MaybeSkipCacheIfPerformingRevalidation();
448 
449   bool
IsContentPolicyTypeOverridden()450   IsContentPolicyTypeOverridden() const
451   {
452     return mContentPolicyTypeOverridden;
453   }
454 
455   static RequestMode
456   MapChannelToRequestMode(nsIChannel* aChannel);
457 
458   static RequestCredentials
459   MapChannelToRequestCredentials(nsIChannel* aChannel);
460 
461   // Takes ownership of the principal info.
462   void
463   SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo);
464 
465   const UniquePtr<mozilla::ipc::PrincipalInfo>&
GetPrincipalInfo()466   GetPrincipalInfo() const
467   {
468     return mPrincipalInfo;
469   }
470 
471 private:
472   // Does not copy mBodyStream.  Use fallible Clone() for complete copy.
473   explicit InternalRequest(const InternalRequest& aOther);
474 
475   ~InternalRequest();
476 
477   static RequestContext
478   MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType);
479 
480   static bool
481   IsNavigationContentPolicy(nsContentPolicyType aContentPolicyType);
482 
483   static bool
484   IsWorkerContentPolicy(nsContentPolicyType aContentPolicyType);
485 
486   nsCString mMethod;
487   // mURLList: a list of one or more fetch URLs
488   nsTArray<nsCString> mURLList;
489   RefPtr<InternalHeaders> mHeaders;
490   nsCOMPtr<nsIInputStream> mBodyStream;
491 
492   nsContentPolicyType mContentPolicyType;
493 
494   // Empty string: no-referrer
495   // "about:client": client (default)
496   // URL: an URL
497   nsString mReferrer;
498   ReferrerPolicy mReferrerPolicy;
499 
500   // This will be used for request created from Window or Worker contexts
501   // In case there's no Referrer Policy in Request, this will be passed to
502   // channel.
503   // The Environment Referrer Policy should be net::ReferrerPolicy so that it
504   // could be associated with nsIHttpChannel.
505   net::ReferrerPolicy mEnvironmentReferrerPolicy;
506   RequestMode mMode;
507   RequestCredentials mCredentialsMode;
508   MOZ_INIT_OUTSIDE_CTOR LoadTainting mResponseTainting;
509   RequestCache mCacheMode;
510   RequestRedirect mRedirectMode;
511   nsString mIntegrity;
512   nsCString mFragment;
513   MOZ_INIT_OUTSIDE_CTOR bool mAuthenticationFlag;
514   MOZ_INIT_OUTSIDE_CTOR bool mForceOriginHeader;
515   MOZ_INIT_OUTSIDE_CTOR bool mPreserveContentCodings;
516   MOZ_INIT_OUTSIDE_CTOR bool mSameOriginDataURL;
517   MOZ_INIT_OUTSIDE_CTOR bool mSkipServiceWorker;
518   MOZ_INIT_OUTSIDE_CTOR bool mSynchronous;
519   MOZ_INIT_OUTSIDE_CTOR bool mUnsafeRequest;
520   MOZ_INIT_OUTSIDE_CTOR bool mUseURLCredentials;
521   // This is only set when a Request object is created by a fetch event.  We
522   // use it to check if Service Workers are simply fetching intercepted Request
523   // objects without modifying them.
524   bool mCreatedByFetchEvent = false;
525   // This is only set when Request.overrideContentPolicyType() has been set.
526   // It is illegal to pass such a Request object to a fetch() method unless
527   // if the caller has chrome privileges.
528   bool mContentPolicyTypeOverridden = false;
529 
530   UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
531 };
532 
533 } // namespace dom
534 } // namespace mozilla
535 
536 #endif // mozilla_dom_InternalRequest_h
537