summaryrefslogtreecommitdiffstats
path: root/dom/fetch/InternalRequest.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/fetch/InternalRequest.h')
-rw-r--r--dom/fetch/InternalRequest.h489
1 files changed, 489 insertions, 0 deletions
diff --git a/dom/fetch/InternalRequest.h b/dom/fetch/InternalRequest.h
new file mode 100644
index 0000000000..3dfbb9284d
--- /dev/null
+++ b/dom/fetch/InternalRequest.h
@@ -0,0 +1,489 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_InternalRequest_h
+#define mozilla_dom_InternalRequest_h
+
+#include "mozilla/dom/HeadersBinding.h"
+#include "mozilla/dom/InternalHeaders.h"
+#include "mozilla/dom/RequestBinding.h"
+#include "mozilla/dom/SafeRefPtr.h"
+#include "mozilla/LoadTainting.h"
+#include "mozilla/UniquePtr.h"
+
+#include "nsIChannelEventSink.h"
+#include "nsIInputStream.h"
+#include "nsISupportsImpl.h"
+#include "mozilla/net/NeckoChannelParams.h"
+#ifdef DEBUG
+# include "nsIURLParser.h"
+# include "nsNetCID.h"
+# include "nsServiceManagerUtils.h"
+#endif
+
+using mozilla::net::RedirectHistoryEntryInfo;
+
+namespace mozilla {
+
+namespace ipc {
+class PBackgroundChild;
+class PrincipalInfo;
+} // namespace ipc
+
+namespace dom {
+
+/*
+ * The mapping of RequestDestination and nsContentPolicyType is currently as the
+ * following.
+ *
+ * RequestDestination| nsContentPolicyType
+ * ------------------+--------------------
+ * "audio" | TYPE_INTERNAL_AUDIO
+ * "audioworklet" | TYPE_INTERNAL_AUDIOWORKLET
+ * "document" | TYPE_DOCUMENT
+ * "embed" | TYPE_INTERNAL_EMBED
+ * "font" | TYPE_FONT, TYPE_INTERNAL_FONT_PRELOAD
+ * "frame" | TYPE_INTERNAL_FRAME
+ * "iframe" | TYPE_SUBDOCUMENT, TYPE_INTERNAL_IFRAME
+ * "image" | TYPE_INTERNAL_IMAGE, TYPE_INTERNAL_IMAGE_PRELOAD,
+ * | TYPE_IMAGE, TYPE_INTERNAL_IMAGE_FAVICON, TYPE_IMAGESET
+ * "manifest" | TYPE_WEB_MANIFEST
+ * "object" | TYPE_INTERNAL_OBJECT, TYPE_OBJECT
+ * "paintworklet" | TYPE_INTERNAL_PAINTWORKLET
+ * "report" | TYPE_CSP_REPORT
+ * "script" | TYPE_INTERNAL_SCRIPT, TYPE_INTERNAL_SCRIPT_PRELOAD,
+ * | TYPE_INTERNAL_MODULE, TYPE_INTERNAL_MODULE_PRELOAD,
+ * | TYPE_SCRIPT,
+ * | TYPE_INTERNAL_SERVICE_WORKER,
+ * | TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS,
+ * | TYPE_INTERNAL_CHROMEUTILS_COMPILED_SCRIPT
+ * | TYPE_INTERNAL_FRAME_MESSAGEMANAGER_SCRIPT
+ * "sharedworker" | TYPE_INTERNAL_SHARED_WORKER
+ * "serviceworker" | The spec lists this as a valid value for the enum,
+ * | however it is impossible to observe a request with this
+ * | destination value.
+ * "style" | TYPE_INTERNAL_STYLESHEET,
+ * | TYPE_INTERNAL_STYLESHEET_PRELOAD,
+ * | TYPE_STYLESHEET
+ * "track" | TYPE_INTERNAL_TRACK
+ * "video" | TYPE_INTERNAL_VIDEO
+ * "worker" | TYPE_INTERNAL_WORKER, TYPE_INTERNAL_WORKER_STATIC_MODULE
+ * "xslt" | TYPE_XSLT
+ * "" | Default for everything else.
+ *
+ */
+
+class IPCInternalRequest;
+class Request;
+
+#define kFETCH_CLIENT_REFERRER_STR "about:client"
+class InternalRequest final : public AtomicSafeRefCounted<InternalRequest> {
+ friend class Request;
+
+ public:
+ MOZ_DECLARE_REFCOUNTED_TYPENAME(InternalRequest)
+ InternalRequest(const nsACString& aURL, const nsACString& aFragment);
+ 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);
+
+ explicit InternalRequest(const IPCInternalRequest& aIPCRequest);
+
+ void ToIPCInternalRequest(IPCInternalRequest* aIPCRequest,
+ mozilla::ipc::PBackgroundChild* aManager);
+
+ SafeRefPtr<InternalRequest> Clone();
+
+ void GetMethod(nsCString& aMethod) const { aMethod.Assign(mMethod); }
+
+ void SetMethod(const nsACString& aMethod) { mMethod.Assign(aMethod); }
+
+ bool HasSimpleMethod() const {
+ return mMethod.LowerCaseEqualsASCII("get") ||
+ mMethod.LowerCaseEqualsASCII("post") ||
+ mMethod.LowerCaseEqualsASCII("head");
+ }
+ // GetURL should get the request's current url with fragment. A request has
+ // an associated current url. It is a pointer to the last fetch URL in
+ // request's url list.
+ void GetURL(nsACString& aURL) const {
+ aURL.Assign(GetURLWithoutFragment());
+ if (GetFragment().IsEmpty()) {
+ return;
+ }
+ aURL.AppendLiteral("#");
+ aURL.Append(GetFragment());
+ }
+
+ const nsCString& GetURLWithoutFragment() const {
+ MOZ_RELEASE_ASSERT(!mURLList.IsEmpty(),
+ "Internal Request's urlList should not be empty.");
+
+ return mURLList.LastElement();
+ }
+
+ // A safe guard for ensuring that request's URL is only allowed to be set in a
+ // sw internal redirect.
+ void SetURLForInternalRedirect(const uint32_t aFlag, const nsACString& aURL,
+ const nsACString& aFragment) {
+ // Only check in debug build to prevent it from being used unexpectedly.
+ MOZ_ASSERT(aFlag & nsIChannelEventSink::REDIRECT_INTERNAL);
+
+ return SetURL(aURL, aFragment);
+ }
+
+ // AddURL should append the url into url list.
+ // Normally we strip the fragment from the URL in Request::Constructor and
+ // pass the fragment as the second argument into it.
+ // If a fragment is present in the URL it must be stripped and passed in
+ // separately.
+ void AddURL(const nsACString& aURL, const nsACString& aFragment) {
+ MOZ_ASSERT(!aURL.IsEmpty());
+ MOZ_ASSERT(!aURL.Contains('#'));
+
+ mURLList.AppendElement(aURL);
+
+ mFragment.Assign(aFragment);
+ }
+ // Get the URL list without their fragments.
+ void GetURLListWithoutFragment(nsTArray<nsCString>& aURLList) {
+ aURLList.Assign(mURLList);
+ }
+ void GetReferrer(nsAString& aReferrer) const { aReferrer.Assign(mReferrer); }
+
+ void SetReferrer(const nsAString& aReferrer) {
+#ifdef DEBUG
+ bool validReferrer = false;
+ if (aReferrer.IsEmpty() ||
+ aReferrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
+ validReferrer = true;
+ } else {
+ nsCOMPtr<nsIURLParser> parser = do_GetService(NS_STDURLPARSER_CONTRACTID);
+ if (!parser) {
+ NS_WARNING("Could not get parser to validate URL!");
+ } else {
+ uint32_t schemePos;
+ int32_t schemeLen;
+ uint32_t authorityPos;
+ int32_t authorityLen;
+ uint32_t pathPos;
+ int32_t pathLen;
+
+ NS_ConvertUTF16toUTF8 ref(aReferrer);
+ nsresult rv =
+ parser->ParseURL(ref.get(), ref.Length(), &schemePos, &schemeLen,
+ &authorityPos, &authorityLen, &pathPos, &pathLen);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Invalid referrer URL!");
+ } else if (schemeLen < 0 || authorityLen < 0) {
+ NS_WARNING("Invalid referrer URL!");
+ } else {
+ validReferrer = true;
+ }
+ }
+ }
+
+ MOZ_ASSERT(validReferrer);
+#endif
+
+ mReferrer.Assign(aReferrer);
+ }
+
+ ReferrerPolicy ReferrerPolicy_() const { return mReferrerPolicy; }
+
+ void SetReferrerPolicy(ReferrerPolicy aReferrerPolicy) {
+ mReferrerPolicy = aReferrerPolicy;
+ }
+
+ ReferrerPolicy GetEnvironmentReferrerPolicy() const {
+ return mEnvironmentReferrerPolicy;
+ }
+
+ void SetEnvironmentReferrerPolicy(ReferrerPolicy aReferrerPolicy) {
+ mEnvironmentReferrerPolicy = aReferrerPolicy;
+ }
+
+ bool SkipServiceWorker() const { return mSkipServiceWorker; }
+
+ void SetSkipServiceWorker() { mSkipServiceWorker = true; }
+
+ bool SkipWasmCaching() const { return mSkipWasmCaching; }
+
+ void SetSkipWasmCaching() { mSkipWasmCaching = true; }
+
+ bool IsSynchronous() const { return mSynchronous; }
+
+ RequestMode Mode() const { return mMode; }
+
+ void SetMode(RequestMode aMode) { mMode = aMode; }
+
+ RequestCredentials GetCredentialsMode() const { return mCredentialsMode; }
+
+ void SetCredentialsMode(RequestCredentials aCredentialsMode) {
+ mCredentialsMode = aCredentialsMode;
+ }
+
+ LoadTainting GetResponseTainting() const { return mResponseTainting; }
+
+ void MaybeIncreaseResponseTainting(LoadTainting aTainting) {
+ if (aTainting > mResponseTainting) {
+ mResponseTainting = aTainting;
+ }
+ }
+
+ RequestCache GetCacheMode() const { return mCacheMode; }
+
+ void SetCacheMode(RequestCache aCacheMode) { mCacheMode = aCacheMode; }
+
+ RequestRedirect GetRedirectMode() const { return mRedirectMode; }
+
+ void SetRedirectMode(RequestRedirect aRedirectMode) {
+ mRedirectMode = aRedirectMode;
+ }
+
+ const nsString& GetIntegrity() const { return mIntegrity; }
+
+ void SetIntegrity(const nsAString& aIntegrity) {
+ mIntegrity.Assign(aIntegrity);
+ }
+
+ bool MozErrors() const { return mMozErrors; }
+
+ void SetMozErrors() { mMozErrors = true; }
+
+ const nsCString& GetFragment() const { return mFragment; }
+
+ nsContentPolicyType ContentPolicyType() const { return mContentPolicyType; }
+ void SetContentPolicyType(nsContentPolicyType aContentPolicyType);
+
+ void OverrideContentPolicyType(nsContentPolicyType aContentPolicyType);
+
+ RequestDestination Destination() const {
+ return MapContentPolicyTypeToRequestDestination(mContentPolicyType);
+ }
+
+ bool UnsafeRequest() const { return mUnsafeRequest; }
+
+ void SetUnsafeRequest() { mUnsafeRequest = true; }
+
+ InternalHeaders* Headers() const { return mHeaders; }
+
+ void SetHeaders(InternalHeaders* aHeaders) {
+ MOZ_ASSERT(aHeaders);
+ mHeaders = aHeaders;
+ }
+
+ void SetBody(nsIInputStream* aStream, int64_t aBodyLength) {
+ // A request's body may not be reset once set.
+ MOZ_ASSERT_IF(aStream, !mBodyStream);
+ mBodyStream = aStream;
+ mBodyLength = aBodyLength;
+ }
+
+ // Will return the original stream!
+ // Use a tee or copy if you don't want to erase the original.
+ void GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr) const {
+ nsCOMPtr<nsIInputStream> s = mBodyStream;
+ s.forget(aStream);
+
+ if (aBodyLength) {
+ *aBodyLength = mBodyLength;
+ }
+ }
+
+ void SetBodyBlobURISpec(nsACString& aBlobURISpec) {
+ mBodyBlobURISpec = aBlobURISpec;
+ }
+
+ const nsACString& BodyBlobURISpec() const { return mBodyBlobURISpec; }
+
+ void SetBodyLocalPath(nsAString& aLocalPath) { mBodyLocalPath = aLocalPath; }
+
+ const nsAString& BodyLocalPath() const { return mBodyLocalPath; }
+
+ // The global is used as the client for the new object.
+ SafeRefPtr<InternalRequest> GetRequestConstructorCopy(
+ nsIGlobalObject* aGlobal, ErrorResult& aRv) const;
+
+ bool IsNavigationRequest() const;
+
+ bool IsWorkerRequest() const;
+
+ bool IsClientRequest() const;
+
+ void MaybeSkipCacheIfPerformingRevalidation();
+
+ bool IsContentPolicyTypeOverridden() const {
+ return mContentPolicyTypeOverridden;
+ }
+
+ static RequestMode MapChannelToRequestMode(nsIChannel* aChannel);
+
+ static RequestCredentials MapChannelToRequestCredentials(
+ nsIChannel* aChannel);
+
+ // Takes ownership of the principal info.
+ void SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo);
+ const UniquePtr<mozilla::ipc::PrincipalInfo>& GetPrincipalInfo() const {
+ return mPrincipalInfo;
+ }
+
+ const nsCString& GetPreferredAlternativeDataType() const {
+ return mPreferredAlternativeDataType;
+ }
+
+ void SetPreferredAlternativeDataType(const nsACString& aDataType) {
+ mPreferredAlternativeDataType = aDataType;
+ }
+
+ ~InternalRequest();
+
+ InternalRequest(const InternalRequest& aOther) = delete;
+
+ void SetEmbedderPolicy(nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) {
+ mEmbedderPolicy = aPolicy;
+ }
+
+ nsILoadInfo::CrossOriginEmbedderPolicy GetEmbedderPolicy() const {
+ return mEmbedderPolicy;
+ }
+
+ void SetInterceptionTriggeringPrincipalInfo(
+ UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo);
+
+ const UniquePtr<mozilla::ipc::PrincipalInfo>&
+ GetInterceptionTriggeringPrincipalInfo() const {
+ return mInterceptionTriggeringPrincipalInfo;
+ }
+
+ nsContentPolicyType InterceptionContentPolicyType() const {
+ return mInterceptionContentPolicyType;
+ }
+ void SetInterceptionContentPolicyType(nsContentPolicyType aContentPolicyType);
+
+ const nsTArray<RedirectHistoryEntryInfo>& InterceptionRedirectChain() const {
+ return mInterceptionRedirectChain;
+ }
+
+ void SetInterceptionRedirectChain(
+ const nsTArray<RedirectHistoryEntryInfo>& aRedirectChain) {
+ mInterceptionRedirectChain = aRedirectChain;
+ }
+
+ const bool& InterceptionFromThirdParty() const {
+ return mInterceptionFromThirdParty;
+ }
+
+ void SetInterceptionFromThirdParty(bool aFromThirdParty) {
+ mInterceptionFromThirdParty = aFromThirdParty;
+ }
+
+ private:
+ struct ConstructorGuard {};
+
+ public:
+ // Does not copy mBodyStream. Use fallible Clone() for complete copy.
+ InternalRequest(const InternalRequest& aOther, ConstructorGuard);
+
+ private:
+ // Map the content policy type to the associated fetch destination, as defined
+ // by the spec at https://fetch.spec.whatwg.org/#concept-request-destination.
+ // Note that while the HTML spec for the "Link" element and its "as" attribute
+ // (https://html.spec.whatwg.org/#attr-link-as) reuse fetch's definition of
+ // destination.
+ static RequestDestination MapContentPolicyTypeToRequestDestination(
+ nsContentPolicyType aContentPolicyType);
+
+ static bool IsNavigationContentPolicy(nsContentPolicyType aContentPolicyType);
+
+ static bool IsWorkerContentPolicy(nsContentPolicyType aContentPolicyType);
+
+ // It should only be called while there is a service-worker-internal-redirect.
+ void SetURL(const nsACString& aURL, const nsACString& aFragment) {
+ MOZ_ASSERT(!aURL.IsEmpty());
+ MOZ_ASSERT(!aURL.Contains('#'));
+ MOZ_ASSERT(mURLList.Length() > 0);
+
+ mURLList.LastElement() = aURL;
+ mFragment.Assign(aFragment);
+ }
+
+ nsCString mMethod;
+ // mURLList: a list of one or more fetch URLs
+ nsTArray<nsCString> mURLList;
+ RefPtr<InternalHeaders> mHeaders;
+ nsCString mBodyBlobURISpec;
+ nsString mBodyLocalPath;
+ nsCOMPtr<nsIInputStream> mBodyStream;
+ int64_t mBodyLength;
+
+ nsCString mPreferredAlternativeDataType;
+
+ nsContentPolicyType mContentPolicyType;
+
+ // Empty string: no-referrer
+ // "about:client": client (default)
+ // URL: an URL
+ nsString mReferrer;
+ ReferrerPolicy mReferrerPolicy;
+
+ // This will be used for request created from Window or Worker contexts
+ // In case there's no Referrer Policy in Request, this will be passed to
+ // channel.
+ ReferrerPolicy mEnvironmentReferrerPolicy;
+ RequestMode mMode;
+ RequestCredentials mCredentialsMode;
+ LoadTainting mResponseTainting = LoadTainting::Basic;
+ RequestCache mCacheMode;
+ RequestRedirect mRedirectMode;
+ nsString mIntegrity;
+ bool mMozErrors = false;
+ nsCString mFragment;
+ bool mSkipServiceWorker = false;
+ bool mSkipWasmCaching = false;
+ bool mSynchronous = false;
+ bool mUnsafeRequest = false;
+ bool mUseURLCredentials = false;
+ // This is only set when Request.overrideContentPolicyType() has been set.
+ // It is illegal to pass such a Request object to a fetch() method unless
+ // if the caller has chrome privileges.
+ bool mContentPolicyTypeOverridden = false;
+ nsILoadInfo::CrossOriginEmbedderPolicy mEmbedderPolicy =
+ nsILoadInfo::EMBEDDER_POLICY_NULL;
+
+ UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
+
+ // Following members are specific for the FetchEvent.request or
+ // NavigationPreload request which is extracted from the
+ // InterceptedHttpChannel.
+ // Notice that these members would not be copied when calling
+ // InternalRequest::GetRequestConstructorCopy() since these information should
+ // not be propagated when copying the Request in ServiceWorker script.
+
+ // This is the trigging principalInfo of the InterceptedHttpChannel.
+ UniquePtr<mozilla::ipc::PrincipalInfo> mInterceptionTriggeringPrincipalInfo;
+
+ // This is the contentPolicyType of the InterceptedHttpChannel.
+ nsContentPolicyType mInterceptionContentPolicyType{
+ nsIContentPolicy::TYPE_INVALID};
+
+ // This is the redirect history of the InterceptedHttpChannel.
+ CopyableTArray<RedirectHistoryEntryInfo> mInterceptionRedirectChain;
+
+ // This indicates that the InterceptedHttpChannel is a third party channel.
+ bool mInterceptionFromThirdParty{false};
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InternalRequest_h