blob: 22e776ca5d9704a72ed0b333c5cc15896d1b30f8 [file] [log] [blame]
[email protected]56f0b082012-06-14 07:12:321// 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
3// found in the LICENSE file.
4
[email protected]678c0362012-12-05 08:02:445#include "content/browser/loader/resource_loader.h"
[email protected]56f0b082012-06-14 07:12:326
[email protected]bbdd1b20b2012-12-11 21:24:137#include "base/command_line.h"
skyostil95082a62015-06-05 19:53:078#include "base/location.h"
[email protected]5e3183482013-08-09 11:05:199#include "base/metrics/histogram.h"
vadimt81ef0df2014-11-18 19:42:3110#include "base/profiler/scoped_tracker.h"
skyostil95082a62015-06-05 19:53:0711#include "base/single_thread_task_runner.h"
12#include "base/thread_task_runner_handle.h"
[email protected]a43858f2013-06-28 15:18:3713#include "base/time/time.h"
[email protected]db3678052014-04-01 16:08:0314#include "content/browser/appcache/appcache_interceptor.h"
[email protected]56f0b082012-06-14 07:12:3215#include "content/browser/child_process_security_policy_impl.h"
[email protected]fc6c1872013-10-03 01:22:3516#include "content/browser/loader/cross_site_resource_handler.h"
[email protected]146b8b22013-11-20 03:59:1817#include "content/browser/loader/detachable_resource_handler.h"
[email protected]678c0362012-12-05 08:02:4418#include "content/browser/loader/resource_loader_delegate.h"
19#include "content/browser/loader/resource_request_info_impl.h"
[email protected]6ee72da12014-07-22 04:39:1020#include "content/browser/service_worker/service_worker_request_handler.h"
[email protected]56f0b082012-06-14 07:12:3221#include "content/browser/ssl/ssl_client_auth_handler.h"
22#include "content/browser/ssl/ssl_manager.h"
estark294fbd92015-07-31 18:36:2423#include "content/browser/ssl/ssl_policy.h"
[email protected]56f0b082012-06-14 07:12:3224#include "content/common/ssl_status_serialization.h"
25#include "content/public/browser/cert_store.h"
[email protected]1ccb6992013-10-30 04:46:2026#include "content/public/browser/resource_context.h"
[email protected]56f0b082012-06-14 07:12:3227#include "content/public/browser/resource_dispatcher_host_login_delegate.h"
[email protected]0bbd63b2013-11-29 00:02:1228#include "content/public/browser/signed_certificate_timestamp_store.h"
[email protected]bbdd1b20b2012-12-11 21:24:1329#include "content/public/common/content_client.h"
30#include "content/public/common/content_switches.h"
[email protected]f3b357692013-03-22 05:16:1331#include "content/public/common/process_type.h"
[email protected]56f0b082012-06-14 07:12:3232#include "content/public/common/resource_response.h"
estark294fbd92015-07-31 18:36:2433#include "content/public/common/security_style.h"
[email protected]fc6c1872013-10-03 01:22:3534#include "net/base/io_buffer.h"
[email protected]56f0b082012-06-14 07:12:3235#include "net/base/load_flags.h"
36#include "net/http/http_response_headers.h"
[email protected]536fd0b2013-03-14 17:41:5737#include "net/ssl/client_cert_store.h"
[email protected]cba24642014-08-15 20:49:5938#include "net/url_request/redirect_info.h"
[email protected]3ed84722013-11-01 17:17:0739#include "net/url_request/url_request_status.h"
[email protected]56f0b082012-06-14 07:12:3240
41using base::TimeDelta;
42using base::TimeTicks;
43
44namespace content {
45namespace {
46
andresantosoe9b1f932015-05-23 03:22:4947// The interval for calls to ResourceLoader::ReportUploadProgress.
48const int kUploadProgressIntervalMsec = 100;
49
estark294fbd92015-07-31 18:36:2450void StoreSignedCertificateTimestamps(
51 const net::SignedCertificateTimestampAndStatusList& sct_list,
52 int process_id,
53 SignedCertificateTimestampIDStatusList* sct_ids) {
54 SignedCertificateTimestampStore* sct_store(
55 SignedCertificateTimestampStore::GetInstance());
56
57 for (auto iter = sct_list.begin(); iter != sct_list.end(); ++iter) {
58 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
59 sct_ids->push_back(
60 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
61 }
62}
63
64void GetSSLStatusForRequest(const GURL& url,
65 const net::SSLInfo& ssl_info,
66 int child_id,
67 SSLStatus* ssl_status) {
68 DCHECK(ssl_info.cert);
69
70 int cert_id =
71 CertStore::GetInstance()->StoreCert(ssl_info.cert.get(), child_id);
72
73 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
74 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
75 child_id, &signed_certificate_timestamp_ids);
76
77 ssl_status->cert_id = cert_id;
78 ssl_status->cert_status = ssl_info.cert_status;
79 ssl_status->security_bits = ssl_info.security_bits;
80 ssl_status->connection_status = ssl_info.connection_status;
81 ssl_status->signed_certificate_timestamp_ids =
82 signed_certificate_timestamp_ids;
83 ssl_status->security_style =
84 SSLPolicy::GetSecurityStyleForResource(url, *ssl_status);
85}
86
estarka7140bc2015-08-12 17:29:3787void PopulateResourceResponse(ResourceRequestInfoImpl* info,
88 net::URLRequest* request,
89 ResourceResponse* response) {
90 response->head.request_time = request->request_time();
91 response->head.response_time = request->response_time();
92 response->head.headers = request->response_headers();
93 request->GetCharset(&response->head.charset);
94 response->head.content_length = request->GetExpectedContentSize();
95 request->GetMimeType(&response->head.mime_type);
96 net::HttpResponseInfo response_info = request->response_info();
97 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
98 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
99 response->head.npn_negotiated_protocol =
100 response_info.npn_negotiated_protocol;
101 response->head.connection_info = response_info.connection_info;
102 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
103 response->head.proxy_server = response_info.proxy_server;
104 response->head.socket_address = request->GetSocketAddress();
105 if (ServiceWorkerRequestHandler* handler =
106 ServiceWorkerRequestHandler::GetHandler(request)) {
107 handler->GetExtraResponseInfo(&response->head);
108 }
109 AppCacheInterceptor::GetExtraResponseInfo(
110 request, &response->head.appcache_id,
111 &response->head.appcache_manifest_url);
112 if (info->is_load_timing_enabled())
113 request->GetLoadTimingInfo(&response->head.load_timing);
114
115 if (request->ssl_info().cert.get()) {
116 SSLStatus ssl_status;
117 GetSSLStatusForRequest(request->url(), request->ssl_info(),
118 info->GetChildID(), &ssl_status);
119 response->head.security_info = SerializeSecurityInfo(ssl_status);
120 } else {
121 // We should not have any SSL state.
122 DCHECK(!request->ssl_info().cert_status &&
123 request->ssl_info().security_bits == -1 &&
124 !request->ssl_info().connection_status);
125 }
126}
127
[email protected]56f0b082012-06-14 07:12:32128} // namespace
129
130ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
131 scoped_ptr<ResourceHandler> handler,
132 ResourceLoaderDelegate* delegate)
[email protected]1ccb6992013-10-30 04:46:20133 : deferred_stage_(DEFERRED_NONE),
134 request_(request.Pass()),
135 handler_(handler.Pass()),
136 delegate_(delegate),
137 last_upload_position_(0),
138 waiting_for_upload_progress_ack_(false),
139 is_transferring_(false),
mmenkee0b2bd622015-06-24 20:23:10140 times_cancelled_before_request_start_(0),
141 started_request_(false),
142 times_cancelled_after_request_start_(0),
[email protected]1ccb6992013-10-30 04:46:20143 weak_ptr_factory_(this) {
144 request_->set_delegate(this);
145 handler_->SetController(this);
[email protected]56f0b082012-06-14 07:12:32146}
147
148ResourceLoader::~ResourceLoader() {
[email protected]fc72bb12013-06-02 21:13:46149 if (login_delegate_.get())
[email protected]56f0b082012-06-14 07:12:32150 login_delegate_->OnRequestCancelled();
davidben6cd57dd2014-12-12 19:23:57151 ssl_client_auth_handler_.reset();
[email protected]56f0b082012-06-14 07:12:32152
153 // Run ResourceHandler destructor before we tear-down the rest of our state
154 // as the ResourceHandler may want to inspect the URLRequest and other state.
155 handler_.reset();
156}
157
158void ResourceLoader::StartRequest() {
159 if (delegate_->HandleExternalProtocol(this, request_->url())) {
[email protected]2756a8e2012-09-07 18:24:29160 CancelAndIgnore();
[email protected]56f0b082012-06-14 07:12:32161 return;
162 }
163
164 // Give the handler a chance to delay the URLRequest from being started.
165 bool defer_start = false;
pkasting941842c2015-04-11 01:51:30166 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
167 Cancel();
168 return;
[email protected]56f0b082012-06-14 07:12:32169 }
170
171 if (defer_start) {
172 deferred_stage_ = DEFERRED_START;
173 } else {
174 StartRequestInternal();
175 }
176}
177
178void ResourceLoader::CancelRequest(bool from_renderer) {
179 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
180}
181
[email protected]2756a8e2012-09-07 18:24:29182void ResourceLoader::CancelAndIgnore() {
183 ResourceRequestInfoImpl* info = GetRequestInfo();
184 info->set_was_ignored_by_handler(true);
185 CancelRequest(false);
186}
187
[email protected]af3d4962012-10-19 10:57:26188void ResourceLoader::CancelWithError(int error_code) {
189 CancelRequestInternal(error_code, false);
190}
191
[email protected]56f0b082012-06-14 07:12:32192void ResourceLoader::ReportUploadProgress() {
andresantosoe9b1f932015-05-23 03:22:49193 DCHECK(GetRequestInfo()->is_upload_progress_enabled());
194
[email protected]56f0b082012-06-14 07:12:32195 if (waiting_for_upload_progress_ack_)
196 return; // Send one progress event at a time.
197
[email protected]7335ab02012-08-30 22:30:42198 net::UploadProgress progress = request_->GetUploadProgress();
199 if (!progress.size())
[email protected]56f0b082012-06-14 07:12:32200 return; // Nothing to upload.
201
[email protected]7335ab02012-08-30 22:30:42202 if (progress.position() == last_upload_position_)
[email protected]56f0b082012-06-14 07:12:32203 return; // No progress made since last time.
204
205 const uint64 kHalfPercentIncrements = 200;
206 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
207
[email protected]7335ab02012-08-30 22:30:42208 uint64 amt_since_last = progress.position() - last_upload_position_;
[email protected]56f0b082012-06-14 07:12:32209 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
210
[email protected]7335ab02012-08-30 22:30:42211 bool is_finished = (progress.size() == progress.position());
212 bool enough_new_progress =
213 (amt_since_last > (progress.size() / kHalfPercentIncrements));
[email protected]56f0b082012-06-14 07:12:32214 bool too_much_time_passed = time_since_last > kOneSecond;
215
216 if (is_finished || enough_new_progress || too_much_time_passed) {
andresantosoe9b1f932015-05-23 03:22:49217 handler_->OnUploadProgress(progress.position(), progress.size());
218 waiting_for_upload_progress_ack_ = true;
[email protected]56f0b082012-06-14 07:12:32219 last_upload_ticks_ = TimeTicks::Now();
[email protected]7335ab02012-08-30 22:30:42220 last_upload_position_ = progress.position();
[email protected]56f0b082012-06-14 07:12:32221 }
222}
223
[email protected]f820d9c52013-12-18 18:42:36224void ResourceLoader::MarkAsTransferring() {
[email protected]6c1e05212014-07-31 00:59:40225 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
[email protected]46c704762013-12-18 18:10:24226 << "Can only transfer for navigations";
[email protected]56f0b082012-06-14 07:12:32227 is_transferring_ = true;
michaelnbfea6ec2014-12-09 23:16:13228
229 int child_id = GetRequestInfo()->GetChildID();
230 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
231 ServiceWorkerRequestHandler* handler =
232 ServiceWorkerRequestHandler::GetHandler(request());
233 if (handler)
234 handler->PrepareForCrossSiteTransfer(child_id);
[email protected]56f0b082012-06-14 07:12:32235}
236
[email protected]1f291cd2013-09-25 22:05:14237void ResourceLoader::CompleteTransfer() {
[email protected]17b674e02014-05-10 04:30:02238 // Although CrossSiteResourceHandler defers at OnResponseStarted
239 // (DEFERRED_READ), it may be seeing a replay of events via
mmenke664a8fd2015-06-13 00:08:51240 // MimeTypeResourceHandler, and so the request itself is actually deferred
241 // at a later read stage.
[email protected]17b674e02014-05-10 04:30:02242 DCHECK(DEFERRED_READ == deferred_stage_ ||
243 DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
michaelnbfea6ec2014-12-09 23:16:13244 DCHECK(is_transferring_);
245
246 // In some cases, a process transfer doesn't really happen and the
247 // request is resumed in the original process. Real transfers to a new process
248 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
249 int child_id = GetRequestInfo()->GetChildID();
250 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
251 request(), child_id);
252 ServiceWorkerRequestHandler* handler =
253 ServiceWorkerRequestHandler::GetHandler(request());
254 if (handler)
255 handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
[email protected]56f0b082012-06-14 07:12:32256
[email protected]56f0b082012-06-14 07:12:32257 is_transferring_ = false;
[email protected]fc6c1872013-10-03 01:22:35258 GetRequestInfo()->cross_site_handler()->ResumeResponse();
[email protected]56f0b082012-06-14 07:12:32259}
260
261ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
262 return ResourceRequestInfoImpl::ForRequest(request_.get());
263}
264
265void ResourceLoader::ClearLoginDelegate() {
266 login_delegate_ = NULL;
267}
268
[email protected]56f0b082012-06-14 07:12:32269void ResourceLoader::OnUploadProgressACK() {
270 waiting_for_upload_progress_ack_ = false;
271}
272
[email protected]56f0b082012-06-14 07:12:32273void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
[email protected]cba24642014-08-15 20:49:59274 const net::RedirectInfo& redirect_info,
[email protected]56f0b082012-06-14 07:12:32275 bool* defer) {
276 DCHECK_EQ(request_.get(), unused);
277
mostynb0e79091bb2015-06-15 16:18:25278 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
[email protected]56f0b082012-06-14 07:12:32279 DCHECK(request_->status().is_success());
280
281 ResourceRequestInfoImpl* info = GetRequestInfo();
282
[email protected]2d09a702014-01-19 23:41:24283 if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
[email protected]56f0b082012-06-14 07:12:32284 !ChildProcessSecurityPolicyImpl::GetInstance()->
[email protected]cba24642014-08-15 20:49:59285 CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
mostynb0e79091bb2015-06-15 16:18:25286 DVLOG(1) << "Denied unauthorized request for "
287 << redirect_info.new_url.possibly_invalid_spec();
[email protected]56f0b082012-06-14 07:12:32288
289 // Tell the renderer that this request was disallowed.
290 Cancel();
291 return;
292 }
293
[email protected]cba24642014-08-15 20:49:59294 delegate_->DidReceiveRedirect(this, redirect_info.new_url);
[email protected]56f0b082012-06-14 07:12:32295
[email protected]cba24642014-08-15 20:49:59296 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
[email protected]56f0b082012-06-14 07:12:32297 // The request is complete so we can remove it.
[email protected]2756a8e2012-09-07 18:24:29298 CancelAndIgnore();
[email protected]56f0b082012-06-14 07:12:32299 return;
300 }
301
302 scoped_refptr<ResourceResponse> response(new ResourceResponse());
[email protected]3821f7a2014-08-13 16:40:08303 PopulateResourceResponse(info, request_.get(), response.get());
[email protected]cba24642014-08-15 20:49:59304 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
[email protected]56f0b082012-06-14 07:12:32305 Cancel();
[email protected]926360f2012-06-29 04:45:02306 } else if (*defer) {
307 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
[email protected]56f0b082012-06-14 07:12:32308 }
[email protected]56f0b082012-06-14 07:12:32309}
310
311void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
312 net::AuthChallengeInfo* auth_info) {
313 DCHECK_EQ(request_.get(), unused);
314
baranovich1b32ffb2015-01-15 14:44:52315 ResourceRequestInfoImpl* info = GetRequestInfo();
316 if (info->do_not_prompt_for_login()) {
[email protected]56f0b082012-06-14 07:12:32317 request_->CancelAuth();
318 return;
319 }
320
[email protected]56f0b082012-06-14 07:12:32321 // Create a login dialog on the UI thread to get authentication data, or pull
322 // from cache and continue on the IO thread.
323
[email protected]fc72bb12013-06-02 21:13:46324 DCHECK(!login_delegate_.get())
325 << "OnAuthRequired called with login_delegate pending";
[email protected]56f0b082012-06-14 07:12:32326 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
[email protected]fc72bb12013-06-02 21:13:46327 if (!login_delegate_.get())
[email protected]56f0b082012-06-14 07:12:32328 request_->CancelAuth();
329}
330
331void ResourceLoader::OnCertificateRequested(
332 net::URLRequest* unused,
333 net::SSLCertRequestInfo* cert_info) {
334 DCHECK_EQ(request_.get(), unused);
335
[email protected]294084d2014-01-06 22:22:02336 if (request_->load_flags() & net::LOAD_PREFETCH) {
[email protected]56f0b082012-06-14 07:12:32337 request_->Cancel();
338 return;
339 }
340
davidben6cd57dd2014-12-12 19:23:57341 DCHECK(!ssl_client_auth_handler_)
[email protected]fc72bb12013-06-02 21:13:46342 << "OnCertificateRequested called with ssl_client_auth_handler pending";
davidben6cd57dd2014-12-12 19:23:57343 ssl_client_auth_handler_.reset(new SSLClientAuthHandler(
344 GetRequestInfo()->GetContext()->CreateClientCertStore(), request_.get(),
davidben3b8455ae72015-03-11 19:42:19345 cert_info, this));
[email protected]56f0b082012-06-14 07:12:32346 ssl_client_auth_handler_->SelectCertificate();
347}
348
349void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
350 const net::SSLInfo& ssl_info,
351 bool fatal) {
352 ResourceRequestInfoImpl* info = GetRequestInfo();
353
354 int render_process_id;
[email protected]1a4e9752013-12-31 20:10:58355 int render_frame_id;
356 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
[email protected]56f0b082012-06-14 07:12:32357 NOTREACHED();
358
359 SSLManager::OnSSLCertificateError(
[email protected]5c1d3e52012-08-01 05:14:27360 weak_ptr_factory_.GetWeakPtr(),
[email protected]56f0b082012-06-14 07:12:32361 info->GetResourceType(),
362 request_->url(),
363 render_process_id,
[email protected]1a4e9752013-12-31 20:10:58364 render_frame_id,
[email protected]56f0b082012-06-14 07:12:32365 ssl_info,
366 fatal);
367}
368
[email protected]5584eab2014-01-09 22:16:15369void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
370 bool* defer) {
371 DCHECK_EQ(request_.get(), unused);
372
373 // Give the handler a chance to delay the URLRequest from using the network.
[email protected]d22e800e2014-05-28 21:55:57374 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
[email protected]5584eab2014-01-09 22:16:15375 Cancel();
376 return;
377 } else if (*defer) {
378 deferred_stage_ = DEFERRED_NETWORK_START;
379 }
380}
381
[email protected]56f0b082012-06-14 07:12:32382void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
383 DCHECK_EQ(request_.get(), unused);
384
mostynb0e79091bb2015-06-15 16:18:25385 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
[email protected]56f0b082012-06-14 07:12:32386
andresantosoe9b1f932015-05-23 03:22:49387 progress_timer_.Stop();
388
[email protected]926360f2012-06-29 04:45:02389 if (!request_->status().is_success()) {
390 ResponseCompleted();
391 return;
392 }
393
394 // We want to send a final upload progress message prior to sending the
395 // response complete message even if we're waiting for an ack to to a
396 // previous upload progress message.
nick9cfbf5bd2015-07-20 23:59:13397 ResourceRequestInfoImpl* info = GetRequestInfo();
andresantosoe9b1f932015-05-23 03:22:49398 if (info->is_upload_progress_enabled()) {
399 waiting_for_upload_progress_ack_ = false;
400 ReportUploadProgress();
401 }
[email protected]926360f2012-06-29 04:45:02402
403 CompleteResponseStarted();
404
405 if (is_deferred())
406 return;
407
pkasting941842c2015-04-11 01:51:30408 if (request_->status().is_success())
[email protected]926360f2012-06-29 04:45:02409 StartReading(false); // Read the first chunk.
pkasting941842c2015-04-11 01:51:30410 else
[email protected]56f0b082012-06-14 07:12:32411 ResponseCompleted();
[email protected]56f0b082012-06-14 07:12:32412}
413
414void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
415 DCHECK_EQ(request_.get(), unused);
mostynb0e79091bb2015-06-15 16:18:25416 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
417 << " bytes_read = " << bytes_read;
[email protected]56f0b082012-06-14 07:12:32418
[email protected]926360f2012-06-29 04:45:02419 // bytes_read == -1 always implies an error.
420 if (bytes_read == -1 || !request_->status().is_success()) {
[email protected]56f0b082012-06-14 07:12:32421 ResponseCompleted();
422 return;
423 }
424
[email protected]218d9d372014-04-16 18:34:55425 CompleteRead(bytes_read);
426
[email protected]d1222a62014-04-14 20:27:32427 // If the handler cancelled or deferred the request, do not continue
428 // processing the read. If cancelled, the URLRequest has already been
429 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
430 // do nothing until resumed.
431 //
432 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
[email protected]17b674e02014-05-10 04:30:02433 // ResponseCompleted().
[email protected]218d9d372014-04-16 18:34:55434 if (is_deferred() || !request_->status().is_success())
[email protected]56f0b082012-06-14 07:12:32435 return;
[email protected]56f0b082012-06-14 07:12:32436
[email protected]d1222a62014-04-14 20:27:32437 if (bytes_read > 0) {
[email protected]926360f2012-06-29 04:45:02438 StartReading(true); // Read the next chunk.
439 } else {
pkasting941842c2015-04-11 01:51:30440 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
441 tracked_objects::ScopedTracker tracking_profile(
442 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
vadimt2df40b372014-11-27 02:01:41443
[email protected]d1222a62014-04-14 20:27:32444 // URLRequest reported an EOF. Call ResponseCompleted.
445 DCHECK_EQ(0, bytes_read);
[email protected]56f0b082012-06-14 07:12:32446 ResponseCompleted();
[email protected]926360f2012-06-29 04:45:02447 }
[email protected]56f0b082012-06-14 07:12:32448}
449
davidben21163ec2014-10-01 23:05:23450void ResourceLoader::CancelSSLRequest(int error,
[email protected]56f0b082012-06-14 07:12:32451 const net::SSLInfo* ssl_info) {
mostynb4c27d042015-03-18 21:47:47452 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]56f0b082012-06-14 07:12:32453
454 // The request can be NULL if it was cancelled by the renderer (as the
455 // request of the user navigating to a new page from the location bar).
456 if (!request_->is_pending())
457 return;
458 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
459
460 if (ssl_info) {
461 request_->CancelWithSSLError(error, *ssl_info);
462 } else {
463 request_->CancelWithError(error);
464 }
465}
466
davidben21163ec2014-10-01 23:05:23467void ResourceLoader::ContinueSSLRequest() {
mostynb4c27d042015-03-18 21:47:47468 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]56f0b082012-06-14 07:12:32469
470 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
471
472 request_->ContinueDespiteLastError();
473}
474
davidben3b8455ae72015-03-11 19:42:19475void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
476 DCHECK(ssl_client_auth_handler_);
477 ssl_client_auth_handler_.reset();
478 request_->ContinueWithCertificate(cert);
479}
480
481void ResourceLoader::CancelCertificateSelection() {
482 DCHECK(ssl_client_auth_handler_);
483 ssl_client_auth_handler_.reset();
484 request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
485}
486
[email protected]56f0b082012-06-14 07:12:32487void ResourceLoader::Resume() {
488 DCHECK(!is_transferring_);
489
490 DeferredStage stage = deferred_stage_;
491 deferred_stage_ = DEFERRED_NONE;
492 switch (stage) {
493 case DEFERRED_NONE:
494 NOTREACHED();
495 break;
496 case DEFERRED_START:
497 StartRequestInternal();
498 break;
[email protected]5584eab2014-01-09 22:16:15499 case DEFERRED_NETWORK_START:
500 request_->ResumeNetworkStart();
501 break;
[email protected]56f0b082012-06-14 07:12:32502 case DEFERRED_REDIRECT:
503 request_->FollowDeferredRedirect();
504 break;
[email protected]56f0b082012-06-14 07:12:32505 case DEFERRED_READ:
skyostil95082a62015-06-05 19:53:07506 base::ThreadTaskRunnerHandle::Get()->PostTask(
507 FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
508 weak_ptr_factory_.GetWeakPtr()));
[email protected]56f0b082012-06-14 07:12:32509 break;
[email protected]17b674e02014-05-10 04:30:02510 case DEFERRED_RESPONSE_COMPLETE:
skyostil95082a62015-06-05 19:53:07511 base::ThreadTaskRunnerHandle::Get()->PostTask(
512 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
513 weak_ptr_factory_.GetWeakPtr()));
[email protected]17b674e02014-05-10 04:30:02514 break;
[email protected]56f0b082012-06-14 07:12:32515 case DEFERRED_FINISH:
516 // Delay self-destruction since we don't know how we were reached.
skyostil95082a62015-06-05 19:53:07517 base::ThreadTaskRunnerHandle::Get()->PostTask(
518 FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
519 weak_ptr_factory_.GetWeakPtr()));
[email protected]56f0b082012-06-14 07:12:32520 break;
521 }
522}
523
524void ResourceLoader::Cancel() {
525 CancelRequest(false);
526}
527
528void ResourceLoader::StartRequestInternal() {
529 DCHECK(!request_->is_pending());
[email protected]4c4092112014-02-26 23:29:12530
531 if (!request_->status().is_success()) {
532 return;
533 }
534
mmenkee0b2bd622015-06-24 20:23:10535 started_request_ = true;
[email protected]56f0b082012-06-14 07:12:32536 request_->Start();
537
538 delegate_->DidStartRequest(this);
andresantosoe9b1f932015-05-23 03:22:49539
540 if (GetRequestInfo()->is_upload_progress_enabled() &&
541 request_->has_upload()) {
542 progress_timer_.Start(
543 FROM_HERE,
544 base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec),
545 this,
546 &ResourceLoader::ReportUploadProgress);
547 }
[email protected]56f0b082012-06-14 07:12:32548}
549
550void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
mostynb0e79091bb2015-06-15 16:18:25551 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
[email protected]56f0b082012-06-14 07:12:32552
553 ResourceRequestInfoImpl* info = GetRequestInfo();
554
555 // WebKit will send us a cancel for downloads since it no longer handles
556 // them. In this case, ignore the cancel since we handle downloads in the
557 // browser.
[email protected]70983822013-11-27 14:33:59558 if (from_renderer && (info->IsDownload() || info->is_stream()))
[email protected]56f0b082012-06-14 07:12:32559 return;
560
[email protected]146b8b22013-11-20 03:59:18561 if (from_renderer && info->detachable_handler()) {
562 // TODO(davidben): Fix Blink handling of prefetches so they are not
563 // cancelled on navigate away and end up in the local cache.
564 info->detachable_handler()->Detach();
565 return;
566 }
567
[email protected]926360f2012-06-29 04:45:02568 // TODO(darin): Perhaps we should really be looking to see if the status is
569 // IO_PENDING?
[email protected]56f0b082012-06-14 07:12:32570 bool was_pending = request_->is_pending();
571
[email protected]fc72bb12013-06-02 21:13:46572 if (login_delegate_.get()) {
[email protected]56f0b082012-06-14 07:12:32573 login_delegate_->OnRequestCancelled();
574 login_delegate_ = NULL;
575 }
davidben6cd57dd2014-12-12 19:23:57576 ssl_client_auth_handler_.reset();
[email protected]56f0b082012-06-14 07:12:32577
mmenkee0b2bd622015-06-24 20:23:10578 if (!started_request_) {
579 times_cancelled_before_request_start_++;
580 } else {
581 times_cancelled_after_request_start_++;
582 }
583
[email protected]56f0b082012-06-14 07:12:32584 request_->CancelWithError(error);
585
586 if (!was_pending) {
587 // If the request isn't in flight, then we won't get an asynchronous
588 // notification from the request, so we have to signal ourselves to finish
589 // this request.
skyostil95082a62015-06-05 19:53:07590 base::ThreadTaskRunnerHandle::Get()->PostTask(
591 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
592 weak_ptr_factory_.GetWeakPtr()));
[email protected]56f0b082012-06-14 07:12:32593 }
594}
595
[email protected]926360f2012-06-29 04:45:02596void ResourceLoader::CompleteResponseStarted() {
[email protected]56f0b082012-06-14 07:12:32597 ResourceRequestInfoImpl* info = GetRequestInfo();
[email protected]56f0b082012-06-14 07:12:32598 scoped_refptr<ResourceResponse> response(new ResourceResponse());
[email protected]3821f7a2014-08-13 16:40:08599 PopulateResourceResponse(info, request_.get(), response.get());
[email protected]56f0b082012-06-14 07:12:32600
[email protected]56f0b082012-06-14 07:12:32601 delegate_->DidReceiveResponse(this);
[email protected]56f0b082012-06-14 07:12:32602
pkasting941842c2015-04-11 01:51:30603 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
vadimt81ef0df2014-11-18 19:42:31604 tracked_objects::ScopedTracker tracking_profile(
pkasting941842c2015-04-11 01:51:30605 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
vadimt81ef0df2014-11-18 19:42:31606
[email protected]56f0b082012-06-14 07:12:32607 bool defer = false;
[email protected]d22e800e2014-05-28 21:55:57608 if (!handler_->OnResponseStarted(response.get(), &defer)) {
[email protected]926360f2012-06-29 04:45:02609 Cancel();
610 } else if (defer) {
[email protected]5e3183482013-08-09 11:05:19611 read_deferral_start_time_ = base::TimeTicks::Now();
[email protected]926360f2012-06-29 04:45:02612 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
[email protected]56f0b082012-06-14 07:12:32613 }
[email protected]56f0b082012-06-14 07:12:32614}
615
[email protected]926360f2012-06-29 04:45:02616void ResourceLoader::StartReading(bool is_continuation) {
[email protected]56f0b082012-06-14 07:12:32617 int bytes_read = 0;
[email protected]926360f2012-06-29 04:45:02618 ReadMore(&bytes_read);
619
620 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
621 if (request_->status().is_io_pending())
622 return;
623
624 if (!is_continuation || bytes_read <= 0) {
[email protected]56f0b082012-06-14 07:12:32625 OnReadCompleted(request_.get(), bytes_read);
[email protected]926360f2012-06-29 04:45:02626 } else {
627 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
628 // thread in case the URLRequest can provide data synchronously.
skyostil95082a62015-06-05 19:53:07629 base::ThreadTaskRunnerHandle::Get()->PostTask(
[email protected]926360f2012-06-29 04:45:02630 FROM_HERE,
[email protected]5c1d3e52012-08-01 05:14:27631 base::Bind(&ResourceLoader::OnReadCompleted,
skyostil95082a62015-06-05 19:53:07632 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
[email protected]926360f2012-06-29 04:45:02633 }
634}
635
636void ResourceLoader::ResumeReading() {
637 DCHECK(!is_deferred());
638
[email protected]5e3183482013-08-09 11:05:19639 if (!read_deferral_start_time_.is_null()) {
640 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
641 base::TimeTicks::Now() - read_deferral_start_time_);
642 read_deferral_start_time_ = base::TimeTicks();
643 }
[email protected]926360f2012-06-29 04:45:02644 if (request_->status().is_success()) {
645 StartReading(false); // Read the next chunk (OK to complete synchronously).
646 } else {
[email protected]56f0b082012-06-14 07:12:32647 ResponseCompleted();
648 }
649}
650
[email protected]926360f2012-06-29 04:45:02651void ResourceLoader::ReadMore(int* bytes_read) {
[email protected]926360f2012-06-29 04:45:02652 DCHECK(!is_deferred());
[email protected]56f0b082012-06-14 07:12:32653
[email protected]ef5306e2013-10-15 19:38:18654 // Make sure we track the buffer in at least one place. This ensures it gets
655 // deleted even in the case the request has already finished its job and
656 // doesn't use the buffer.
657 scoped_refptr<net::IOBuffer> buf;
[email protected]56f0b082012-06-14 07:12:32658 int buf_size;
vadimt81ef0df2014-11-18 19:42:31659 {
pkasting941842c2015-04-11 01:51:30660 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
vadimt394300b02014-12-02 04:38:41661 tracked_objects::ScopedTracker tracking_profile2(
pkasting941842c2015-04-11 01:51:30662 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()"));
vadimt81ef0df2014-11-18 19:42:31663
664 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
665 Cancel();
666 return;
667 }
[email protected]926360f2012-06-29 04:45:02668 }
[email protected]56f0b082012-06-14 07:12:32669
dcheng67769df52014-08-26 19:43:51670 DCHECK(buf.get());
[email protected]56f0b082012-06-14 07:12:32671 DCHECK(buf_size > 0);
672
[email protected]ef5306e2013-10-15 19:38:18673 request_->Read(buf.get(), buf_size, bytes_read);
[email protected]926360f2012-06-29 04:45:02674
675 // No need to check the return value here as we'll detect errors by
676 // inspecting the URLRequest's status.
[email protected]56f0b082012-06-14 07:12:32677}
678
[email protected]218d9d372014-04-16 18:34:55679void ResourceLoader::CompleteRead(int bytes_read) {
[email protected]926360f2012-06-29 04:45:02680 DCHECK(bytes_read >= 0);
681 DCHECK(request_->status().is_success());
[email protected]56f0b082012-06-14 07:12:32682
pkasting941842c2015-04-11 01:51:30683 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
vadimt81ef0df2014-11-18 19:42:31684 tracked_objects::ScopedTracker tracking_profile(
pkasting941842c2015-04-11 01:51:30685 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
vadimt81ef0df2014-11-18 19:42:31686
[email protected]56f0b082012-06-14 07:12:32687 bool defer = false;
[email protected]d22e800e2014-05-28 21:55:57688 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
[email protected]56f0b082012-06-14 07:12:32689 Cancel();
[email protected]926360f2012-06-29 04:45:02690 } else if (defer) {
[email protected]17b674e02014-05-10 04:30:02691 deferred_stage_ =
692 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
[email protected]56f0b082012-06-14 07:12:32693 }
[email protected]218d9d372014-04-16 18:34:55694
695 // Note: the request may still have been cancelled while OnReadCompleted
696 // returns true if OnReadCompleted caused request to get cancelled
697 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
698 // instance.)
[email protected]56f0b082012-06-14 07:12:32699}
700
701void ResourceLoader::ResponseCompleted() {
mostynb0e79091bb2015-06-15 16:18:25702 DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
[email protected]3ed84722013-11-01 17:17:07703 RecordHistograms();
[email protected]56f0b082012-06-14 07:12:32704 ResourceRequestInfoImpl* info = GetRequestInfo();
705
706 std::string security_info;
707 const net::SSLInfo& ssl_info = request_->ssl_info();
[email protected]fc72bb12013-06-02 21:13:46708 if (ssl_info.cert.get() != NULL) {
estark294fbd92015-07-31 18:36:24709 SSLStatus ssl_status;
710 GetSSLStatusForRequest(request_->url(), ssl_info, info->GetChildID(),
711 &ssl_status);
[email protected]0bbd63b2013-11-29 00:02:12712
estark294fbd92015-07-31 18:36:24713 security_info = SerializeSecurityInfo(ssl_status);
[email protected]56f0b082012-06-14 07:12:32714 }
715
[email protected]3780874a2013-11-18 05:49:03716 bool defer = false;
vadimt81ef0df2014-11-18 19:42:31717 {
pkasting941842c2015-04-11 01:51:30718 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
vadimt81ef0df2014-11-18 19:42:31719 tracked_objects::ScopedTracker tracking_profile(
pkasting941842c2015-04-11 01:51:30720 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
vadimt81ef0df2014-11-18 19:42:31721
722 handler_->OnResponseCompleted(request_->status(), security_info, &defer);
723 }
[email protected]3780874a2013-11-18 05:49:03724 if (defer) {
[email protected]56f0b082012-06-14 07:12:32725 // The handler is not ready to die yet. We will call DidFinishLoading when
726 // we resume.
727 deferred_stage_ = DEFERRED_FINISH;
[email protected]3780874a2013-11-18 05:49:03728 } else {
729 // This will result in our destruction.
730 CallDidFinishLoading();
[email protected]56f0b082012-06-14 07:12:32731 }
732}
733
[email protected]56f0b082012-06-14 07:12:32734void ResourceLoader::CallDidFinishLoading() {
735 delegate_->DidFinishLoading(this);
736}
737
[email protected]3ed84722013-11-01 17:17:07738void ResourceLoader::RecordHistograms() {
739 ResourceRequestInfoImpl* info = GetRequestInfo();
740
[email protected]6c1e05212014-07-31 00:59:40741 if (info->GetResourceType() == RESOURCE_TYPE_PREFETCH) {
[email protected]3ed84722013-11-01 17:17:07742 PrefetchStatus status = STATUS_UNDEFINED;
743 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
744
745 switch (request_->status().status()) {
746 case net::URLRequestStatus::SUCCESS:
747 if (request_->was_cached()) {
748 status = STATUS_SUCCESS_FROM_CACHE;
749 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
750 total_time);
751 } else {
752 status = STATUS_SUCCESS_FROM_NETWORK;
753 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
754 total_time);
755 }
756 break;
757 case net::URLRequestStatus::CANCELED:
758 status = STATUS_CANCELED;
759 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
760 break;
761 case net::URLRequestStatus::IO_PENDING:
762 case net::URLRequestStatus::FAILED:
763 status = STATUS_UNDEFINED;
764 break;
765 }
766
767 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
768 }
769}
770
[email protected]56f0b082012-06-14 07:12:32771} // namespace content