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

Side by Side 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, 5 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/url_request/url_request_job.h" 5 #include "net/url_request/url_request_job.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
13 #include "base/power_monitor/power_monitor.h" 13 #include "base/power_monitor/power_monitor.h"
14 #include "base/profiler/scoped_tracker.h" 14 #include "base/profiler/scoped_tracker.h"
15 #include "base/single_thread_task_runner.h" 15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h" 18 #include "base/strings/string_util.h"
18 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/values.h" 20 #include "base/values.h"
20 #include "net/base/auth.h" 21 #include "net/base/auth.h"
21 #include "net/base/host_port_pair.h" 22 #include "net/base/host_port_pair.h"
22 #include "net/base/io_buffer.h" 23 #include "net/base/io_buffer.h"
23 #include "net/base/load_flags.h" 24 #include "net/base/load_flags.h"
24 #include "net/base/load_states.h" 25 #include "net/base/load_states.h"
25 #include "net/base/net_errors.h" 26 #include "net/base/net_errors.h"
26 #include "net/base/network_delegate.h" 27 #include "net/base/network_delegate.h"
(...skipping 28 matching lines...) Expand all
55 // See: 56 // See:
56 // https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-17#section-7.3 57 // https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-17#section-7.3
57 if ((http_status_code == 303 && method != "HEAD") || 58 if ((http_status_code == 303 && method != "HEAD") ||
58 ((http_status_code == 301 || http_status_code == 302) && 59 ((http_status_code == 301 || http_status_code == 302) &&
59 method == "POST")) { 60 method == "POST")) {
60 return "GET"; 61 return "GET";
61 } 62 }
62 return method; 63 return method;
63 } 64 }
64 65
66 // Given a referrer policy |token| (from the list of policies defined in
67 // https://w3c.github.io/webappsec-referrer-policy/#referrer-policies),
68 // this function sets |new_referrer_policy| to the new referrer policy that
69 // should be used, and sets |new_referrer_source| to the value that
70 // should be used as input to ComputeReferrerForRedirect().
71 // ComputeReferrerForRedirect() is responsible for applying the
72 // request's URLRequest::ReferrerPolicy to compute the final referrer.
73 //
74 // If |token| does not match any policy, then this function does not
75 // modify |new_referrer_policy| or |new_referrer_source|.
76 //
77 // Note that
78 // https://w3c.github.io/webappsec-referrer-policy/#determine-policy-for-token
79 // defines legacy keywords "never", "default", and "always", which this
80 // function respects even though authors are discouraged from using them.
81 void GetReferrerPolicyFromToken(const std::string& token,
82 const std::string& referrer_source,
83 URLRequest::ReferrerPolicy* new_referrer_policy,
84 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
85 // For a referrer policy of 'no-referrer', clear the referrer
86 // source. With an empty referrer source, the request's referrer
87 // policy doesn't really matter because the final referrer will always
88 // be empty.
89 if (base::CompareCaseInsensitiveASCII(token, "never") == 0 ||
90 base::CompareCaseInsensitiveASCII(token, "no-referrer") == 0) {
91 *new_referrer_policy = URLRequest::NEVER_CLEAR_REFERRER;
92 *new_referrer_source = std::string();
93 return;
94 }
95
96 // For a referrer policy of 'no-referrer-when-downgrade', setting the
97 // referrer policy is sufficient; ComputeReferrerForRedirect() will
98 // apply this policy to strip the referrer if necessary.
99 if (base::CompareCaseInsensitiveASCII(token, "default") == 0 ||
100 base::CompareCaseInsensitiveASCII(token, "no-referrer-when-downgrade") ==
101 0) {
102 *new_referrer_policy =
103 URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
104 *new_referrer_source = referrer_source;
105 return;
106 }
107
108 // For a referrer policy of 'origin', strip the referrer source to the
109 // origin. After doing so, there is no need to modify the referrer
110 // further, so set the policy to leave the referrer alone.
111 if (base::CompareCaseInsensitiveASCII(token, "origin") == 0) {
112 *new_referrer_policy = URLRequest::NEVER_CLEAR_REFERRER;
113 *new_referrer_source = GURL(referrer_source).GetOrigin().spec();
114 return;
115 }
116
117 // For a referrer policy of 'origin-when-cross-origin', setting the
118 // URLRequest's ReferrerPolicy is sufficient;
119 // ComputeReferrerForRedirect() will apply this policy to strip the
120 // referrer if necessary.
121 if (base::CompareCaseInsensitiveASCII(token, "origin-when-cross-origin") ==
122 0) {
123 *new_referrer_policy = URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN;
124 *new_referrer_source = referrer_source;
125 return;
126 }
127
128 // For a referrer policy of 'unsafe-url', leave the referrer source
129 // untouched and set the policy so that ComputeReferrerForRedirect()
130 // will not modify it.
131 if (base::CompareCaseInsensitiveASCII(token, "always") == 0 ||
132 base::CompareCaseInsensitiveASCII(token, "unsafe-url") == 0) {
133 *new_referrer_policy = URLRequest::NEVER_CLEAR_REFERRER;
134 *new_referrer_source = referrer_source;
135 return;
136 }
137
138 return;
139 }
140
141 // A redirect response can contain a Referrer-Policy header
142 // (https://w3c.github.io/webappsec-referrer-policy/). This function
143 // checks for a Referrer-Policy header, and parses it if
144 // present. Returns the referrer policy that should be used for the
145 // request. Sets |new_referrer_source| to the URL that should be used as
146 // what the spec calls the "referrerSource" -- that is, the referrer
147 // that will be used as input to ComputeReferrerForRedirect().
148 URLRequest::ReferrerPolicy ProcessReferrerPolicyHeaderOnRedirect(
149 URLRequest* request,
150 std::string* new_referrer_source) {
151 URLRequest::ReferrerPolicy new_policy = request->referrer_policy();
152 *new_referrer_source = request->referrer();
153
154 std::string referrer_policy_header;
155 request->GetResponseHeaderByName("Referrer-Policy", &referrer_policy_header);
156 std::vector<std::string> policy_tokens =
157 base::SplitString(referrer_policy_header, ",", base::TRIM_WHITESPACE,
158 base::SPLIT_WANT_NONEMPTY);
159
160 for (const auto& token : policy_tokens) {
161 GetReferrerPolicyFromToken(token, request->referrer(), &new_policy,
162 new_referrer_source);
163 }
164 return new_policy;
165 }
166
65 } // namespace 167 } // namespace
66 168
67 URLRequestJob::URLRequestJob(URLRequest* request, 169 URLRequestJob::URLRequestJob(URLRequest* request,
68 NetworkDelegate* network_delegate) 170 NetworkDelegate* network_delegate)
69 : request_(request), 171 : request_(request),
70 done_(false), 172 done_(false),
71 prefilter_bytes_read_(0), 173 prefilter_bytes_read_(0),
72 postfilter_bytes_read_(0), 174 postfilter_bytes_read_(0),
73 filter_needs_more_output_space_(false), 175 filter_needs_more_output_space_(false),
74 filtered_read_buffer_len_(0), 176 filtered_read_buffer_len_(0),
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 return GURL(); 439 return GURL();
338 } else { 440 } else {
339 return original_referrer.GetOrigin(); 441 return original_referrer.GetOrigin();
340 } 442 }
341 443
342 case URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN: 444 case URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
343 return same_origin ? original_referrer : original_referrer.GetOrigin(); 445 return same_origin ? original_referrer : original_referrer.GetOrigin();
344 446
345 case URLRequest::NEVER_CLEAR_REFERRER: 447 case URLRequest::NEVER_CLEAR_REFERRER:
346 return original_referrer; 448 return original_referrer;
449 case URLRequest::MAX_REFERRER_POLICY:
450 NOTREACHED();
451 return original_referrer;
347 } 452 }
348 453
349 NOTREACHED(); 454 NOTREACHED();
350 return GURL(); 455 return GURL();
351 } 456 }
352 457
353 void URLRequestJob::NotifyCertificateRequested( 458 void URLRequestJob::NotifyCertificateRequested(
354 SSLCertRequestInfo* cert_request_info) { 459 SSLCertRequestInfo* cert_request_info) {
355 request_->NotifyCertificateRequested(cert_request_info); 460 request_->NotifyCertificateRequested(cert_request_info);
356 } 461 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 // the time stamps if it has that information. The default request_time is 496 // the time stamps if it has that information. The default request_time is
392 // set by URLRequest before it calls our Start method. 497 // set by URLRequest before it calls our Start method.
393 request_->response_info_.response_time = base::Time::Now(); 498 request_->response_info_.response_time = base::Time::Now();
394 GetResponseInfo(&request_->response_info_); 499 GetResponseInfo(&request_->response_info_);
395 500
396 MaybeNotifyNetworkBytes(); 501 MaybeNotifyNetworkBytes();
397 request_->OnHeadersComplete(); 502 request_->OnHeadersComplete();
398 503
399 GURL new_location; 504 GURL new_location;
400 int http_status_code; 505 int http_status_code;
506
401 if (IsRedirectResponse(&new_location, &http_status_code)) { 507 if (IsRedirectResponse(&new_location, &http_status_code)) {
402 // Redirect response bodies are not read. Notify the transaction 508 // Redirect response bodies are not read. Notify the transaction
403 // so it does not treat being stopped as an error. 509 // so it does not treat being stopped as an error.
404 DoneReadingRedirectResponse(); 510 DoneReadingRedirectResponse();
405 511
406 // When notifying the URLRequest::Delegate, it can destroy the request, 512 // When notifying the URLRequest::Delegate, it can destroy the request,
407 // which will destroy |this|. After calling to the URLRequest::Delegate, 513 // which will destroy |this|. After calling to the URLRequest::Delegate,
408 // pointer must be checked to see if |this| still exists, and if not, the 514 // pointer must be checked to see if |this| still exists, and if not, the
409 // code must return immediately. 515 // code must return immediately.
410 base::WeakPtr<URLRequestJob> weak_this(weak_factory_.GetWeakPtr()); 516 base::WeakPtr<URLRequestJob> weak_this(weak_factory_.GetWeakPtr());
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after
937 1043
938 // Update the first-party URL if appropriate. 1044 // Update the first-party URL if appropriate.
939 if (request_->first_party_url_policy() == 1045 if (request_->first_party_url_policy() ==
940 URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT) { 1046 URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT) {
941 redirect_info.new_first_party_for_cookies = redirect_info.new_url; 1047 redirect_info.new_first_party_for_cookies = redirect_info.new_url;
942 } else { 1048 } else {
943 redirect_info.new_first_party_for_cookies = 1049 redirect_info.new_first_party_for_cookies =
944 request_->first_party_for_cookies(); 1050 request_->first_party_for_cookies();
945 } 1051 }
946 1052
1053 // |referrer_source| is the starting-point referrer, which may be
1054 // modified by ComputeReferrerForRedirect() to produce a new referrer
1055 // that obeys the request's referrer policy.
1056 std::string referrer_source;
1057 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
1058 redirect_info.new_referrer_policy =
1059 ProcessReferrerPolicyHeaderOnRedirect(request_, &referrer_source);
1060 } else {
1061 referrer_source = request_->referrer();
1062 redirect_info.new_referrer_policy = request_->referrer_policy();
1063 }
1064
947 // Alter the referrer if redirecting cross-origin (especially HTTP->HTTPS). 1065 // Alter the referrer if redirecting cross-origin (especially HTTP->HTTPS).
948 redirect_info.new_referrer = 1066 redirect_info.new_referrer =
949 ComputeReferrerForRedirect(request_->referrer_policy(), 1067 ComputeReferrerForRedirect(redirect_info.new_referrer_policy,
950 request_->referrer(), 1068 referrer_source, redirect_info.new_url)
951 redirect_info.new_url).spec(); 1069 .spec();
952 1070
953 std::string include_referer; 1071 std::string include_referer;
954 request_->GetResponseHeaderByName("include-referer-token-binding-id", 1072 request_->GetResponseHeaderByName("include-referer-token-binding-id",
955 &include_referer); 1073 &include_referer);
956 if (include_referer == "true" && 1074 if (include_referer == "true" &&
957 request_->ssl_info().token_binding_negotiated) { 1075 request_->ssl_info().token_binding_negotiated) {
958 redirect_info.referred_token_binding_host = url.host(); 1076 redirect_info.referred_token_binding_host = url.host();
959 } 1077 }
960 1078
961 return redirect_info; 1079 return redirect_info;
(...skipping 16 matching lines...) Expand all
978 int64_t total_sent_bytes = GetTotalSentBytes(); 1096 int64_t total_sent_bytes = GetTotalSentBytes();
979 DCHECK_GE(total_sent_bytes, last_notified_total_sent_bytes_); 1097 DCHECK_GE(total_sent_bytes, last_notified_total_sent_bytes_);
980 if (total_sent_bytes > last_notified_total_sent_bytes_) { 1098 if (total_sent_bytes > last_notified_total_sent_bytes_) {
981 network_delegate_->NotifyNetworkBytesSent( 1099 network_delegate_->NotifyNetworkBytesSent(
982 request_, total_sent_bytes - last_notified_total_sent_bytes_); 1100 request_, total_sent_bytes - last_notified_total_sent_bytes_);
983 } 1101 }
984 last_notified_total_sent_bytes_ = total_sent_bytes; 1102 last_notified_total_sent_bytes_ = total_sent_bytes;
985 } 1103 }
986 1104
987 } // namespace net 1105 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698