Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(860)

Unified Diff: net/url_request/url_request_job.cc

Issue 2100583002: Apply Referrer-Policy header when following redirects (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: update ios switch Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/url_request/url_request_job.cc
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index b9c8646f729e75e45b45d65b635d1f51e78da254..45f4d71a4fe628b5bb6ac40463c7d62737450651 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -14,6 +14,7 @@
#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
@@ -62,6 +63,107 @@ std::string ComputeMethodForRedirect(const std::string& method,
return method;
}
+// Given a referrer policy |token| (from the list of policies defined in
+// https://w3c.github.io/webappsec-referrer-policy/#referrer-policies),
+// this function sets |new_referrer_policy| to the new referrer policy that
+// should be used, and sets |new_referrer_source| to the value that
+// should be used as input to ComputeReferrerForRedirect().
+// ComputeReferrerForRedirect() is responsible for applying the
+// request's URLRequest::ReferrerPolicy to compute the final referrer.
+//
+// If |token| does not match any policy, then this function does not
+// modify |new_referrer_policy| or |new_referrer_source|.
+//
+// Note that
+// https://w3c.github.io/webappsec-referrer-policy/#determine-policy-for-token
+// defines legacy keywords "never", "default", and "always", which this
+// function respects even though authors are discouraged from using them.
+void GetReferrerPolicyFromToken(const std::string& token,
+ const std::string& referrer_source,
+ URLRequest::ReferrerPolicy* new_referrer_policy,
+ std::string* new_referrer_source) {
mmenke 2016/06/27 18:38:05 "source" is a really confusing name. It's actuall
estark 2016/06/27 22:18:34 Heh, I called it "referrer source" because I found
mmenke 2016/06/28 14:29:23 "referrer_source" sounds like the source of the re
+ // For a referrer policy of 'no-referrer', clear the referrer
+ // source. With an empty referrer source, the request's referrer
+ // policy doesn't really matter because the final referrer will always
+ // be empty.
+ if (base::CompareCaseInsensitiveASCII(token, "never") == 0 ||
+ base::CompareCaseInsensitiveASCII(token, "no-referrer") == 0) {
+ *new_referrer_policy = URLRequest::NEVER_CLEAR_REFERRER;
+ *new_referrer_source = std::string();
+ return;
+ }
+
+ // For a referrer policy of 'no-referrer-when-downgrade', setting the
+ // referrer policy is sufficient; ComputeReferrerForRedirect() will
+ // apply this policy to strip the referrer if necessary.
+ if (base::CompareCaseInsensitiveASCII(token, "default") == 0 ||
+ base::CompareCaseInsensitiveASCII(token, "no-referrer-when-downgrade") ==
+ 0) {
+ *new_referrer_policy =
+ URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
+ *new_referrer_source = referrer_source;
+ return;
+ }
+
+ // For a referrer policy of 'origin', strip the referrer source to the
+ // origin. After doing so, there is no need to modify the referrer
+ // further, so set the policy to leave the referrer alone.
+ if (base::CompareCaseInsensitiveASCII(token, "origin") == 0) {
+ *new_referrer_policy = URLRequest::NEVER_CLEAR_REFERRER;
+ *new_referrer_source = GURL(referrer_source).GetOrigin().spec();
+ return;
+ }
+
+ // For a referrer policy of 'origin-when-cross-origin', setting the
+ // URLRequest's ReferrerPolicy is sufficient;
+ // ComputeReferrerForRedirect() will apply this policy to strip the
+ // referrer if necessary.
+ if (base::CompareCaseInsensitiveASCII(token, "origin-when-cross-origin") ==
+ 0) {
+ *new_referrer_policy = URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN;
+ *new_referrer_source = referrer_source;
+ return;
+ }
+
+ // For a referrer policy of 'unsafe-url', leave the referrer source
+ // untouched and set the policy so that ComputeReferrerForRedirect()
+ // will not modify it.
+ if (base::CompareCaseInsensitiveASCII(token, "always") == 0 ||
+ base::CompareCaseInsensitiveASCII(token, "unsafe-url") == 0) {
+ *new_referrer_policy = URLRequest::NEVER_CLEAR_REFERRER;
+ *new_referrer_source = referrer_source;
+ return;
+ }
+
+ return;
+}
+
+// A redirect response can contain a Referrer-Policy header
+// (https://w3c.github.io/webappsec-referrer-policy/). This function
+// checks for a Referrer-Policy header, and parses it if
+// present. Returns the referrer policy that should be used for the
+// request. Sets |new_referrer_source| to the URL that should be used as
+// what the spec calls the "referrerSource" -- that is, the referrer
+// that will be used as input to ComputeReferrerForRedirect().
+URLRequest::ReferrerPolicy ProcessReferrerPolicyHeaderOnRedirect(
+ URLRequest* request,
+ std::string* new_referrer_source) {
+ URLRequest::ReferrerPolicy new_policy = request->referrer_policy();
+ *new_referrer_source = request->referrer();
+
+ std::string referrer_policy_header;
+ request->GetResponseHeaderByName("Referrer-Policy", &referrer_policy_header);
+ std::vector<std::string> policy_tokens =
+ base::SplitString(referrer_policy_header, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+
+ for (const auto& token : policy_tokens) {
+ GetReferrerPolicyFromToken(token, request->referrer(), &new_policy,
+ new_referrer_source);
+ }
+ return new_policy;
+}
+
} // namespace
URLRequestJob::URLRequestJob(URLRequest* request,
@@ -344,6 +446,9 @@ GURL URLRequestJob::ComputeReferrerForRedirect(
case URLRequest::NEVER_CLEAR_REFERRER:
return original_referrer;
+ case URLRequest::MAX_REFERRER_POLICY:
+ NOTREACHED();
+ return original_referrer;
}
NOTREACHED();
@@ -398,6 +503,7 @@ void URLRequestJob::NotifyHeadersComplete() {
GURL new_location;
int http_status_code;
+
if (IsRedirectResponse(&new_location, &http_status_code)) {
// Redirect response bodies are not read. Notify the transaction
// so it does not treat being stopped as an error.
@@ -944,11 +1050,23 @@ RedirectInfo URLRequestJob::ComputeRedirectInfo(const GURL& location,
request_->first_party_for_cookies();
}
+ // |referrer_source| is the starting-point referrer, which may be
+ // modified by ComputeReferrerForRedirect() to produce a new referrer
+ // that obeys the request's referrer policy.
+ std::string referrer_source;
+ if (request_->context()->enable_referrer_policy_header()) {
mmenke 2016/06/27 17:18:04 Question...I may have asked this before, but it se
mmenke 2016/06/27 17:20:04 That is, Site C is not secure, and not on the same
estark 2016/06/27 17:27:52 That does seem weird, but I'm pretty sure that's b
+ redirect_info.new_referrer_policy =
+ ProcessReferrerPolicyHeaderOnRedirect(request_, &referrer_source);
+ } else {
+ referrer_source = request_->referrer();
+ redirect_info.new_referrer_policy = request_->referrer_policy();
+ }
+
// Alter the referrer if redirecting cross-origin (especially HTTP->HTTPS).
redirect_info.new_referrer =
- ComputeReferrerForRedirect(request_->referrer_policy(),
- request_->referrer(),
- redirect_info.new_url).spec();
+ ComputeReferrerForRedirect(redirect_info.new_referrer_policy,
+ referrer_source, redirect_info.new_url)
+ .spec();
std::string include_referer;
request_->GetResponseHeaderByName("include-referer-token-binding-id",

Powered by Google App Engine
This is Rietveld 408576698