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