InternalRequest.cpp 17 KB

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