tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ReferrerInfo.h (16503B)


      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_ReferrerInfo_h
      8 #define mozilla_dom_ReferrerInfo_h
      9 
     10 #include "mozilla/HashFunctions.h"
     11 #include "mozilla/Maybe.h"
     12 #include "mozilla/dom/ReferrerPolicyBinding.h"
     13 #include "nsCOMPtr.h"
     14 #include "nsIReferrerInfo.h"
     15 #include "nsReadableUtils.h"
     16 
     17 #define REFERRERINFO_CONTRACTID "@mozilla.org/referrer-info;1"
     18 // 041a129f-10ce-4bda-a60d-e027a26d5ed0
     19 #define REFERRERINFO_CID \
     20  {0x041a129f, 0x10ce, 0x4bda, {0xa6, 0x0d, 0xe0, 0x27, 0xa2, 0x6d, 0x5e, 0xd0}}
     21 
     22 class nsIHttpChannel;
     23 class nsIURI;
     24 class nsIChannel;
     25 class nsILoadInfo;
     26 class nsINode;
     27 class nsIPrincipal;
     28 
     29 namespace mozilla {
     30 class StyleSheet;
     31 class URLAndReferrerInfo;
     32 
     33 namespace net {
     34 class HttpBaseChannel;
     35 class nsHttpChannel;
     36 }  // namespace net
     37 }  // namespace mozilla
     38 
     39 namespace mozilla::dom {
     40 
     41 /**
     42 * The ReferrerInfo class holds the raw referrer and potentially a referrer
     43 * policy which allows to query the computed referrer which should be applied to
     44 * a channel as the actual referrer value.
     45 *
     46 * The ReferrerInfo class solely contains readonly fields and represents a 1:1
     47 * sync to the referrer header of the corresponding channel. In turn that means
     48 * the class is immutable - so any modifications require to clone the current
     49 * ReferrerInfo.
     50 *
     51 * For example if a request undergoes a redirect, the new channel
     52 * will need a new ReferrerInfo clone with members being updated accordingly.
     53 */
     54 
     55 class ReferrerInfo : public nsIReferrerInfo {
     56 public:
     57  typedef enum ReferrerPolicy ReferrerPolicyEnum;
     58  ReferrerInfo();
     59 
     60  explicit ReferrerInfo(
     61      nsIURI* aOriginalReferrer,
     62      ReferrerPolicyEnum aPolicy = ReferrerPolicy::_empty,
     63      bool aSendReferrer = true,
     64      const Maybe<nsCString>& aComputedReferrer = Maybe<nsCString>());
     65 
     66  // Creates already initialized ReferrerInfo from an element or a document.
     67  explicit ReferrerInfo(const Element&);
     68  explicit ReferrerInfo(const Document&, const bool = true);
     69 
     70  // Creates already initialized ReferrerInfo from an element or a document with
     71  // a specific referrer policy.
     72  ReferrerInfo(const Element&, ReferrerPolicyEnum);
     73 
     74  // create an exact copy of the ReferrerInfo
     75  already_AddRefed<ReferrerInfo> Clone() const;
     76 
     77  // create an copy of the ReferrerInfo with new referrer policy
     78  already_AddRefed<ReferrerInfo> CloneWithNewPolicy(
     79      ReferrerPolicyEnum aPolicy) const;
     80 
     81  // create an copy of the ReferrerInfo with new original referrer
     82  already_AddRefed<ReferrerInfo> CloneWithNewOriginalReferrer(
     83      nsIURI* aOriginalReferrer) const;
     84 
     85  // Record the telemetry for the referrer policy.
     86  void RecordTelemetry(nsIHttpChannel* aChannel);
     87 
     88  /*
     89   * Helper function to create a new ReferrerInfo object from a given document
     90   * and override referrer policy if needed (for example, when parsing link
     91   * header or speculative loading).
     92   *
     93   * @param aDocument the document to init referrerInfo object.
     94   * @param aPolicyOverride referrer policy to override if necessary.
     95   */
     96  static already_AddRefed<nsIReferrerInfo> CreateFromDocumentAndPolicyOverride(
     97      Document* aDoc, ReferrerPolicyEnum aPolicyOverride);
     98 
     99  /*
    100   * Implements step 3.1 and 3.3 of the Determine request's Referrer algorithm
    101   * from the Referrer Policy specification.
    102   *
    103   * https://w3c.github.io/webappsec/specs/referrer-policy/#determine-requests-referrer
    104   */
    105  static already_AddRefed<nsIReferrerInfo> CreateForFetch(
    106      nsIPrincipal* aPrincipal, Document* aDoc);
    107 
    108  /**
    109   * Helper function to create new ReferrerInfo object from a given external
    110   * stylesheet. The returned nsIReferrerInfo object will be used for any
    111   * requests or resources referenced by the sheet.
    112   *
    113   * @param aExternalSheet the stylesheet.
    114   * @param aExternalSheetURI the stylesheet URI.
    115   * @param aPolicy referrer policy from header if there's any.
    116   */
    117  static already_AddRefed<nsIReferrerInfo> CreateForExternalCSSResources(
    118      StyleSheet* aExternalSheet, nsIURI* aExternalSheetURI,
    119      ReferrerPolicyEnum aPolicy = ReferrerPolicy::_empty);
    120 
    121  /**
    122   * Helper function to create new ReferrerInfo object from a given document.
    123   * The returned nsIReferrerInfo object will be used for any requests or
    124   * resources referenced by internal stylesheet (for example style="" or
    125   * wrapped by <style> tag), as well as SVG resources.
    126   *
    127   * @param aDocument the document to init referrerInfo object.
    128   */
    129  static already_AddRefed<nsIReferrerInfo> CreateForInternalCSSAndSVGResources(
    130      Document* aDocument);
    131 
    132  /**
    133   * Check whether the given referrer's scheme is allowed to be computed and
    134   * sent. The allowlist schemes are: http, https.
    135   */
    136  static bool IsReferrerSchemeAllowed(nsIURI* aReferrer);
    137 
    138  /*
    139   * The Referrer Policy should be inherited for nested browsing contexts that
    140   * are not created from responses. Such as: srcdoc, data, blob.
    141   */
    142  static bool ShouldResponseInheritReferrerInfo(nsIChannel* aChannel);
    143 
    144  /*
    145   * Check whether referrer is allowed to send in secure to insecure scenario.
    146   */
    147  static nsresult HandleSecureToInsecureReferral(nsIURI* aOriginalURI,
    148                                                 nsIURI* aURI,
    149                                                 ReferrerPolicyEnum aPolicy,
    150                                                 bool& aAllowed);
    151 
    152  /**
    153   * Returns true if the given channel is cross-origin request
    154   *
    155   * Computing whether the request is cross-origin may be expensive, so please
    156   * do that in cases where we're going to use this information later on.
    157   */
    158  static bool IsCrossOriginRequest(nsIHttpChannel* aChannel);
    159 
    160  /**
    161   * Returns true if aReferrer's origin and aChannel's URI are cross-origin.
    162   */
    163  static bool IsReferrerCrossOrigin(nsIHttpChannel* aChannel,
    164                                    nsIURI* aReferrer);
    165 
    166  /**
    167   * Returns true if the given channel is cross-site request.
    168   */
    169  static bool IsCrossSiteRequest(nsIHttpChannel* aChannel);
    170 
    171  /**
    172   * Returns true if the given channel is suppressed by Referrer-Policy header
    173   * and should set "null" to Origin header.
    174   */
    175  static bool ShouldSetNullOriginHeader(net::HttpBaseChannel* aChannel,
    176                                        nsIURI* aOriginURI);
    177 
    178  /**
    179   * Getter for network.http.sendRefererHeader.
    180   */
    181  static uint32_t GetUserReferrerSendingPolicy();
    182 
    183  /**
    184   * Getter for network.http.referer.XOriginPolicy.
    185   */
    186  static uint32_t GetUserXOriginSendingPolicy();
    187 
    188  /**
    189   * Getter for network.http.referer.trimmingPolicy.
    190   */
    191  static uint32_t GetUserTrimmingPolicy();
    192 
    193  /**
    194   * Getter for network.http.referer.XOriginTrimmingPolicy.
    195   */
    196  static uint32_t GetUserXOriginTrimmingPolicy();
    197 
    198  /**
    199   * Return default referrer policy which is controlled by user
    200   * prefs:
    201   * network.http.referer.defaultPolicy for regular mode
    202   * network.http.referer.defaultPolicy.trackers for third-party trackers
    203   * in regular mode
    204   * network.http.referer.defaultPolicy.pbmode for private mode
    205   * network.http.referer.defaultPolicy.trackers.pbmode for third-party trackers
    206   * in private mode
    207   */
    208  static ReferrerPolicyEnum GetDefaultReferrerPolicy(
    209      nsIHttpChannel* aChannel = nullptr, nsIURI* aURI = nullptr,
    210      bool aPrivateBrowsing = false);
    211 
    212  /**
    213   * Return default referrer policy for third party which is controlled by user
    214   * prefs:
    215   * network.http.referer.defaultPolicy.trackers for regular mode
    216   * network.http.referer.defaultPolicy.trackers.pbmode for private mode
    217   */
    218  static ReferrerPolicyEnum GetDefaultThirdPartyReferrerPolicy(
    219      bool aPrivateBrowsing = false);
    220 
    221  /*
    222   * Helper function to parse ReferrerPolicy from meta tag referrer content.
    223   * For example: <meta name="referrer" content="origin">
    224   *
    225   * @param aContent content string to be transformed into ReferrerPolicyEnum,
    226   *                 e.g. "origin".
    227   */
    228  static ReferrerPolicyEnum ReferrerPolicyFromMetaString(
    229      const nsAString& aContent);
    230 
    231  /*
    232   * Helper function to parse ReferrerPolicy from string content of
    233   * referrerpolicy attribute.
    234   * For example: <a href="http://example.com" referrerpolicy="no-referrer">
    235   *
    236   * @param aContent content string to be transformed into ReferrerPolicyEnum,
    237   *                 e.g. "no-referrer".
    238   */
    239  static ReferrerPolicyEnum ReferrerPolicyAttributeFromString(
    240      const nsAString& aContent);
    241 
    242  /*
    243   * Helper function to parse ReferrerPolicy from string content of
    244   * Referrer-Policy header.
    245   * For example: Referrer-Policy: origin no-referrer
    246   * https://www.w3.org/tr/referrer-policy/#parse-referrer-policy-from-header
    247   *
    248   * @param aContent content string to be transformed into ReferrerPolicyEnum.
    249   *                e.g. "origin no-referrer"
    250   */
    251  static ReferrerPolicyEnum ReferrerPolicyFromHeaderString(
    252      const nsAString& aContent);
    253 
    254  /**
    255   * Hash function for this object
    256   */
    257  HashNumber Hash() const;
    258 
    259  NS_DECL_THREADSAFE_ISUPPORTS
    260  NS_DECL_NSIREFERRERINFO
    261  NS_DECL_NSISERIALIZABLE
    262 
    263 private:
    264  virtual ~ReferrerInfo() = default;
    265 
    266  ReferrerInfo(const ReferrerInfo& rhs);
    267 
    268  /*
    269   * Trimming policy when compute referrer, indicate how much information in the
    270   * referrer will be sent. Order matters here.
    271   */
    272  enum TrimmingPolicy : uint32_t {
    273    ePolicyFullURI = 0,
    274    ePolicySchemeHostPortPath = 1,
    275    ePolicySchemeHostPort = 2,
    276  };
    277 
    278  /*
    279   * Referrer sending policy, indicates type of action could trigger to send
    280   * referrer header, not send at all, send only with user's action (click on a
    281   * link) or send even with inline content request (image request).
    282   * Order matters here.
    283   */
    284  enum ReferrerSendingPolicy : uint32_t {
    285    ePolicyNotSend = 0,
    286    ePolicySendWhenUserTrigger = 1,
    287    ePolicySendInlineContent = 2,
    288  };
    289 
    290  /*
    291   * Sending referrer when cross origin policy, indicates when referrer should
    292   * be send when compare 2 origins. Order matters here.
    293   */
    294  enum XOriginSendingPolicy : uint32_t {
    295    ePolicyAlwaysSend = 0,
    296    ePolicySendWhenSameDomain = 1,
    297    ePolicySendWhenSameHost = 2,
    298  };
    299 
    300  /*
    301   * Handle user controlled pref network.http.referer.XOriginPolicy
    302   */
    303  nsresult HandleUserXOriginSendingPolicy(nsIURI* aURI, nsIURI* aReferrer,
    304                                          bool& aAllowed) const;
    305 
    306  /*
    307   * Handle user controlled pref network.http.sendRefererHeader
    308   */
    309  nsresult HandleUserReferrerSendingPolicy(nsIHttpChannel* aChannel,
    310                                           bool& aAllowed) const;
    311 
    312  /*
    313   * Compute trimming policy from user controlled prefs.
    314   * This function is called when we already made sure a nonempty referrer is
    315   * allowed to send.
    316   */
    317  TrimmingPolicy ComputeTrimmingPolicy(nsIHttpChannel* aChannel,
    318                                       nsIURI* aReferrer) const;
    319 
    320  // HttpBaseChannel could access IsInitialized() and ComputeReferrer();
    321  friend class mozilla::net::HttpBaseChannel;
    322 
    323  /*
    324   * Compute referrer for a given channel. The computation result then will be
    325   * stored in this class and then used to set the actual referrer header of
    326   * the channel. The computation could be controlled by several user prefs
    327   * which are defined in StaticPrefList.yaml (see StaticPrefList.yaml for more
    328   * details):
    329   *  network.http.sendRefererHeader
    330   *  network.http.referer.spoofSource
    331   *  network.http.referer.hideOnionSource
    332   *  network.http.referer.XOriginPolicy
    333   *  network.http.referer.trimmingPolicy
    334   *  network.http.referer.XOriginTrimmingPolicy
    335   */
    336  nsresult ComputeReferrer(nsIHttpChannel* aChannel);
    337 
    338  /*
    339   * Check whether the ReferrerInfo has been initialized or not.
    340   */
    341  bool IsInitialized() { return mInitialized; }
    342 
    343  // nsHttpChannel, Document could access IsPolicyOverrided();
    344  friend class mozilla::net::nsHttpChannel;
    345  friend class mozilla::dom::Document;
    346  /*
    347   * Check whether if unset referrer policy is overrided by default or not
    348   */
    349  bool IsPolicyOverrided() { return mOverridePolicyByDefault; }
    350 
    351  /*
    352   *  Get origin string from a given valid referrer URI (http, https)
    353   *
    354   *  @aReferrer - the full referrer URI
    355   *  @aResult - the resulting aReferrer in string format.
    356   */
    357  nsresult GetOriginFromReferrerURI(nsIURI* aReferrer,
    358                                    nsACString& aResult) const;
    359 
    360  /*
    361   * Trim a given referrer with a given a trimming policy,
    362   */
    363  nsresult TrimReferrerWithPolicy(nsIURI* aReferrer,
    364                                  TrimmingPolicy aTrimmingPolicy,
    365                                  nsACString& aResult) const;
    366 
    367  /**
    368   * Returns true if we should ignore less restricted referrer policies,
    369   * including 'unsafe_url', 'no_referrer_when_downgrade' and
    370   * 'origin_when_cross_origin', for the given channel. We only apply this
    371   * restriction for cross-site requests. For the same-site request, we will
    372   * still allow overriding the default referrer policy with less restricted
    373   * one.
    374   *
    375   * Note that the channel triggered by the system and the extension will be
    376   * exempt from this restriction.
    377   */
    378  bool ShouldIgnoreLessRestrictedPolicies(
    379      nsIHttpChannel* aChannel, const ReferrerPolicyEnum aPolicy) const;
    380 
    381  /*
    382   *  Limit referrer length using the following ruleset:
    383   *   - If the length of referrer URL is over max length, strip down to origin.
    384   *   - If the origin is still over max length, remove the referrer entirely.
    385   *
    386   *  This function comlements TrimReferrerPolicy and needs to be called right
    387   *  after TrimReferrerPolicy.
    388   *
    389   *  @aChannel - used to query information needed for logging to the console.
    390   *  @aReferrer - the full referrer URI; needs to be identical to aReferrer
    391   *               passed to TrimReferrerPolicy.
    392   *  @aTrimmingPolicy - represents the trimming policy which was applied to the
    393   *                     referrer; needs to be identical to aTrimmingPolicy
    394   *                     passed to TrimReferrerPolicy.
    395   *  @aInAndOutTrimmedReferrer -  an in and outgoing argument representing the
    396   *                               referrer value. Please pass the result of
    397   *                               TrimReferrerWithPolicy as
    398   *                               aInAndOutTrimmedReferrer which will then be
    399   *                               reduced to the origin or completely truncated
    400   *                               in case the referrer value exceeds the length
    401   *                               limitation.
    402   */
    403  nsresult LimitReferrerLength(nsIHttpChannel* aChannel, nsIURI* aReferrer,
    404                               TrimmingPolicy aTrimmingPolicy,
    405                               nsACString& aInAndOutTrimmedReferrer) const;
    406 
    407  /**
    408   * The helper function to read the old data format before gecko 100 for
    409   * deserialization.
    410   */
    411  nsresult ReadTailDataBeforeGecko100(const uint32_t& aData,
    412                                      nsIObjectInputStream* aInputStream);
    413 
    414  /*
    415   * Write message to the error console
    416   */
    417  void LogMessageToConsole(nsIHttpChannel* aChannel, const char* aMsg,
    418                           const nsTArray<nsString>& aParams) const;
    419 
    420  friend class mozilla::URLAndReferrerInfo;
    421 
    422  nsCOMPtr<nsIURI> mOriginalReferrer;
    423 
    424  ReferrerPolicyEnum mPolicy;
    425 
    426  // The referrer policy that has been set originally for the channel. Note that
    427  // the policy may have been overridden by the default referrer policy, so we
    428  // need to keep track of this if we need to recover the original referrer
    429  // policy.
    430  ReferrerPolicyEnum mOriginalPolicy;
    431 
    432  // Indicates if the referrer should be sent or not even when it's available
    433  // (default is true).
    434  bool mSendReferrer;
    435 
    436  // Since the ReferrerInfo is immutable, we use this member as a helper to
    437  // ensure no one can call e.g. init() twice to modify state of the
    438  // ReferrerInfo.
    439  bool mInitialized;
    440 
    441  // Indicates if unset referrer policy is overrided by default
    442  bool mOverridePolicyByDefault;
    443 
    444  // Store a computed referrer for a given channel
    445  Maybe<nsCString> mComputedReferrer;
    446 
    447 #ifdef DEBUG
    448  // Indicates if the telemetry has been recorded. This is used to make sure the
    449  // telemetry will be only recored once.
    450  bool mTelemetryRecorded = false;
    451 #endif  // DEBUG
    452 };
    453 
    454 }  // namespace mozilla::dom
    455 
    456 #endif  // mozilla_dom_ReferrerInfo_h