Chromium Code Reviews| 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", |