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