blob: 6204faa4d2abc55ccade5d7314c87c8baac2dcb2 [file] [log] [blame]
[email protected]fecef222012-01-05 02:26:151// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
[email protected]175adac2008-07-30 17:28:045#include "net/url_request/url_request_http_job.h"
initial.commit586acc5fe2008-07-26 22:42:526
[email protected]4ed2755f2008-12-15 09:01:337#include "base/base_switches.h"
[email protected]4f9e5c82011-11-17 16:04:568#include "base/bind.h"
[email protected]084262c2011-12-01 21:12:479#include "base/bind_helpers.h"
[email protected]4ed2755f2008-12-15 09:01:3310#include "base/command_line.h"
[email protected]39ce5c02008-08-22 04:03:4411#include "base/compiler_specific.h"
[email protected]60889422008-09-23 01:18:1612#include "base/file_version_info.h"
skyostil4891b25b2015-06-11 11:43:4513#include "base/location.h"
Avi Drissman13fc8932015-12-20 04:40:4614#include "base/macros.h"
[email protected]8684a8812011-03-22 13:59:3815#include "base/metrics/field_trial.h"
asvitkinec3c93722015-06-17 14:48:3716#include "base/metrics/histogram_macros.h"
vadimt29494d82014-11-04 20:06:2617#include "base/profiler/scoped_tracker.h"
[email protected]5b90b5d2009-04-30 23:06:0118#include "base/rand_util.h"
skyostil4891b25b2015-06-11 11:43:4519#include "base/single_thread_task_runner.h"
[email protected]4dc3ad4f2013-06-11 07:15:5020#include "base/strings/string_util.h"
skyostil4891b25b2015-06-11 11:43:4521#include "base/thread_task_runner_handle.h"
[email protected]f002abb2013-06-28 02:30:2122#include "base/time/time.h"
estade5e5529d2015-05-21 20:59:1123#include "base/values.h"
[email protected]6d81b482011-02-22 19:47:1924#include "net/base/host_port_pair.h"
[email protected]b8430722008-09-17 20:05:4425#include "net/base/load_flags.h"
initial.commit586acc5fe2008-07-26 22:42:5226#include "net/base/net_errors.h"
[email protected]636eccd2011-06-28 12:28:0127#include "net/base/network_delegate.h"
tbansal79ed5cd2015-08-10 18:53:5628#include "net/base/network_quality_estimator.h"
[email protected]60889422008-09-23 01:18:1629#include "net/base/sdch_manager.h"
baranovichc5e38652014-11-14 03:08:1530#include "net/base/sdch_net_log_params.h"
tfarina7a4a7fd2016-01-20 14:23:4431#include "net/base/url_util.h"
[email protected]6e7845ae2013-03-29 21:48:1132#include "net/cert/cert_status_flags.h"
[email protected]dc8313a2014-03-24 21:38:1433#include "net/cookies/cookie_store.h"
[email protected]262191712014-03-22 00:46:5734#include "net/http/http_content_disposition.h"
[email protected]7a299a92012-10-24 23:54:5035#include "net/http/http_network_session.h"
[email protected]8c76ae22010-04-20 22:15:4336#include "net/http/http_request_headers.h"
[email protected]319d9e6f2009-02-18 19:47:2137#include "net/http/http_response_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5238#include "net/http/http_response_info.h"
[email protected]9094b602012-02-27 21:44:5839#include "net/http/http_status_code.h"
initial.commit586acc5fe2008-07-26 22:42:5240#include "net/http/http_transaction.h"
41#include "net/http/http_transaction_factory.h"
[email protected]0757e7702009-03-27 04:00:2242#include "net/http/http_util.h"
[email protected]597a1ab2014-06-26 08:12:2743#include "net/proxy/proxy_info.h"
[email protected]536fd0b2013-03-14 17:41:5744#include "net/ssl/ssl_cert_request_info.h"
45#include "net/ssl/ssl_config_service.h"
[email protected]ee4c30d2012-11-07 15:08:4346#include "net/url_request/http_user_agent_settings.h"
initial.commit586acc5fe2008-07-26 22:42:5247#include "net/url_request/url_request.h"
xunjieli3bb781a2015-07-22 22:40:3448#include "net/url_request/url_request_backoff_manager.h"
[email protected]319d9e6f2009-02-18 19:47:2149#include "net/url_request/url_request_context.h"
initial.commit586acc5fe2008-07-26 22:42:5250#include "net/url_request/url_request_error_job.h"
[email protected]e0f35c92013-05-08 16:04:3451#include "net/url_request/url_request_job_factory.h"
[email protected]06965e02009-09-04 21:36:4252#include "net/url_request/url_request_redirect_job.h"
[email protected]6b3f9642010-11-25 02:29:0653#include "net/url_request/url_request_throttler_manager.h"
[email protected]f4533ba2013-11-28 09:35:4154#include "net/websockets/websocket_handshake_stream_base.h"
mkwst8241a122015-10-20 07:15:1055#include "url/origin.h"
initial.commit586acc5fe2008-07-26 22:42:5256
[email protected]8c76ae22010-04-20 22:15:4357static const char kAvailDictionaryHeader[] = "Avail-Dictionary";
58
mkwst202534e32016-01-15 16:07:1559namespace {
60
61// True if the request method is "safe" (per section 4.2.1 of RFC 7231).
62bool IsMethodSafe(const std::string& method) {
63 return method == "GET" || method == "HEAD" || method == "OPTIONS" ||
64 method == "TRACE";
65}
66
67} // namespace
68
[email protected]4f5656c62010-12-13 10:47:0969namespace net {
70
[email protected]2e92354c2011-03-25 20:49:5371class URLRequestHttpJob::HttpFilterContext : public FilterContext {
72 public:
73 explicit HttpFilterContext(URLRequestHttpJob* job);
dchengb03027d2014-10-21 12:00:2074 ~HttpFilterContext() override;
[email protected]2e92354c2011-03-25 20:49:5375
76 // FilterContext implementation.
dchengb03027d2014-10-21 12:00:2077 bool GetMimeType(std::string* mime_type) const override;
78 bool GetURL(GURL* gurl) const override;
dchengb03027d2014-10-21 12:00:2079 base::Time GetRequestTime() const override;
80 bool IsCachedContent() const override;
rdsmith81f607562014-11-21 18:35:1681 SdchManager::DictionarySet* SdchDictionariesAdvertised() const override;
Avi Drissman13fc8932015-12-20 04:40:4682 int64_t GetByteReadCount() const override;
dchengb03027d2014-10-21 12:00:2083 int GetResponseCode() const override;
84 const URLRequestContext* GetURLRequestContext() const override;
85 void RecordPacketStats(StatisticSelector statistic) const override;
baranovichc5e38652014-11-14 03:08:1586 const BoundNetLog& GetNetLog() const override;
[email protected]2e92354c2011-03-25 20:49:5387
88 private:
89 URLRequestHttpJob* job_;
90
baranovichc5e38652014-11-14 03:08:1591 // URLRequestHttpJob may be detached from URLRequest, but we still need to
92 // return something.
93 BoundNetLog dummy_log_;
94
[email protected]2e92354c2011-03-25 20:49:5395 DISALLOW_COPY_AND_ASSIGN(HttpFilterContext);
96};
97
[email protected]fc01f232011-03-17 19:06:0198URLRequestHttpJob::HttpFilterContext::HttpFilterContext(URLRequestHttpJob* job)
99 : job_(job) {
100 DCHECK(job_);
101}
102
103URLRequestHttpJob::HttpFilterContext::~HttpFilterContext() {
104}
105
106bool URLRequestHttpJob::HttpFilterContext::GetMimeType(
107 std::string* mime_type) const {
108 return job_->GetMimeType(mime_type);
109}
110
111bool URLRequestHttpJob::HttpFilterContext::GetURL(GURL* gurl) const {
112 if (!job_->request())
113 return false;
114 *gurl = job_->request()->url();
115 return true;
116}
117
118base::Time URLRequestHttpJob::HttpFilterContext::GetRequestTime() const {
119 return job_->request() ? job_->request()->request_time() : base::Time();
120}
121
122bool URLRequestHttpJob::HttpFilterContext::IsCachedContent() const {
[email protected]dd29bcd72011-03-24 00:03:44123 return job_->is_cached_content_;
[email protected]fc01f232011-03-17 19:06:01124}
125
rdsmith81f607562014-11-21 18:35:16126SdchManager::DictionarySet*
127URLRequestHttpJob::HttpFilterContext::SdchDictionariesAdvertised() const {
128 return job_->dictionaries_advertised_.get();
[email protected]fc01f232011-03-17 19:06:01129}
130
Avi Drissman13fc8932015-12-20 04:40:46131int64_t URLRequestHttpJob::HttpFilterContext::GetByteReadCount() const {
mmenkebbf19be22015-04-11 02:44:48132 return job_->prefilter_bytes_read();
[email protected]fc01f232011-03-17 19:06:01133}
134
135int URLRequestHttpJob::HttpFilterContext::GetResponseCode() const {
136 return job_->GetResponseCode();
137}
138
[email protected]6a586762014-06-15 16:02:22139const URLRequestContext*
140URLRequestHttpJob::HttpFilterContext::GetURLRequestContext() const {
141 return job_->request() ? job_->request()->context() : NULL;
142}
143
[email protected]fc01f232011-03-17 19:06:01144void URLRequestHttpJob::HttpFilterContext::RecordPacketStats(
145 StatisticSelector statistic) const {
146 job_->RecordPacketStats(statistic);
147}
148
baranovichc5e38652014-11-14 03:08:15149const BoundNetLog& URLRequestHttpJob::HttpFilterContext::GetNetLog() const {
150 return job_->request() ? job_->request()->net_log() : dummy_log_;
151}
152
initial.commit586acc5fe2008-07-26 22:42:52153// TODO(darin): make sure the port blocking code is not lost
initial.commit586acc5fe2008-07-26 22:42:52154// static
[email protected]4f5656c62010-12-13 10:47:09155URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
[email protected]9f170462012-08-24 01:06:58156 NetworkDelegate* network_delegate,
[email protected]4f5656c62010-12-13 10:47:09157 const std::string& scheme) {
[email protected]f4533ba2013-11-28 09:35:41158 DCHECK(scheme == "http" || scheme == "https" || scheme == "ws" ||
159 scheme == "wss");
initial.commit586acc5fe2008-07-26 22:42:52160
[email protected]81293f482012-08-13 19:35:45161 if (!request->context()->http_transaction_factory()) {
initial.commit586acc5fe2008-07-26 22:42:52162 NOTREACHED() << "requires a valid context";
[email protected]9f170462012-08-24 01:06:58163 return new URLRequestErrorJob(
164 request, network_delegate, ERR_INVALID_ARGUMENT);
initial.commit586acc5fe2008-07-26 22:42:52165 }
166
[email protected]ce572df2012-05-04 19:47:17167 GURL redirect_url;
[email protected]8ccc69f2012-11-28 19:52:14168 if (request->GetHSTSRedirect(&redirect_url)) {
169 return new URLRequestRedirectJob(
170 request, network_delegate, redirect_url,
171 // Use status code 307 to preserve the method, so POST requests work.
[email protected]7983c4a2014-03-12 01:47:09172 URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT, "HSTS");
[email protected]8ccc69f2012-11-28 19:52:14173 }
[email protected]ee4c30d2012-11-07 15:08:43174 return new URLRequestHttpJob(request,
175 network_delegate,
176 request->context()->http_user_agent_settings());
initial.commit586acc5fe2008-07-26 22:42:52177}
178
[email protected]ee4c30d2012-11-07 15:08:43179URLRequestHttpJob::URLRequestHttpJob(
180 URLRequest* request,
181 NetworkDelegate* network_delegate,
182 const HttpUserAgentSettings* http_user_agent_settings)
[email protected]9f170462012-08-24 01:06:58183 : URLRequestJob(request, network_delegate),
[email protected]5033ab82013-03-22 20:17:46184 priority_(DEFAULT_PRIORITY),
mmenke54e82af2016-02-16 23:06:30185 response_info_(nullptr),
[email protected]4f5656c62010-12-13 10:47:09186 proxy_auth_state_(AUTH_STATE_DONT_NEED_AUTH),
187 server_auth_state_(AUTH_STATE_DONT_NEED_AUTH),
[email protected]dd946bb2013-06-12 22:53:01188 start_callback_(base::Bind(&URLRequestHttpJob::OnStartCompleted,
189 base::Unretained(this))),
190 notify_before_headers_sent_callback_(
191 base::Bind(&URLRequestHttpJob::NotifyBeforeSendHeadersCallback,
192 base::Unretained(this))),
[email protected]3589e552008-08-20 23:11:34193 read_in_progress_(false),
mmenke54e82af2016-02-16 23:06:30194 throttling_entry_(nullptr),
[email protected]5b90b5d2009-04-30 23:06:01195 sdch_test_activated_(false),
[email protected]d8fd5132009-05-15 01:06:53196 sdch_test_control_(false),
[email protected]00e48bf2010-12-03 06:15:42197 is_cached_content_(false),
[email protected]ec23f522011-02-22 21:01:38198 request_creation_time_(),
[email protected]dd29bcd72011-03-24 00:03:44199 packet_timing_enabled_(false),
[email protected]bbaea8f2011-06-24 00:11:01200 done_(false),
[email protected]dd29bcd72011-03-24 00:03:44201 bytes_observed_in_packets_(0),
[email protected]dd29bcd72011-03-24 00:03:44202 request_time_snapshot_(),
203 final_packet_time_(),
[email protected]aa249b52013-04-30 01:04:32204 filter_context_(new HttpFilterContext(this)),
[email protected]dd946bb2013-06-12 22:53:01205 on_headers_received_callback_(
206 base::Bind(&URLRequestHttpJob::OnHeadersReceivedCallback,
207 base::Unretained(this))),
[email protected]5a07c192012-07-30 20:18:22208 awaiting_callback_(false),
[email protected]09812102014-05-24 00:04:11209 http_user_agent_settings_(http_user_agent_settings),
xunjieli3bb781a2015-07-22 22:40:34210 backoff_manager_(request->context()->backoff_manager()),
sclittlece72c482015-08-24 20:20:59211 total_received_bytes_from_previous_transactions_(0),
sclittlefb249892015-09-10 21:33:22212 total_sent_bytes_from_previous_transactions_(0),
[email protected]09812102014-05-24 00:04:11213 weak_factory_(this) {
[email protected]a73a2802012-05-02 19:20:15214 URLRequestThrottlerManager* manager = request->context()->throttler_manager();
215 if (manager)
216 throttling_entry_ = manager->RegisterRequestUrl(request->url());
217
[email protected]ec23f522011-02-22 21:01:38218 ResetTimer();
initial.commit586acc5fe2008-07-26 22:42:52219}
220
[email protected]5033ab82013-03-22 20:17:46221URLRequestHttpJob::~URLRequestHttpJob() {
222 CHECK(!awaiting_callback_);
223
224 DCHECK(!sdch_test_control_ || !sdch_test_activated_);
225 if (!is_cached_content_) {
226 if (sdch_test_control_)
227 RecordPacketStats(FilterContext::SDCH_EXPERIMENT_HOLDBACK);
228 if (sdch_test_activated_)
229 RecordPacketStats(FilterContext::SDCH_EXPERIMENT_DECODE);
230 }
231 // Make sure SDCH filters are told to emit histogram data while
232 // filter_context_ is still alive.
233 DestroyFilters();
234
[email protected]5033ab82013-03-22 20:17:46235 DoneWithRequest(ABORTED);
236}
237
238void URLRequestHttpJob::SetPriority(RequestPriority priority) {
239 priority_ = priority;
240 if (transaction_)
241 transaction_->SetPriority(priority_);
242}
243
244void URLRequestHttpJob::Start() {
mmenke833437d2015-04-23 20:56:54245 // TODO(mmenke): Remove ScopedTracker below once crbug.com/456327 is fixed.
246 tracked_objects::ScopedTracker tracking_profile(
247 FROM_HERE_WITH_EXPLICIT_FUNCTION("456327 URLRequestHttpJob::Start"));
248
[email protected]5033ab82013-03-22 20:17:46249 DCHECK(!transaction_.get());
250
[email protected]99ecf6e2013-04-10 22:46:13251 // URLRequest::SetReferrer ensures that we do not send username and password
252 // fields in the referrer.
253 GURL referrer(request_->referrer());
[email protected]5033ab82013-03-22 20:17:46254
255 request_info_.url = request_->url();
256 request_info_.method = request_->method();
257 request_info_.load_flags = request_->load_flags();
[email protected]e6d017652013-05-17 18:01:40258 // Enable privacy mode if cookie settings or flags tell us not send or
259 // save cookies.
260 bool enable_privacy_mode =
261 (request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES) ||
262 (request_info_.load_flags & LOAD_DO_NOT_SAVE_COOKIES) ||
263 CanEnablePrivacyMode();
mkwste3e95992016-02-23 17:45:41264 // Privacy mode could still be disabled in SetCookieHeaderAndStart if we are
265 // going to send previously saved cookies.
[email protected]e6d017652013-05-17 18:01:40266 request_info_.privacy_mode = enable_privacy_mode ?
[email protected]314b03992014-04-01 01:28:53267 PRIVACY_MODE_ENABLED : PRIVACY_MODE_DISABLED;
[email protected]5033ab82013-03-22 20:17:46268
269 // Strip Referer from request_info_.extra_headers to prevent, e.g., plugins
270 // from overriding headers that are controlled using other means. Otherwise a
271 // plugin could set a referrer although sending the referrer is inhibited.
272 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kReferer);
273
rdsmith81f607562014-11-21 18:35:16274 // Our consumer should have made sure that this is a safe referrer. See for
[email protected]5033ab82013-03-22 20:17:46275 // instance WebCore::FrameLoader::HideReferrer.
276 if (referrer.is_valid()) {
277 request_info_.extra_headers.SetHeader(HttpRequestHeaders::kReferer,
278 referrer.spec());
279 }
280
281 request_info_.extra_headers.SetHeaderIfMissing(
282 HttpRequestHeaders::kUserAgent,
283 http_user_agent_settings_ ?
[email protected]aa051272014-03-10 05:56:56284 http_user_agent_settings_->GetUserAgent() : std::string());
[email protected]5033ab82013-03-22 20:17:46285
286 AddExtraHeaders();
287 AddCookieHeaderAndStart();
288}
289
290void URLRequestHttpJob::Kill() {
[email protected]5033ab82013-03-22 20:17:46291 weak_factory_.InvalidateWeakPtrs();
mmenke2281f3762015-11-02 20:38:17292 if (transaction_)
293 DestroyTransaction();
[email protected]5033ab82013-03-22 20:17:46294 URLRequestJob::Kill();
295}
296
ttuttle3ae06922015-05-11 23:41:52297void URLRequestHttpJob::GetConnectionAttempts(ConnectionAttempts* out) const {
298 if (transaction_)
299 transaction_->GetConnectionAttempts(out);
300 else
301 out->clear();
302}
303
[email protected]597a1ab2014-06-26 08:12:27304void URLRequestHttpJob::NotifyBeforeSendProxyHeadersCallback(
[email protected]1252d42f2014-07-01 21:20:20305 const ProxyInfo& proxy_info,
306 HttpRequestHeaders* request_headers) {
307 DCHECK(request_headers);
[email protected]597a1ab2014-06-26 08:12:27308 DCHECK_NE(URLRequestStatus::CANCELED, GetStatus().status());
309 if (network_delegate()) {
310 network_delegate()->NotifyBeforeSendProxyHeaders(
311 request_,
312 proxy_info,
[email protected]1252d42f2014-07-01 21:20:20313 request_headers);
[email protected]597a1ab2014-06-26 08:12:27314 }
315}
316
xunjieli3bb781a2015-07-22 22:40:34317void URLRequestHttpJob::NotifyBeforeNetworkStart(bool* defer) {
318 if (!request_)
319 return;
320 if (backoff_manager_) {
xunjieli33550b842015-09-24 22:26:58321 if ((request_->load_flags() & LOAD_MAYBE_USER_GESTURE) == 0 &&
322 backoff_manager_->ShouldRejectRequest(request()->url(),
xunjieli3bb781a2015-07-22 22:40:34323 request()->request_time())) {
324 *defer = true;
325 base::MessageLoop::current()->PostTask(
326 FROM_HERE,
327 base::Bind(&URLRequestHttpJob::OnStartCompleted,
328 weak_factory_.GetWeakPtr(), ERR_TEMPORARY_BACKOFF));
329 return;
330 }
331 }
332 URLRequestJob::NotifyBeforeNetworkStart(defer);
333}
334
[email protected]175adac2008-07-30 17:28:04335void URLRequestHttpJob::NotifyHeadersComplete() {
initial.commit586acc5fe2008-07-26 22:42:52336 DCHECK(!response_info_);
337
338 response_info_ = transaction_->GetResponseInfo();
339
[email protected]d8fd5132009-05-15 01:06:53340 // Save boolean, as we'll need this info at destruction time, and filters may
341 // also need this info.
342 is_cached_content_ = response_info_->was_cached;
343
xunjieli041e9392015-05-19 21:51:33344 if (!is_cached_content_ && throttling_entry_.get())
345 throttling_entry_->UpdateWithResponse(GetResponseCode());
[email protected]6b3f9642010-11-25 02:29:06346
xunjieli3bb781a2015-07-22 22:40:34347 if (!is_cached_content_)
348 ProcessBackoffHeader();
349
[email protected]fecef222012-01-05 02:26:15350 // The ordering of these calls is not important.
[email protected]77f6fb432009-09-05 14:21:09351 ProcessStrictTransportSecurityHeader();
[email protected]fecef222012-01-05 02:26:15352 ProcessPublicKeyPinsHeader();
[email protected]a9cea7542009-05-20 04:30:23353
rdsmith81f607562014-11-21 18:35:16354 // Handle the server notification of a new SDCH dictionary.
[email protected]6a586762014-06-15 16:02:22355 SdchManager* sdch_manager(request()->context()->sdch_manager());
baranovichc5e38652014-11-14 03:08:15356 if (sdch_manager) {
357 SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
358 if (rv != SDCH_OK) {
ellyjones085ac462015-08-18 12:02:53359 SdchManager::SdchErrorRecovery(rv);
360 request()->net_log().AddEvent(
361 NetLog::TYPE_SDCH_DECODING_ERROR,
362 base::Bind(&NetLogSdchResourceProblemCallback, rv));
baranovichc5e38652014-11-14 03:08:15363 } else {
364 const std::string name = "Get-Dictionary";
365 std::string url_text;
olli.raulaee489a52016-01-25 08:37:10366 size_t iter = 0;
baranovichc5e38652014-11-14 03:08:15367 // TODO(jar): We need to not fetch dictionaries the first time they are
368 // seen, but rather wait until we can justify their usefulness.
369 // For now, we will only fetch the first dictionary, which will at least
370 // require multiple suggestions before we get additional ones for this
371 // site. Eventually we should wait until a dictionary is requested
372 // several times
373 // before we even download it (so that we don't waste memory or
374 // bandwidth).
375 if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) {
376 // Resolve suggested URL relative to request url.
377 GURL sdch_dictionary_url = request_->url().Resolve(url_text);
Bacek41dc425d2016-01-28 22:45:35378 // Don't try to download Dictionary for cached responses. It's either
379 // useless or too late.
380 if (sdch_dictionary_url.is_valid() && !is_cached_content_) {
baranovichc5e38652014-11-14 03:08:15381 rv = sdch_manager->OnGetDictionary(request_->url(),
382 sdch_dictionary_url);
383 if (rv != SDCH_OK) {
384 SdchManager::SdchErrorRecovery(rv);
385 request_->net_log().AddEvent(
386 NetLog::TYPE_SDCH_DICTIONARY_ERROR,
387 base::Bind(&NetLogSdchDictionaryFetchProblemCallback, rv,
388 sdch_dictionary_url, false));
389 }
390 }
[email protected]6a586762014-06-15 16:02:22391 }
[email protected]60889422008-09-23 01:18:16392 }
393 }
394
rdsmith81f607562014-11-21 18:35:16395 // Handle the server signalling no SDCH encoding.
396 if (dictionaries_advertised_) {
397 // We are wary of proxies that discard or damage SDCH encoding. If a server
398 // explicitly states that this is not SDCH content, then we can correct our
399 // assumption that this is an SDCH response, and avoid the need to recover
400 // as though the content is corrupted (when we discover it is not SDCH
401 // encoded).
402 std::string sdch_response_status;
olli.raulaee489a52016-01-25 08:37:10403 size_t iter = 0;
rdsmith81f607562014-11-21 18:35:16404 while (GetResponseHeaders()->EnumerateHeader(&iter, "X-Sdch-Encode",
405 &sdch_response_status)) {
406 if (sdch_response_status == "0") {
407 dictionaries_advertised_.reset();
408 break;
409 }
410 }
411 }
412
[email protected]0757e7702009-03-27 04:00:22413 // The HTTP transaction may be restarted several times for the purposes
414 // of sending authorization information. Each time it restarts, we get
415 // notified of the headers completion so that we can update the cookie store.
416 if (transaction_->IsReadyToRestartForAuth()) {
417 DCHECK(!response_info_->auth_challenge.get());
[email protected]87a09a92011-07-14 15:50:50418 // TODO(battre): This breaks the webrequest API for
419 // URLRequestTestHTTP.BasicAuthWithCookies
[email protected]5796dc942011-07-14 19:26:10420 // where OnBeforeSendHeaders -> OnSendHeaders -> OnBeforeSendHeaders
[email protected]87a09a92011-07-14 15:50:50421 // occurs.
[email protected]f3cf9802011-10-28 18:44:58422 RestartTransactionWithAuth(AuthCredentials());
[email protected]0757e7702009-03-27 04:00:22423 return;
424 }
425
[email protected]4f5656c62010-12-13 10:47:09426 URLRequestJob::NotifyHeadersComplete();
initial.commit586acc5fe2008-07-26 22:42:52427}
428
[email protected]175adac2008-07-30 17:28:04429void URLRequestHttpJob::DestroyTransaction() {
[email protected]c6a4eb92010-03-03 23:51:19430 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52431
[email protected]bbaea8f2011-06-24 00:11:01432 DoneWithRequest(ABORTED);
sclittlece72c482015-08-24 20:20:59433
434 total_received_bytes_from_previous_transactions_ +=
435 transaction_->GetTotalReceivedBytes();
sclittlefb249892015-09-10 21:33:22436 total_sent_bytes_from_previous_transactions_ +=
437 transaction_->GetTotalSentBytes();
[email protected]af4876d2008-10-21 23:10:57438 transaction_.reset();
initial.commit586acc5fe2008-07-26 22:42:52439 response_info_ = NULL;
[email protected]3b23a222013-05-15 21:33:25440 receive_headers_end_ = base::TimeTicks();
initial.commit586acc5fe2008-07-26 22:42:52441}
442
[email protected]175adac2008-07-30 17:28:04443void URLRequestHttpJob::StartTransaction() {
mmenke833437d2015-04-23 20:56:54444 // TODO(mmenke): Remove ScopedTracker below once crbug.com/456327 is fixed.
445 tracked_objects::ScopedTracker tracking_profile(
446 FROM_HERE_WITH_EXPLICIT_FUNCTION(
447 "456327 URLRequestHttpJob::StartTransaction"));
448
[email protected]cc05edc2013-03-08 18:04:41449 if (network_delegate()) {
[email protected]abe1c4a2013-10-25 19:28:51450 OnCallToDelegate();
[email protected]cc05edc2013-03-08 18:04:41451 int rv = network_delegate()->NotifyBeforeSendHeaders(
[email protected]084262c2011-12-01 21:12:47452 request_, notify_before_headers_sent_callback_,
[email protected]636eccd2011-06-28 12:28:01453 &request_info_.extra_headers);
454 // If an extension blocks the request, we rely on the callback to
[email protected]b4438d32012-09-27 06:15:30455 // MaybeStartTransactionInternal().
[email protected]abe1c4a2013-10-25 19:28:51456 if (rv == ERR_IO_PENDING)
[email protected]636eccd2011-06-28 12:28:01457 return;
[email protected]b4438d32012-09-27 06:15:30458 MaybeStartTransactionInternal(rv);
459 return;
[email protected]636eccd2011-06-28 12:28:01460 }
461 StartTransactionInternal();
462}
463
464void URLRequestHttpJob::NotifyBeforeSendHeadersCallback(int result) {
[email protected]9045b8822012-01-13 20:35:35465 // Check that there are no callbacks to already canceled requests.
466 DCHECK_NE(URLRequestStatus::CANCELED, GetStatus().status());
467
[email protected]b4438d32012-09-27 06:15:30468 MaybeStartTransactionInternal(result);
469}
470
471void URLRequestHttpJob::MaybeStartTransactionInternal(int result) {
mmenke833437d2015-04-23 20:56:54472 // TODO(mmenke): Remove ScopedTracker below once crbug.com/456327 is fixed.
473 tracked_objects::ScopedTracker tracking_profile(
474 FROM_HERE_WITH_EXPLICIT_FUNCTION(
475 "456327 URLRequestHttpJob::MaybeStartTransactionInternal"));
476
[email protected]abe1c4a2013-10-25 19:28:51477 OnCallToDelegateComplete();
[email protected]636eccd2011-06-28 12:28:01478 if (result == OK) {
479 StartTransactionInternal();
480 } else {
[email protected]55b8a6c12012-06-13 22:03:42481 std::string source("delegate");
[email protected]636eccd2011-06-28 12:28:01482 request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
[email protected]55b8a6c12012-06-13 22:03:42483 NetLog::StringCallback("source", &source));
[email protected]b4438d32012-09-27 06:15:30484 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
[email protected]636eccd2011-06-28 12:28:01485 }
486}
487
488void URLRequestHttpJob::StartTransactionInternal() {
mmenke4600b602015-10-28 18:52:17489 // This should only be called while the request's status is IO_PENDING.
mmenke2281f3762015-11-02 20:38:17490 DCHECK_EQ(URLRequestStatus::IO_PENDING, request_->status().status());
mmenke4600b602015-10-28 18:52:17491
initial.commit586acc5fe2008-07-26 22:42:52492 // NOTE: This method assumes that request_info_ is already setup properly.
493
[email protected]34602282010-02-03 22:14:15494 // If we already have a transaction, then we should restart the transaction
[email protected]f3cf9802011-10-28 18:44:58495 // with auth provided by auth_credentials_.
initial.commit586acc5fe2008-07-26 22:42:52496
hiroshigecb76caa4c52015-12-22 07:50:25497 bool invalid_header_values_in_rfc7230 = false;
498 for (HttpRequestHeaders::Iterator it(request_info_.extra_headers);
499 it.GetNext();) {
500 if (!HttpUtil::IsValidHeaderValueRFC7230(it.value())) {
501 invalid_header_values_in_rfc7230 = true;
502 break;
503 }
504 }
505 UMA_HISTOGRAM_BOOLEAN("Net.HttpRequest.ContainsInvalidHeaderValuesInRFC7230",
506 invalid_header_values_in_rfc7230);
507
[email protected]99c07902010-08-17 18:59:52508 int rv;
[email protected]6b3f9642010-11-25 02:29:06509
[email protected]cc05edc2013-03-08 18:04:41510 if (network_delegate()) {
511 network_delegate()->NotifySendHeaders(
[email protected]5796dc942011-07-14 19:26:10512 request_, request_info_.extra_headers);
513 }
514
[email protected]34602282010-02-03 22:14:15515 if (transaction_.get()) {
[email protected]49639fa2011-12-20 23:22:41516 rv = transaction_->RestartWithAuth(auth_credentials_, start_callback_);
[email protected]f3cf9802011-10-28 18:44:58517 auth_credentials_ = AuthCredentials();
[email protected]34602282010-02-03 22:14:15518 } else {
[email protected]34602282010-02-03 22:14:15519 DCHECK(request_->context()->http_transaction_factory());
initial.commit586acc5fe2008-07-26 22:42:52520
[email protected]99c07902010-08-17 18:59:52521 rv = request_->context()->http_transaction_factory()->CreateTransaction(
[email protected]027bd85a2013-12-27 22:39:10522 priority_, &transaction_);
[email protected]f4533ba2013-11-28 09:35:41523
524 if (rv == OK && request_info_.url.SchemeIsWSOrWSS()) {
[email protected]f4533ba2013-11-28 09:35:41525 base::SupportsUserData::Data* data = request_->GetUserData(
526 WebSocketHandshakeStreamBase::CreateHelper::DataKey());
527 if (data) {
528 transaction_->SetWebSocketHandshakeStreamCreateHelper(
529 static_cast<WebSocketHandshakeStreamBase::CreateHelper*>(data));
530 } else {
531 rv = ERR_DISALLOWED_URL_SCHEME;
532 }
533 }
534
[email protected]4f5656c62010-12-13 10:47:09535 if (rv == OK) {
[email protected]a45840b2014-01-10 15:40:22536 transaction_->SetBeforeNetworkStartCallback(
537 base::Bind(&URLRequestHttpJob::NotifyBeforeNetworkStart,
538 base::Unretained(this)));
[email protected]597a1ab2014-06-26 08:12:27539 transaction_->SetBeforeProxyHeadersSentCallback(
540 base::Bind(&URLRequestHttpJob::NotifyBeforeSendProxyHeadersCallback,
541 base::Unretained(this)));
[email protected]a45840b2014-01-10 15:40:22542
dchengc2e01e82014-08-27 00:24:42543 if (!throttling_entry_.get() ||
xunjieli41edcdd2015-06-24 14:26:40544 !throttling_entry_->ShouldRejectRequest(*request_)) {
[email protected]227b0e82011-03-25 21:11:53545 rv = transaction_->Start(
[email protected]49639fa2011-12-20 23:22:41546 &request_info_, start_callback_, request_->net_log());
[email protected]bbaea8f2011-06-24 00:11:01547 start_time_ = base::TimeTicks::Now();
[email protected]227b0e82011-03-25 21:11:53548 } else {
549 // Special error code for the exponential back-off module.
550 rv = ERR_TEMPORARILY_THROTTLED;
551 }
[email protected]34602282010-02-03 22:14:15552 }
initial.commit586acc5fe2008-07-26 22:42:52553 }
554
[email protected]4f5656c62010-12-13 10:47:09555 if (rv == ERR_IO_PENDING)
[email protected]34602282010-02-03 22:14:15556 return;
557
initial.commit586acc5fe2008-07-26 22:42:52558 // The transaction started synchronously, but we need to notify the
[email protected]4f5656c62010-12-13 10:47:09559 // URLRequest delegate via the message loop.
skyostil4891b25b2015-06-11 11:43:45560 base::ThreadTaskRunnerHandle::Get()->PostTask(
561 FROM_HERE, base::Bind(&URLRequestHttpJob::OnStartCompleted,
562 weak_factory_.GetWeakPtr(), rv));
initial.commit586acc5fe2008-07-26 22:42:52563}
564
[email protected]175adac2008-07-30 17:28:04565void URLRequestHttpJob::AddExtraHeaders() {
[email protected]6a586762014-06-15 16:02:22566 SdchManager* sdch_manager = request()->context()->sdch_manager();
567
[email protected]c7bef94c2011-06-21 18:05:51568 // Supply Accept-Encoding field only if it is not already provided.
569 // It should be provided IF the content is known to have restrictions on
570 // potential encoding, such as streaming multi-media.
571 // For details see bug 47381.
572 // TODO(jar, enal): jpeg files etc. should set up a request header if
573 // possible. Right now it is done only by buffered_resource_loader and
574 // simple_data_source.
575 if (!request_info_.extra_headers.HasHeader(
576 HttpRequestHeaders::kAcceptEncoding)) {
baranovichc5e38652014-11-14 03:08:15577 // We don't support SDCH responses to POST as there is a possibility
578 // of having SDCH encoded responses returned (e.g. by the cache)
579 // which we cannot decode, and in those situations, we will need
580 // to retransmit the request without SDCH, which is illegal for a POST.
581 bool advertise_sdch = sdch_manager != NULL && request()->method() != "POST";
582 if (advertise_sdch) {
583 SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
584 if (rv != SDCH_OK) {
585 advertise_sdch = false;
ellyjones085ac462015-08-18 12:02:53586 SdchManager::SdchErrorRecovery(rv);
587 request()->net_log().AddEvent(
588 NetLog::TYPE_SDCH_DECODING_ERROR,
589 base::Bind(&NetLogSdchResourceProblemCallback, rv));
baranovichc5e38652014-11-14 03:08:15590 }
591 }
[email protected]c7bef94c2011-06-21 18:05:51592 if (advertise_sdch) {
rdsmith81f607562014-11-21 18:35:16593 dictionaries_advertised_ =
594 sdch_manager->GetDictionarySet(request_->url());
595 }
[email protected]5b90b5d2009-04-30 23:06:01596
rdsmith81f607562014-11-21 18:35:16597 // The AllowLatencyExperiment() is only true if we've successfully done a
598 // full SDCH compression recently in this browser session for this host.
599 // Note that for this path, there might be no applicable dictionaries,
600 // and hence we can't participate in the experiment.
601 if (dictionaries_advertised_ &&
602 sdch_manager->AllowLatencyExperiment(request_->url())) {
603 // We are participating in the test (or control), and hence we'll
604 // eventually record statistics via either SDCH_EXPERIMENT_DECODE or
605 // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data.
606 packet_timing_enabled_ = true;
607 if (base::RandDouble() < .01) {
608 sdch_test_control_ = true; // 1% probability.
609 dictionaries_advertised_.reset();
610 advertise_sdch = false;
611 } else {
612 sdch_test_activated_ = true;
[email protected]5b90b5d2009-04-30 23:06:01613 }
614 }
[email protected]5b90b5d2009-04-30 23:06:01615
eustasfbec9132015-12-30 14:56:51616 // Advertise "br" encoding only if transferred data is opaque to proxy.
617 bool advertise_brotli = false;
618 const HttpNetworkSession::Params* network_session_params =
619 request()->context()->GetNetworkSessionParams();
620 if (network_session_params && network_session_params->enable_brotli)
621 advertise_brotli = request()->url().SchemeIsCryptographic();
622
[email protected]c7bef94c2011-06-21 18:05:51623 // Supply Accept-Encoding headers first so that it is more likely that they
rdsmith81f607562014-11-21 18:35:16624 // will be in the first transmitted packet. This can sometimes make it
[email protected]c7bef94c2011-06-21 18:05:51625 // easier to filter and analyze the streams to assure that a proxy has not
rdsmith81f607562014-11-21 18:35:16626 // damaged these headers. Some proxies deliberately corrupt Accept-Encoding
[email protected]c7bef94c2011-06-21 18:05:51627 // headers.
eustasfbec9132015-12-30 14:56:51628 std::string advertised_encodings = "gzip, deflate";
629 if (advertise_sdch)
630 advertised_encodings += ", sdch";
631 if (advertise_brotli)
632 advertised_encodings += ", br";
633 // Tell the server what compression formats are supported.
634 request_info_.extra_headers.SetHeader(HttpRequestHeaders::kAcceptEncoding,
635 advertised_encodings);
636
637 if (dictionaries_advertised_) {
[email protected]8c76ae22010-04-20 22:15:43638 request_info_.extra_headers.SetHeader(
eustasfbec9132015-12-30 14:56:51639 kAvailDictionaryHeader,
640 dictionaries_advertised_->GetDictionaryClientHashList());
641 // Since we're tagging this transaction as advertising a dictionary,
642 // we'll definitely employ an SDCH filter (or tentative sdch filter)
643 // when we get a response. When done, we'll record histograms via
644 // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet
645 // arrival times.
646 packet_timing_enabled_ = true;
[email protected]423041b2008-10-27 17:39:28647 }
[email protected]423041b2008-10-27 17:39:28648 }
649
[email protected]ee4c30d2012-11-07 15:08:43650 if (http_user_agent_settings_) {
[email protected]84f05432013-03-15 01:00:12651 // Only add default Accept-Language if the request didn't have it
652 // specified.
[email protected]ee4c30d2012-11-07 15:08:43653 std::string accept_language =
654 http_user_agent_settings_->GetAcceptLanguage();
655 if (!accept_language.empty()) {
656 request_info_.extra_headers.SetHeaderIfMissing(
657 HttpRequestHeaders::kAcceptLanguage,
658 accept_language);
659 }
initial.commit586acc5fe2008-07-26 22:42:52660 }
initial.commit586acc5fe2008-07-26 22:42:52661}
662
[email protected]34602282010-02-03 22:14:15663void URLRequestHttpJob::AddCookieHeaderAndStart() {
[email protected]ed24fad2011-05-10 22:44:01664 // If the request was destroyed, then there is no more work to do.
665 if (!request_)
666 return;
[email protected]34602282010-02-03 22:14:15667
davidben151423e2015-03-23 18:48:36668 CookieStore* cookie_store = request_->context()->cookie_store();
[email protected]1a6fff52011-10-20 21:00:16669 if (cookie_store && !(request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES)) {
mkwste3e95992016-02-23 17:45:41670 CookieOptions options;
671 options.set_include_httponly();
672
673 // TODO(mkwst): If same-site cookies aren't enabled, pretend the request is
674 // same-site regardless, in order to include all cookies. Drop this check
675 // once we decide whether or not we're shipping this feature:
676 // https://crbug.com/459154
677 url::Origin requested_origin(request_->url());
678 if (!network_delegate() ||
679 !network_delegate()->AreExperimentalCookieFeaturesEnabled()) {
680 options.set_include_same_site();
681 } else if (requested_origin.IsSameOriginWith(
682 url::Origin(request_->first_party_for_cookies())) &&
683 (IsMethodSafe(request_->method()) ||
684 requested_origin.IsSameOriginWith(request_->initiator()))) {
685 options.set_include_same_site();
686 }
687
688 cookie_store->GetCookieListWithOptionsAsync(
689 request_->url(), options,
690 base::Bind(&URLRequestHttpJob::SetCookieHeaderAndStart,
[email protected]dc8313a2014-03-24 21:38:14691 weak_factory_.GetWeakPtr()));
[email protected]03d845f2011-07-29 19:06:26692 } else {
693 DoStartTransaction();
694 }
695}
696
mkwste3e95992016-02-23 17:45:41697void URLRequestHttpJob::SetCookieHeaderAndStart(const CookieList& cookie_list) {
698 if (cookie_list.size() && CanGetCookies(cookie_list)) {
[email protected]54f4c9362011-07-25 21:54:46699 request_info_.extra_headers.SetHeader(
mkwste3e95992016-02-23 17:45:41700 HttpRequestHeaders::kCookie, CookieStore::BuildCookieLine(cookie_list));
[email protected]e6d017652013-05-17 18:01:40701 // Disable privacy mode as we are sending cookies anyway.
[email protected]314b03992014-04-01 01:28:53702 request_info_.privacy_mode = PRIVACY_MODE_DISABLED;
[email protected]54f4c9362011-07-25 21:54:46703 }
[email protected]54f4c9362011-07-25 21:54:46704 DoStartTransaction();
705}
706
707void URLRequestHttpJob::DoStartTransaction() {
[email protected]03d845f2011-07-29 19:06:26708 // We may have been canceled while retrieving cookies.
[email protected]9025016c2011-05-12 15:51:23709 if (GetStatus().is_success()) {
710 StartTransaction();
711 } else {
712 NotifyCanceled();
713 }
[email protected]0757e7702009-03-27 04:00:22714}
715
[email protected]ea8141e2011-10-05 13:12:51716void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
[email protected]abe1c4a2013-10-25 19:28:51717 // End of the call started in OnStartCompleted.
718 OnCallToDelegateComplete();
719
ttuttle859dc7a2015-04-23 19:42:29720 if (result != OK) {
[email protected]55b8a6c12012-06-13 22:03:42721 std::string source("delegate");
[email protected]ea8141e2011-10-05 13:12:51722 request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
[email protected]55b8a6c12012-06-13 22:03:42723 NetLog::StringCallback("source", &source));
[email protected]ea8141e2011-10-05 13:12:51724 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
725 return;
726 }
727
mmenke54e82af2016-02-16 23:06:30728 std::vector<std::string> response_cookies;
729 FetchResponseCookies(&response_cookies);
initial.commit586acc5fe2008-07-26 22:42:52730
mmenke54e82af2016-02-16 23:06:30731 base::Time response_date;
732 if (!GetResponseHeaders()->GetDateValue(&response_date))
733 response_date = base::Time();
[email protected]263163f2012-06-14 22:40:34734
735 if (!(request_info_.load_flags & LOAD_DO_NOT_SAVE_COOKIES) &&
mmenke54e82af2016-02-16 23:06:30736 request_->context()->cookie_store()) {
[email protected]263163f2012-06-14 22:40:34737 CookieOptions options;
738 options.set_include_httponly();
mmenke54e82af2016-02-16 23:06:30739 options.set_server_time(response_date);
jww79aceda2015-12-07 01:56:34740
estarkf1dc4442015-12-01 19:31:15741 if (network_delegate() &&
jww79aceda2015-12-07 01:56:34742 network_delegate()->AreStrictSecureCookiesEnabled()) {
743 options.set_enforce_strict_secure();
744 }
745
mmenke54e82af2016-02-16 23:06:30746 // Set all cookies, without waiting for them to be set. Any subsequent read
747 // will see the combined result of all cookie operation.
748 for (const std::string& cookie : response_cookies) {
749 if (!CanSetCookie(cookie, &options))
750 continue;
751 request_->context()->cookie_store()->SetCookieWithOptionsAsync(
752 request_->url(), cookie, options, CookieStore::SetCookiesCallback());
[email protected]263163f2012-06-14 22:40:34753 }
754 }
755
mmenke54e82af2016-02-16 23:06:30756 NotifyHeadersComplete();
[email protected]34602282010-02-03 22:14:15757}
758
759void URLRequestHttpJob::FetchResponseCookies(
[email protected]34602282010-02-03 22:14:15760 std::vector<std::string>* cookies) {
[email protected]264300242011-11-07 06:03:30761 const std::string name = "Set-Cookie";
initial.commit586acc5fe2008-07-26 22:42:52762 std::string value;
763
olli.raulaee489a52016-01-25 08:37:10764 size_t iter = 0;
[email protected]ea8141e2011-10-05 13:12:51765 HttpResponseHeaders* headers = GetResponseHeaders();
766 while (headers->EnumerateHeader(&iter, name, &value)) {
[email protected]2adf2882010-09-27 08:30:37767 if (!value.empty())
768 cookies->push_back(value);
769 }
initial.commit586acc5fe2008-07-26 22:42:52770}
[email protected]a9cea7542009-05-20 04:30:23771
xunjieli3bb781a2015-07-22 22:40:34772void URLRequestHttpJob::ProcessBackoffHeader() {
773 DCHECK(response_info_);
774
775 if (!backoff_manager_)
776 return;
777
778 TransportSecurityState* security_state =
779 request_->context()->transport_security_state();
780 const SSLInfo& ssl_info = response_info_->ssl_info;
781
782 // Only accept Backoff headers on HTTPS connections that have no
783 // certificate errors.
784 if (!ssl_info.is_valid() || IsCertStatusError(ssl_info.cert_status) ||
785 !security_state)
786 return;
787
788 backoff_manager_->UpdateWithResponse(request()->url(), GetResponseHeaders(),
789 base::Time::Now());
790}
791
[email protected]000d9df02012-01-18 20:01:46792// NOTE: |ProcessStrictTransportSecurityHeader| and
793// |ProcessPublicKeyPinsHeader| have very similar structures, by design.
[email protected]77f6fb432009-09-05 14:21:09794void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
[email protected]a9cea7542009-05-20 04:30:23795 DCHECK(response_info_);
[email protected]6ed72be2013-01-08 22:07:33796 TransportSecurityState* security_state =
797 request_->context()->transport_security_state();
[email protected]e88006f2012-01-11 06:15:07798 const SSLInfo& ssl_info = response_info_->ssl_info;
[email protected]a9cea7542009-05-20 04:30:23799
[email protected]6ed72be2013-01-08 22:07:33800 // Only accept HSTS headers on HTTPS connections that have no
801 // certificate errors.
[email protected]e88006f2012-01-11 06:15:07802 if (!ssl_info.is_valid() || IsCertStatusError(ssl_info.cert_status) ||
[email protected]6ed72be2013-01-08 22:07:33803 !security_state)
[email protected]e88006f2012-01-11 06:15:07804 return;
[email protected]326e6792009-12-11 21:04:42805
estarka5da76702015-04-09 04:00:16806 // Don't accept HSTS headers when the hostname is an IP address.
807 if (request_info_.url.HostIsIPAddress())
808 return;
809
[email protected]242d8562012-10-30 21:20:46810 // http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec:
811 //
812 // If a UA receives more than one STS header field in a HTTP response
813 // message over secure transport, then the UA MUST process only the
814 // first such header field.
[email protected]6ed72be2013-01-08 22:07:33815 HttpResponseHeaders* headers = GetResponseHeaders();
816 std::string value;
olli.raulaee489a52016-01-25 08:37:10817 if (headers->EnumerateHeader(nullptr, "Strict-Transport-Security", &value))
[email protected]6ed72be2013-01-08 22:07:33818 security_state->AddHSTSHeader(request_info_.url.host(), value);
[email protected]a9cea7542009-05-20 04:30:23819}
[email protected]4f5656c62010-12-13 10:47:09820
[email protected]fecef222012-01-05 02:26:15821void URLRequestHttpJob::ProcessPublicKeyPinsHeader() {
822 DCHECK(response_info_);
[email protected]6ed72be2013-01-08 22:07:33823 TransportSecurityState* security_state =
824 request_->context()->transport_security_state();
[email protected]fecef222012-01-05 02:26:15825 const SSLInfo& ssl_info = response_info_->ssl_info;
826
[email protected]6ed72be2013-01-08 22:07:33827 // Only accept HPKP headers on HTTPS connections that have no
[email protected]e88006f2012-01-11 06:15:07828 // certificate errors.
[email protected]fecef222012-01-05 02:26:15829 if (!ssl_info.is_valid() || IsCertStatusError(ssl_info.cert_status) ||
[email protected]6ed72be2013-01-08 22:07:33830 !security_state)
[email protected]fecef222012-01-05 02:26:15831 return;
[email protected]fecef222012-01-05 02:26:15832
estarka5da76702015-04-09 04:00:16833 // Don't accept HSTS headers when the hostname is an IP address.
834 if (request_info_.url.HostIsIPAddress())
835 return;
836
estark53fee7c2015-08-03 18:31:51837 // http://tools.ietf.org/html/rfc7469:
[email protected]6ed72be2013-01-08 22:07:33838 //
839 // If a UA receives more than one PKP header field in an HTTP
840 // response message over secure transport, then the UA MUST process
841 // only the first such header field.
[email protected]fecef222012-01-05 02:26:15842 HttpResponseHeaders* headers = GetResponseHeaders();
[email protected]fecef222012-01-05 02:26:15843 std::string value;
estark53fee7c2015-08-03 18:31:51844 if (headers->EnumerateHeader(nullptr, "Public-Key-Pins", &value))
[email protected]6ed72be2013-01-08 22:07:33845 security_state->AddHPKPHeader(request_info_.url.host(), value, ssl_info);
estark53fee7c2015-08-03 18:31:51846 if (headers->EnumerateHeader(nullptr, "Public-Key-Pins-Report-Only",
847 &value)) {
848 security_state->ProcessHPKPReportOnlyHeader(
849 value, HostPortPair::FromURL(request_info_.url), ssl_info);
850 }
[email protected]fecef222012-01-05 02:26:15851}
852
[email protected]5394e422011-01-20 22:07:43853void URLRequestHttpJob::OnStartCompleted(int result) {
[email protected]ec23f522011-02-22 21:01:38854 RecordTimer();
855
[email protected]5394e422011-01-20 22:07:43856 // If the request was destroyed, then there is no more work to do.
[email protected]a83dd332011-07-13 10:41:01857 if (!request_)
[email protected]5394e422011-01-20 22:07:43858 return;
859
[email protected]80abdad2014-03-15 00:20:54860 // If the job is done (due to cancellation), can just ignore this
861 // notification.
862 if (done_)
[email protected]5394e422011-01-20 22:07:43863 return;
864
[email protected]3b23a222013-05-15 21:33:25865 receive_headers_end_ = base::TimeTicks::Now();
866
[email protected]ef2bf422012-05-11 03:27:09867 const URLRequestContext* context = request_->context();
868
[email protected]5394e422011-01-20 22:07:43869 if (result == OK) {
[email protected]d8fc4722014-06-13 13:17:15870 if (transaction_ && transaction_->GetResponseInfo()) {
871 SetProxyServer(transaction_->GetResponseInfo()->proxy_server);
872 }
[email protected]ea8141e2011-10-05 13:12:51873 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
hiroshigecb76caa4c52015-12-22 07:50:25874
875 if (headers) {
olli.raula33c282f2016-01-21 12:12:49876 size_t iter = 0;
hiroshigecb76caa4c52015-12-22 07:50:25877 std::string name;
878 std::string value;
879 bool invalid_header_values_in_rfc7230 = false;
880 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
881 if (!HttpUtil::IsValidHeaderValueRFC7230(value)) {
882 invalid_header_values_in_rfc7230 = true;
883 break;
884 }
885 }
886 UMA_HISTOGRAM_BOOLEAN(
887 "Net.HttpResponse.ContainsInvalidHeaderValuesInRFC7230",
888 invalid_header_values_in_rfc7230);
889 }
890
[email protected]cc05edc2013-03-08 18:04:41891 if (network_delegate()) {
[email protected]ea8141e2011-10-05 13:12:51892 // Note that |this| may not be deleted until
893 // |on_headers_received_callback_| or
894 // |NetworkDelegate::URLRequestDestroyed()| has been called.
[email protected]abe1c4a2013-10-25 19:28:51895 OnCallToDelegate();
[email protected]5f714132014-03-26 10:41:16896 allowed_unsafe_redirect_url_ = GURL();
[email protected]cc05edc2013-03-08 18:04:41897 int error = network_delegate()->NotifyHeadersReceived(
[email protected]90499482013-06-01 00:39:50898 request_,
899 on_headers_received_callback_,
900 headers.get(),
[email protected]5f714132014-03-26 10:41:16901 &override_response_headers_,
902 &allowed_unsafe_redirect_url_);
ttuttle859dc7a2015-04-23 19:42:29903 if (error != OK) {
904 if (error == ERR_IO_PENDING) {
[email protected]ea8141e2011-10-05 13:12:51905 awaiting_callback_ = true;
[email protected]ea8141e2011-10-05 13:12:51906 } else {
[email protected]55b8a6c12012-06-13 22:03:42907 std::string source("delegate");
[email protected]ea8141e2011-10-05 13:12:51908 request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
[email protected]55b8a6c12012-06-13 22:03:42909 NetLog::StringCallback("source",
910 &source));
[email protected]abe1c4a2013-10-25 19:28:51911 OnCallToDelegateComplete();
[email protected]ea8141e2011-10-05 13:12:51912 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, error));
913 }
914 return;
915 }
916 }
917
ttuttle859dc7a2015-04-23 19:42:29918 SaveCookiesAndNotifyHeadersComplete(OK);
[email protected]e5624f02011-09-27 19:43:53919 } else if (IsCertificateError(result)) {
[email protected]6061c142013-10-21 15:13:34920 // We encountered an SSL certificate error.
921 if (result == ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY ||
922 result == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN) {
923 // These are hard failures. They're handled separately and don't have
924 // the correct cert status, so set it here.
925 SSLInfo info(transaction_->GetResponseInfo()->ssl_info);
926 info.cert_status = MapNetErrorToCertStatus(result);
927 NotifySSLCertificateError(info, true);
928 } else {
929 // Maybe overridable, maybe not. Ask the delegate to decide.
[email protected]9e6968d2014-05-07 21:46:26930 TransportSecurityState* state = context->transport_security_state();
931 const bool fatal =
Adam Langley5cbb7d7a2014-09-25 23:14:12932 state && state->ShouldSSLErrorsBeFatal(request_info_.url.host());
[email protected]6061c142013-10-21 15:13:34933 NotifySSLCertificateError(
934 transaction_->GetResponseInfo()->ssl_info, fatal);
935 }
[email protected]5394e422011-01-20 22:07:43936 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]a83dd332011-07-13 10:41:01937 NotifyCertificateRequested(
[email protected]90499482013-06-01 00:39:50938 transaction_->GetResponseInfo()->cert_request_info.get());
[email protected]5394e422011-01-20 22:07:43939 } else {
[email protected]419704c2014-01-14 11:18:06940 // Even on an error, there may be useful information in the response
941 // info (e.g. whether there's a cached copy).
942 if (transaction_.get())
943 response_info_ = transaction_->GetResponseInfo();
[email protected]5394e422011-01-20 22:07:43944 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
945 }
946}
947
[email protected]ea8141e2011-10-05 13:12:51948void URLRequestHttpJob::OnHeadersReceivedCallback(int result) {
[email protected]ea8141e2011-10-05 13:12:51949 awaiting_callback_ = false;
[email protected]9045b8822012-01-13 20:35:35950
951 // Check that there are no callbacks to already canceled requests.
952 DCHECK_NE(URLRequestStatus::CANCELED, GetStatus().status());
953
[email protected]ea8141e2011-10-05 13:12:51954 SaveCookiesAndNotifyHeadersComplete(result);
955}
956
[email protected]5394e422011-01-20 22:07:43957void URLRequestHttpJob::OnReadCompleted(int result) {
958 read_in_progress_ = false;
959
xunjieli26ede962015-11-23 19:39:13960 DCHECK_NE(ERR_IO_PENDING, result);
961
[email protected]f001bd6a2011-12-08 04:31:37962 if (ShouldFixMismatchedContentLength(result))
[email protected]5543cbb2012-04-20 16:35:23963 result = OK;
[email protected]f001bd6a2011-12-08 04:31:37964
xunjieli26ede962015-11-23 19:39:13965 // EOF or error, done with this job.
966 if (result <= 0)
967 DoneWithRequest(FINISHED);
[email protected]5394e422011-01-20 22:07:43968
xunjieli26ede962015-11-23 19:39:13969 ReadRawDataComplete(result);
[email protected]5394e422011-01-20 22:07:43970}
971
[email protected]5394e422011-01-20 22:07:43972void URLRequestHttpJob::RestartTransactionWithAuth(
[email protected]f3cf9802011-10-28 18:44:58973 const AuthCredentials& credentials) {
974 auth_credentials_ = credentials;
[email protected]5394e422011-01-20 22:07:43975
976 // These will be reset in OnStartCompleted.
977 response_info_ = NULL;
[email protected]3b23a222013-05-15 21:33:25978 receive_headers_end_ = base::TimeTicks();
[email protected]5394e422011-01-20 22:07:43979
[email protected]ec23f522011-02-22 21:01:38980 ResetTimer();
981
[email protected]5394e422011-01-20 22:07:43982 // Update the cookies, since the cookie store may have been updated from the
983 // headers in the 401/407. Since cookies were already appended to
984 // extra_headers, we need to strip them out before adding them again.
[email protected]ea8141e2011-10-05 13:12:51985 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kCookie);
[email protected]5394e422011-01-20 22:07:43986
987 AddCookieHeaderAndStart();
988}
989
[email protected]0736d9e2012-11-28 19:50:40990void URLRequestHttpJob::SetUpload(UploadDataStream* upload) {
[email protected]5394e422011-01-20 22:07:43991 DCHECK(!transaction_.get()) << "cannot change once started";
[email protected]0736d9e2012-11-28 19:50:40992 request_info_.upload_data_stream = upload;
[email protected]5394e422011-01-20 22:07:43993}
994
995void URLRequestHttpJob::SetExtraRequestHeaders(
996 const HttpRequestHeaders& headers) {
997 DCHECK(!transaction_.get()) << "cannot change once started";
998 request_info_.extra_headers.CopyFrom(headers);
999}
1000
[email protected]5394e422011-01-20 22:07:431001LoadState URLRequestHttpJob::GetLoadState() const {
1002 return transaction_.get() ?
1003 transaction_->GetLoadState() : LOAD_STATE_IDLE;
1004}
1005
[email protected]7335ab02012-08-30 22:30:421006UploadProgress URLRequestHttpJob::GetUploadProgress() const {
1007 return transaction_.get() ?
1008 transaction_->GetUploadProgress() : UploadProgress();
[email protected]5394e422011-01-20 22:07:431009}
1010
1011bool URLRequestHttpJob::GetMimeType(std::string* mime_type) const {
1012 DCHECK(transaction_.get());
1013
1014 if (!response_info_)
1015 return false;
1016
ellyjones0e9d5e82015-02-17 23:06:281017 HttpResponseHeaders* headers = GetResponseHeaders();
1018 if (!headers)
1019 return false;
1020 return headers->GetMimeType(mime_type);
[email protected]5394e422011-01-20 22:07:431021}
1022
1023bool URLRequestHttpJob::GetCharset(std::string* charset) {
1024 DCHECK(transaction_.get());
1025
1026 if (!response_info_)
1027 return false;
1028
[email protected]ea8141e2011-10-05 13:12:511029 return GetResponseHeaders()->GetCharset(charset);
[email protected]5394e422011-01-20 22:07:431030}
1031
1032void URLRequestHttpJob::GetResponseInfo(HttpResponseInfo* info) {
1033 DCHECK(request_);
[email protected]5394e422011-01-20 22:07:431034
[email protected]ea8141e2011-10-05 13:12:511035 if (response_info_) {
[email protected]419704c2014-01-14 11:18:061036 DCHECK(transaction_.get());
1037
[email protected]5394e422011-01-20 22:07:431038 *info = *response_info_;
[email protected]90499482013-06-01 00:39:501039 if (override_response_headers_.get())
[email protected]ea8141e2011-10-05 13:12:511040 info->headers = override_response_headers_;
1041 }
[email protected]5394e422011-01-20 22:07:431042}
1043
[email protected]58e32bb2013-01-21 18:23:251044void URLRequestHttpJob::GetLoadTimingInfo(
1045 LoadTimingInfo* load_timing_info) const {
[email protected]3b23a222013-05-15 21:33:251046 // If haven't made it far enough to receive any headers, don't return
rdsmith81f607562014-11-21 18:35:161047 // anything. This makes for more consistent behavior in the case of errors.
[email protected]3b23a222013-05-15 21:33:251048 if (!transaction_ || receive_headers_end_.is_null())
1049 return;
1050 if (transaction_->GetLoadTimingInfo(load_timing_info))
1051 load_timing_info->receive_headers_end = receive_headers_end_;
[email protected]58e32bb2013-01-21 18:23:251052}
1053
ttuttled9dbc652015-09-29 20:00:591054bool URLRequestHttpJob::GetRemoteEndpoint(IPEndPoint* endpoint) const {
1055 if (!transaction_)
1056 return false;
1057
1058 return transaction_->GetRemoteEndpoint(endpoint);
1059}
1060
[email protected]ea8141e2011-10-05 13:12:511061bool URLRequestHttpJob::GetResponseCookies(std::vector<std::string>* cookies) {
[email protected]5394e422011-01-20 22:07:431062 DCHECK(transaction_.get());
1063
1064 if (!response_info_)
1065 return false;
1066
[email protected]5394e422011-01-20 22:07:431067 cookies->clear();
[email protected]ea8141e2011-10-05 13:12:511068 FetchResponseCookies(cookies);
[email protected]5394e422011-01-20 22:07:431069 return true;
1070}
1071
1072int URLRequestHttpJob::GetResponseCode() const {
1073 DCHECK(transaction_.get());
1074
1075 if (!response_info_)
1076 return -1;
1077
[email protected]ea8141e2011-10-05 13:12:511078 return GetResponseHeaders()->response_code();
[email protected]5394e422011-01-20 22:07:431079}
1080
zhongyi48704c182015-12-07 07:52:021081void URLRequestHttpJob::PopulateNetErrorDetails(
1082 NetErrorDetails* details) const {
1083 if (!transaction_)
1084 return;
1085 return transaction_->PopulateNetErrorDetails(details);
1086}
1087
[email protected]5a3b4d32011-03-17 01:24:051088Filter* URLRequestHttpJob::SetupFilter() const {
[email protected]5394e422011-01-20 22:07:431089 DCHECK(transaction_.get());
1090 if (!response_info_)
[email protected]5a3b4d32011-03-17 01:24:051091 return NULL;
[email protected]5394e422011-01-20 22:07:431092
[email protected]5a3b4d32011-03-17 01:24:051093 std::vector<Filter::FilterType> encoding_types;
[email protected]5394e422011-01-20 22:07:431094 std::string encoding_type;
[email protected]ea8141e2011-10-05 13:12:511095 HttpResponseHeaders* headers = GetResponseHeaders();
olli.raulaee489a52016-01-25 08:37:101096 size_t iter = 0;
[email protected]ea8141e2011-10-05 13:12:511097 while (headers->EnumerateHeader(&iter, "Content-Encoding", &encoding_type)) {
[email protected]5a3b4d32011-03-17 01:24:051098 encoding_types.push_back(Filter::ConvertEncodingToType(encoding_type));
[email protected]5394e422011-01-20 22:07:431099 }
1100
1101 // Even if encoding types are empty, there is a chance that we need to add
1102 // some decoding, as some proxies strip encoding completely. In such cases,
1103 // we may need to add (for example) SDCH filtering (when the context suggests
1104 // it is appropriate).
[email protected]2e92354c2011-03-25 20:49:531105 Filter::FixupEncodingTypes(*filter_context_, &encoding_types);
[email protected]5394e422011-01-20 22:07:431106
[email protected]5a3b4d32011-03-17 01:24:051107 return !encoding_types.empty()
[email protected]2e92354c2011-03-25 20:49:531108 ? Filter::Factory(encoding_types, *filter_context_) : NULL;
[email protected]5394e422011-01-20 22:07:431109}
1110
[email protected]f878230e2014-04-03 15:36:141111bool URLRequestHttpJob::CopyFragmentOnRedirect(const GURL& location) const {
1112 // Allow modification of reference fragments by default, unless
1113 // |allowed_unsafe_redirect_url_| is set and equal to the redirect URL.
1114 // When this is the case, we assume that the network delegate has set the
1115 // desired redirect URL (with or without fragment), so it must not be changed
1116 // any more.
1117 return !allowed_unsafe_redirect_url_.is_valid() ||
1118 allowed_unsafe_redirect_url_ != location;
1119}
1120
[email protected]5394e422011-01-20 22:07:431121bool URLRequestHttpJob::IsSafeRedirect(const GURL& location) {
[email protected]e0f35c92013-05-08 16:04:341122 // HTTP is always safe.
1123 // TODO(pauljensen): Remove once crbug.com/146591 is fixed.
1124 if (location.is_valid() &&
1125 (location.scheme() == "http" || location.scheme() == "https")) {
[email protected]5394e422011-01-20 22:07:431126 return true;
[email protected]5394e422011-01-20 22:07:431127 }
[email protected]f878230e2014-04-03 15:36:141128 // Delegates may mark a URL as safe for redirection.
1129 if (allowed_unsafe_redirect_url_.is_valid() &&
1130 allowed_unsafe_redirect_url_ == location) {
1131 return true;
[email protected]5f714132014-03-26 10:41:161132 }
[email protected]e0f35c92013-05-08 16:04:341133 // Query URLRequestJobFactory as to whether |location| would be safe to
1134 // redirect to.
1135 return request_->context()->job_factory() &&
1136 request_->context()->job_factory()->IsSafeRedirectTarget(location);
[email protected]5394e422011-01-20 22:07:431137}
1138
1139bool URLRequestHttpJob::NeedsAuth() {
1140 int code = GetResponseCode();
1141 if (code == -1)
1142 return false;
1143
rdsmith81f607562014-11-21 18:35:161144 // Check if we need either Proxy or WWW Authentication. This could happen
[email protected]5394e422011-01-20 22:07:431145 // because we either provided no auth info, or provided incorrect info.
1146 switch (code) {
1147 case 407:
1148 if (proxy_auth_state_ == AUTH_STATE_CANCELED)
1149 return false;
1150 proxy_auth_state_ = AUTH_STATE_NEED_AUTH;
1151 return true;
1152 case 401:
1153 if (server_auth_state_ == AUTH_STATE_CANCELED)
1154 return false;
1155 server_auth_state_ = AUTH_STATE_NEED_AUTH;
1156 return true;
1157 }
1158 return false;
1159}
1160
1161void URLRequestHttpJob::GetAuthChallengeInfo(
1162 scoped_refptr<AuthChallengeInfo>* result) {
1163 DCHECK(transaction_.get());
1164 DCHECK(response_info_);
1165
1166 // sanity checks:
1167 DCHECK(proxy_auth_state_ == AUTH_STATE_NEED_AUTH ||
1168 server_auth_state_ == AUTH_STATE_NEED_AUTH);
[email protected]9094b602012-02-27 21:44:581169 DCHECK((GetResponseHeaders()->response_code() == HTTP_UNAUTHORIZED) ||
1170 (GetResponseHeaders()->response_code() ==
1171 HTTP_PROXY_AUTHENTICATION_REQUIRED));
[email protected]5394e422011-01-20 22:07:431172
1173 *result = response_info_->auth_challenge;
1174}
1175
[email protected]f3cf9802011-10-28 18:44:581176void URLRequestHttpJob::SetAuth(const AuthCredentials& credentials) {
[email protected]5394e422011-01-20 22:07:431177 DCHECK(transaction_.get());
1178
1179 // Proxy gets set first, then WWW.
1180 if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
1181 proxy_auth_state_ = AUTH_STATE_HAVE_AUTH;
1182 } else {
[email protected]dd29bcd72011-03-24 00:03:441183 DCHECK_EQ(server_auth_state_, AUTH_STATE_NEED_AUTH);
[email protected]5394e422011-01-20 22:07:431184 server_auth_state_ = AUTH_STATE_HAVE_AUTH;
1185 }
1186
[email protected]f3cf9802011-10-28 18:44:581187 RestartTransactionWithAuth(credentials);
[email protected]5394e422011-01-20 22:07:431188}
1189
1190void URLRequestHttpJob::CancelAuth() {
1191 // Proxy gets set first, then WWW.
1192 if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
1193 proxy_auth_state_ = AUTH_STATE_CANCELED;
1194 } else {
[email protected]dd29bcd72011-03-24 00:03:441195 DCHECK_EQ(server_auth_state_, AUTH_STATE_NEED_AUTH);
[email protected]5394e422011-01-20 22:07:431196 server_auth_state_ = AUTH_STATE_CANCELED;
1197 }
1198
1199 // These will be reset in OnStartCompleted.
1200 response_info_ = NULL;
[email protected]3b23a222013-05-15 21:33:251201 receive_headers_end_ = base::TimeTicks::Now();
[email protected]5394e422011-01-20 22:07:431202
[email protected]ec23f522011-02-22 21:01:381203 ResetTimer();
1204
[email protected]5394e422011-01-20 22:07:431205 // OK, let the consumer read the error page...
1206 //
1207 // Because we set the AUTH_STATE_CANCELED flag, NeedsAuth will return false,
1208 // which will cause the consumer to receive OnResponseStarted instead of
1209 // OnAuthRequired.
1210 //
1211 // We have to do this via InvokeLater to avoid "recursing" the consumer.
1212 //
skyostil4891b25b2015-06-11 11:43:451213 base::ThreadTaskRunnerHandle::Get()->PostTask(
1214 FROM_HERE, base::Bind(&URLRequestHttpJob::OnStartCompleted,
1215 weak_factory_.GetWeakPtr(), OK));
[email protected]5394e422011-01-20 22:07:431216}
1217
1218void URLRequestHttpJob::ContinueWithCertificate(
svaldez7872fd02015-11-19 21:10:541219 X509Certificate* client_cert,
1220 SSLPrivateKey* client_private_key) {
[email protected]5394e422011-01-20 22:07:431221 DCHECK(transaction_.get());
1222
1223 DCHECK(!response_info_) << "should not have a response yet";
[email protected]3b23a222013-05-15 21:33:251224 receive_headers_end_ = base::TimeTicks();
[email protected]5394e422011-01-20 22:07:431225
[email protected]ec23f522011-02-22 21:01:381226 ResetTimer();
1227
svaldez7872fd02015-11-19 21:10:541228 int rv = transaction_->RestartWithCertificate(client_cert, client_private_key,
1229 start_callback_);
[email protected]5394e422011-01-20 22:07:431230 if (rv == ERR_IO_PENDING)
1231 return;
1232
1233 // The transaction started synchronously, but we need to notify the
1234 // URLRequest delegate via the message loop.
skyostil4891b25b2015-06-11 11:43:451235 base::ThreadTaskRunnerHandle::Get()->PostTask(
1236 FROM_HERE, base::Bind(&URLRequestHttpJob::OnStartCompleted,
1237 weak_factory_.GetWeakPtr(), rv));
[email protected]5394e422011-01-20 22:07:431238}
1239
1240void URLRequestHttpJob::ContinueDespiteLastError() {
1241 // If the transaction was destroyed, then the job was cancelled.
1242 if (!transaction_.get())
1243 return;
1244
1245 DCHECK(!response_info_) << "should not have a response yet";
[email protected]3b23a222013-05-15 21:33:251246 receive_headers_end_ = base::TimeTicks();
[email protected]5394e422011-01-20 22:07:431247
[email protected]ec23f522011-02-22 21:01:381248 ResetTimer();
1249
[email protected]49639fa2011-12-20 23:22:411250 int rv = transaction_->RestartIgnoringLastError(start_callback_);
[email protected]5394e422011-01-20 22:07:431251 if (rv == ERR_IO_PENDING)
1252 return;
1253
1254 // The transaction started synchronously, but we need to notify the
1255 // URLRequest delegate via the message loop.
skyostil4891b25b2015-06-11 11:43:451256 base::ThreadTaskRunnerHandle::Get()->PostTask(
1257 FROM_HERE, base::Bind(&URLRequestHttpJob::OnStartCompleted,
1258 weak_factory_.GetWeakPtr(), rv));
[email protected]5394e422011-01-20 22:07:431259}
1260
[email protected]1826a402014-01-08 15:40:481261void URLRequestHttpJob::ResumeNetworkStart() {
1262 DCHECK(transaction_.get());
1263 transaction_->ResumeNetworkStart();
1264}
1265
[email protected]f001bd6a2011-12-08 04:31:371266bool URLRequestHttpJob::ShouldFixMismatchedContentLength(int rv) const {
1267 // Some servers send the body compressed, but specify the content length as
rdsmith81f607562014-11-21 18:35:161268 // the uncompressed size. Although this violates the HTTP spec we want to
[email protected]f001bd6a2011-12-08 04:31:371269 // support it (as IE and FireFox do), but *only* for an exact match.
1270 // See http://crbug.com/79694.
ttuttle859dc7a2015-04-23 19:42:291271 if (rv == ERR_CONTENT_LENGTH_MISMATCH ||
1272 rv == ERR_INCOMPLETE_CHUNKED_ENCODING) {
[email protected]f001bd6a2011-12-08 04:31:371273 if (request_ && request_->response_headers()) {
Avi Drissman13fc8932015-12-20 04:40:461274 int64_t expected_length =
1275 request_->response_headers()->GetContentLength();
[email protected]f001bd6a2011-12-08 04:31:371276 VLOG(1) << __FUNCTION__ << "() "
1277 << "\"" << request_->url().spec() << "\""
1278 << " content-length = " << expected_length
1279 << " pre total = " << prefilter_bytes_read()
1280 << " post total = " << postfilter_bytes_read();
1281 if (postfilter_bytes_read() == expected_length) {
1282 // Clear the error.
1283 return true;
1284 }
1285 }
1286 }
1287 return false;
1288}
1289
xunjieli26ede962015-11-23 19:39:131290int URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size) {
[email protected]5394e422011-01-20 22:07:431291 DCHECK_NE(buf_size, 0);
[email protected]5394e422011-01-20 22:07:431292 DCHECK(!read_in_progress_);
1293
[email protected]49639fa2011-12-20 23:22:411294 int rv = transaction_->Read(
1295 buf, buf_size,
1296 base::Bind(&URLRequestHttpJob::OnReadCompleted, base::Unretained(this)));
[email protected]85c1dce2011-07-06 12:01:291297
[email protected]f001bd6a2011-12-08 04:31:371298 if (ShouldFixMismatchedContentLength(rv))
xunjieli26ede962015-11-23 19:39:131299 rv = OK;
[email protected]f001bd6a2011-12-08 04:31:371300
xunjieli26ede962015-11-23 19:39:131301 if (rv == 0 || (rv < 0 && rv != ERR_IO_PENDING))
1302 DoneWithRequest(FINISHED);
[email protected]5394e422011-01-20 22:07:431303
xunjieli26ede962015-11-23 19:39:131304 if (rv == ERR_IO_PENDING)
[email protected]5394e422011-01-20 22:07:431305 read_in_progress_ = true;
[email protected]5394e422011-01-20 22:07:431306
xunjieli26ede962015-11-23 19:39:131307 return rv;
[email protected]5394e422011-01-20 22:07:431308}
1309
1310void URLRequestHttpJob::StopCaching() {
1311 if (transaction_.get())
1312 transaction_->StopCaching();
1313}
1314
[email protected]79e1fd62013-06-20 06:50:041315bool URLRequestHttpJob::GetFullRequestHeaders(
1316 HttpRequestHeaders* headers) const {
1317 if (!transaction_)
1318 return false;
1319
1320 return transaction_->GetFullRequestHeaders(headers);
1321}
1322
Avi Drissman13fc8932015-12-20 04:40:461323int64_t URLRequestHttpJob::GetTotalReceivedBytes() const {
sclittlece72c482015-08-24 20:20:591324 int64_t total_received_bytes =
1325 total_received_bytes_from_previous_transactions_;
1326 if (transaction_)
1327 total_received_bytes += transaction_->GetTotalReceivedBytes();
1328 return total_received_bytes;
[email protected]71e5ff8f2014-01-13 09:44:041329}
1330
sclittlefb249892015-09-10 21:33:221331int64_t URLRequestHttpJob::GetTotalSentBytes() const {
1332 int64_t total_sent_bytes = total_sent_bytes_from_previous_transactions_;
1333 if (transaction_)
1334 total_sent_bytes += transaction_->GetTotalSentBytes();
1335 return total_sent_bytes;
1336}
1337
[email protected]5c04f722011-08-12 17:52:471338void URLRequestHttpJob::DoneReading() {
[email protected]e50efea2014-03-24 18:41:001339 if (transaction_) {
[email protected]5c04f722011-08-12 17:52:471340 transaction_->DoneReading();
[email protected]e50efea2014-03-24 18:41:001341 }
1342 DoneWithRequest(FINISHED);
1343}
1344
1345void URLRequestHttpJob::DoneReadingRedirectResponse() {
1346 if (transaction_) {
1347 if (transaction_->GetResponseInfo()->headers->IsRedirect(NULL)) {
1348 // If the original headers indicate a redirect, go ahead and cache the
1349 // response, even if the |override_response_headers_| are a redirect to
1350 // another location.
1351 transaction_->DoneReading();
1352 } else {
1353 // Otherwise, |override_response_headers_| must be non-NULL and contain
1354 // bogus headers indicating a redirect.
dchengc2e01e82014-08-27 00:24:421355 DCHECK(override_response_headers_.get());
[email protected]e50efea2014-03-24 18:41:001356 DCHECK(override_response_headers_->IsRedirect(NULL));
1357 transaction_->StopCaching();
1358 }
1359 }
[email protected]5c04f722011-08-12 17:52:471360 DoneWithRequest(FINISHED);
1361}
1362
[email protected]6d81b482011-02-22 19:47:191363HostPortPair URLRequestHttpJob::GetSocketAddress() const {
1364 return response_info_ ? response_info_->socket_address : HostPortPair();
1365}
1366
[email protected]ec23f522011-02-22 21:01:381367void URLRequestHttpJob::RecordTimer() {
1368 if (request_creation_time_.is_null()) {
1369 NOTREACHED()
1370 << "The same transaction shouldn't start twice without new timing.";
1371 return;
1372 }
1373
[email protected]320a29f12011-03-21 14:47:411374 base::TimeDelta to_start = base::Time::Now() - request_creation_time_;
[email protected]ec23f522011-02-22 21:01:381375 request_creation_time_ = base::Time();
[email protected]8684a8812011-03-22 13:59:381376
[email protected]5c68d692011-08-24 04:59:411377 UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpTimeToFirstByte", to_start);
[email protected]ec23f522011-02-22 21:01:381378}
1379
1380void URLRequestHttpJob::ResetTimer() {
1381 if (!request_creation_time_.is_null()) {
1382 NOTREACHED()
1383 << "The timer was reset before it was recorded.";
1384 return;
1385 }
1386 request_creation_time_ = base::Time::Now();
1387}
1388
[email protected]dd29bcd72011-03-24 00:03:441389void URLRequestHttpJob::UpdatePacketReadTimes() {
1390 if (!packet_timing_enabled_)
1391 return;
1392
mmenkebbf19be22015-04-11 02:44:481393 DCHECK_GT(prefilter_bytes_read(), bytes_observed_in_packets_);
[email protected]dd29bcd72011-03-24 00:03:441394
[email protected]006ce1a2014-07-30 14:41:231395 base::Time now(base::Time::Now());
[email protected]dd29bcd72011-03-24 00:03:441396 if (!bytes_observed_in_packets_)
[email protected]006ce1a2014-07-30 14:41:231397 request_time_snapshot_ = now;
1398 final_packet_time_ = now;
[email protected]dd29bcd72011-03-24 00:03:441399
mmenkebbf19be22015-04-11 02:44:481400 bytes_observed_in_packets_ = prefilter_bytes_read();
[email protected]dd29bcd72011-03-24 00:03:441401}
1402
1403void URLRequestHttpJob::RecordPacketStats(
1404 FilterContext::StatisticSelector statistic) const {
1405 if (!packet_timing_enabled_ || (final_packet_time_ == base::Time()))
1406 return;
1407
1408 base::TimeDelta duration = final_packet_time_ - request_time_snapshot_;
1409 switch (statistic) {
1410 case FilterContext::SDCH_DECODE: {
[email protected]dd29bcd72011-03-24 00:03:441411 UMA_HISTOGRAM_CUSTOM_COUNTS("Sdch3.Network_Decode_Bytes_Processed_b",
1412 static_cast<int>(bytes_observed_in_packets_), 500, 100000, 100);
[email protected]dd29bcd72011-03-24 00:03:441413 return;
1414 }
1415 case FilterContext::SDCH_PASSTHROUGH: {
1416 // Despite advertising a dictionary, we handled non-sdch compressed
1417 // content.
[email protected]dd29bcd72011-03-24 00:03:441418 return;
1419 }
1420
1421 case FilterContext::SDCH_EXPERIMENT_DECODE: {
[email protected]006ce1a2014-07-30 14:41:231422 UMA_HISTOGRAM_CUSTOM_TIMES("Sdch3.Experiment3_Decode",
[email protected]dd29bcd72011-03-24 00:03:441423 duration,
1424 base::TimeDelta::FromMilliseconds(20),
1425 base::TimeDelta::FromMinutes(10), 100);
[email protected]dd29bcd72011-03-24 00:03:441426 return;
1427 }
1428 case FilterContext::SDCH_EXPERIMENT_HOLDBACK: {
[email protected]006ce1a2014-07-30 14:41:231429 UMA_HISTOGRAM_CUSTOM_TIMES("Sdch3.Experiment3_Holdback",
[email protected]dd29bcd72011-03-24 00:03:441430 duration,
1431 base::TimeDelta::FromMilliseconds(20),
1432 base::TimeDelta::FromMinutes(10), 100);
[email protected]dd29bcd72011-03-24 00:03:441433 return;
1434 }
1435 default:
1436 NOTREACHED();
1437 return;
1438 }
1439}
1440
[email protected]bbaea8f2011-06-24 00:11:011441void URLRequestHttpJob::RecordPerfHistograms(CompletionCause reason) {
1442 if (start_time_.is_null())
1443 return;
1444
1445 base::TimeDelta total_time = base::TimeTicks::Now() - start_time_;
1446 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTime", total_time);
1447
1448 if (reason == FINISHED) {
1449 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeSuccess", total_time);
1450 } else {
1451 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeCancel", total_time);
1452 }
1453
[email protected]4b4d20242012-02-23 18:27:461454 if (response_info_) {
rtennetie55c4b72015-08-03 21:48:351455 // QUIC (by default) supports https scheme only, thus track https URLs only
1456 // for QUIC.
1457 bool is_https_google = request() && request()->url().SchemeIs("https") &&
1458 HasGoogleHost(request()->url());
rtenneti72928bb2015-04-28 18:28:131459 bool used_quic = response_info_->DidUseQuic();
rtennetie55c4b72015-08-03 21:48:351460 if (is_https_google) {
rtenneti72928bb2015-04-28 18:28:131461 if (used_quic) {
rtennetie55c4b72015-08-03 21:48:351462 UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpJob.TotalTime.Secure.Quic",
1463 total_time);
rtenneti72928bb2015-04-28 18:28:131464 } else {
rtennetie55c4b72015-08-03 21:48:351465 UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpJob.TotalTime.Secure.NotQuic",
1466 total_time);
rtenneti72928bb2015-04-28 18:28:131467 }
1468 }
[email protected]4b4d20242012-02-23 18:27:461469 if (response_info_->was_cached) {
1470 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeCached", total_time);
rtennetie55c4b72015-08-03 21:48:351471 if (is_https_google) {
rtenneti72928bb2015-04-28 18:28:131472 if (used_quic) {
rtennetie55c4b72015-08-03 21:48:351473 UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpJob.TotalTimeCached.Secure.Quic",
rtenneti72928bb2015-04-28 18:28:131474 total_time);
1475 } else {
rtennetie55c4b72015-08-03 21:48:351476 UMA_HISTOGRAM_MEDIUM_TIMES(
1477 "Net.HttpJob.TotalTimeCached.Secure.NotQuic", total_time);
rtenneti72928bb2015-04-28 18:28:131478 }
1479 }
[email protected]4b4d20242012-02-23 18:27:461480 } else {
1481 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeNotCached", total_time);
rtennetie55c4b72015-08-03 21:48:351482 if (is_https_google) {
rtenneti72928bb2015-04-28 18:28:131483 if (used_quic) {
rtennetie55c4b72015-08-03 21:48:351484 UMA_HISTOGRAM_MEDIUM_TIMES(
1485 "Net.HttpJob.TotalTimeNotCached.Secure.Quic", total_time);
rtenneti72928bb2015-04-28 18:28:131486 } else {
rtennetie55c4b72015-08-03 21:48:351487 UMA_HISTOGRAM_MEDIUM_TIMES(
1488 "Net.HttpJob.TotalTimeNotCached.Secure.NotQuic", total_time);
rtenneti72928bb2015-04-28 18:28:131489 }
1490 }
[email protected]b73656ca2011-07-22 17:42:171491 }
[email protected]bbaea8f2011-06-24 00:11:011492 }
1493
[email protected]3ed84722013-11-01 17:17:071494 if (request_info_.load_flags & LOAD_PREFETCH && !request_->was_cached())
1495 UMA_HISTOGRAM_COUNTS("Net.Prefetch.PrefilterBytesReadFromNetwork",
1496 prefilter_bytes_read());
1497
[email protected]bbaea8f2011-06-24 00:11:011498 start_time_ = base::TimeTicks();
1499}
1500
1501void URLRequestHttpJob::DoneWithRequest(CompletionCause reason) {
1502 if (done_)
1503 return;
1504 done_ = true;
tbansal79ed5cd2015-08-10 18:53:561505
1506 // Notify NetworkQualityEstimator.
1507 if (request() && (reason == FINISHED || reason == ABORTED)) {
1508 NetworkQualityEstimator* network_quality_estimator =
1509 request()->context()->network_quality_estimator();
1510 if (network_quality_estimator)
1511 network_quality_estimator->NotifyRequestCompleted(*request());
1512 }
1513
[email protected]bbaea8f2011-06-24 00:11:011514 RecordPerfHistograms(reason);
kundajib8c0d102015-07-27 21:47:411515 if (request_)
[email protected]7a299a92012-10-24 23:54:501516 request_->set_received_response_content_length(prefilter_bytes_read());
[email protected]bbaea8f2011-06-24 00:11:011517}
1518
[email protected]ea8141e2011-10-05 13:12:511519HttpResponseHeaders* URLRequestHttpJob::GetResponseHeaders() const {
1520 DCHECK(transaction_.get());
1521 DCHECK(transaction_->GetResponseInfo());
1522 return override_response_headers_.get() ?
[email protected]90499482013-06-01 00:39:501523 override_response_headers_.get() :
1524 transaction_->GetResponseInfo()->headers.get();
[email protected]ea8141e2011-10-05 13:12:511525}
1526
1527void URLRequestHttpJob::NotifyURLRequestDestroyed() {
1528 awaiting_callback_ = false;
1529}
1530
[email protected]4f5656c62010-12-13 10:47:091531} // namespace net