Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blob5c2b9b814c97f6b87ed5fcf805484c880f1fb92c
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/loader/resource_loader.h"
7 #include "base/command_line.h"
8 #include "base/location.h"
9 #include "base/metrics/histogram.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "content/browser/appcache/appcache_interceptor.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/loader/cross_site_resource_handler.h"
17 #include "content/browser/loader/detachable_resource_handler.h"
18 #include "content/browser/loader/resource_loader_delegate.h"
19 #include "content/browser/loader/resource_request_info_impl.h"
20 #include "content/browser/service_worker/service_worker_request_handler.h"
21 #include "content/browser/ssl/ssl_client_auth_handler.h"
22 #include "content/browser/ssl/ssl_manager.h"
23 #include "content/common/ssl_status_serialization.h"
24 #include "content/public/browser/cert_store.h"
25 #include "content/public/browser/resource_context.h"
26 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
27 #include "content/public/browser/signed_certificate_timestamp_store.h"
28 #include "content/public/common/content_client.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/process_type.h"
31 #include "content/public/common/resource_response.h"
32 #include "net/base/io_buffer.h"
33 #include "net/base/load_flags.h"
34 #include "net/http/http_response_headers.h"
35 #include "net/ssl/client_cert_store.h"
36 #include "net/url_request/redirect_info.h"
37 #include "net/url_request/url_request_status.h"
39 using base::TimeDelta;
40 using base::TimeTicks;
42 namespace content {
43 namespace {
45 // The interval for calls to ResourceLoader::ReportUploadProgress.
46 const int kUploadProgressIntervalMsec = 100;
48 void PopulateResourceResponse(ResourceRequestInfoImpl* info,
49 net::URLRequest* request,
50 ResourceResponse* response) {
51 response->head.request_time = request->request_time();
52 response->head.response_time = request->response_time();
53 response->head.headers = request->response_headers();
54 request->GetCharset(&response->head.charset);
55 response->head.content_length = request->GetExpectedContentSize();
56 request->GetMimeType(&response->head.mime_type);
57 net::HttpResponseInfo response_info = request->response_info();
58 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
59 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
60 response->head.npn_negotiated_protocol =
61 response_info.npn_negotiated_protocol;
62 response->head.connection_info = response_info.connection_info;
63 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
64 response->head.proxy_server = response_info.proxy_server;
65 response->head.socket_address = request->GetSocketAddress();
66 if (ServiceWorkerRequestHandler* handler =
67 ServiceWorkerRequestHandler::GetHandler(request)) {
68 handler->GetExtraResponseInfo(&response->head);
70 AppCacheInterceptor::GetExtraResponseInfo(
71 request,
72 &response->head.appcache_id,
73 &response->head.appcache_manifest_url);
74 if (info->is_load_timing_enabled())
75 request->GetLoadTimingInfo(&response->head.load_timing);
78 } // namespace
80 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
81 scoped_ptr<ResourceHandler> handler,
82 ResourceLoaderDelegate* delegate)
83 : deferred_stage_(DEFERRED_NONE),
84 request_(request.Pass()),
85 handler_(handler.Pass()),
86 delegate_(delegate),
87 last_upload_position_(0),
88 waiting_for_upload_progress_ack_(false),
89 is_transferring_(false),
90 times_cancelled_before_request_start_(0),
91 started_request_(false),
92 times_cancelled_after_request_start_(0),
93 weak_ptr_factory_(this) {
94 request_->set_delegate(this);
95 handler_->SetController(this);
98 ResourceLoader::~ResourceLoader() {
99 if (login_delegate_.get())
100 login_delegate_->OnRequestCancelled();
101 ssl_client_auth_handler_.reset();
103 // Run ResourceHandler destructor before we tear-down the rest of our state
104 // as the ResourceHandler may want to inspect the URLRequest and other state.
105 handler_.reset();
108 void ResourceLoader::StartRequest() {
109 if (delegate_->HandleExternalProtocol(this, request_->url())) {
110 CancelAndIgnore();
111 return;
114 // Give the handler a chance to delay the URLRequest from being started.
115 bool defer_start = false;
116 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
117 Cancel();
118 return;
121 if (defer_start) {
122 deferred_stage_ = DEFERRED_START;
123 } else {
124 StartRequestInternal();
128 void ResourceLoader::CancelRequest(bool from_renderer) {
129 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
132 void ResourceLoader::CancelAndIgnore() {
133 ResourceRequestInfoImpl* info = GetRequestInfo();
134 info->set_was_ignored_by_handler(true);
135 CancelRequest(false);
138 void ResourceLoader::CancelWithError(int error_code) {
139 CancelRequestInternal(error_code, false);
142 void ResourceLoader::ReportUploadProgress() {
143 DCHECK(GetRequestInfo()->is_upload_progress_enabled());
145 if (waiting_for_upload_progress_ack_)
146 return; // Send one progress event at a time.
148 net::UploadProgress progress = request_->GetUploadProgress();
149 if (!progress.size())
150 return; // Nothing to upload.
152 if (progress.position() == last_upload_position_)
153 return; // No progress made since last time.
155 const uint64 kHalfPercentIncrements = 200;
156 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
158 uint64 amt_since_last = progress.position() - last_upload_position_;
159 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
161 bool is_finished = (progress.size() == progress.position());
162 bool enough_new_progress =
163 (amt_since_last > (progress.size() / kHalfPercentIncrements));
164 bool too_much_time_passed = time_since_last > kOneSecond;
166 if (is_finished || enough_new_progress || too_much_time_passed) {
167 handler_->OnUploadProgress(progress.position(), progress.size());
168 waiting_for_upload_progress_ack_ = true;
169 last_upload_ticks_ = TimeTicks::Now();
170 last_upload_position_ = progress.position();
174 void ResourceLoader::MarkAsTransferring() {
175 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
176 << "Can only transfer for navigations";
177 is_transferring_ = true;
179 int child_id = GetRequestInfo()->GetChildID();
180 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
181 ServiceWorkerRequestHandler* handler =
182 ServiceWorkerRequestHandler::GetHandler(request());
183 if (handler)
184 handler->PrepareForCrossSiteTransfer(child_id);
187 void ResourceLoader::CompleteTransfer() {
188 // Although CrossSiteResourceHandler defers at OnResponseStarted
189 // (DEFERRED_READ), it may be seeing a replay of events via
190 // MimeTypeResourceHandler, and so the request itself is actually deferred
191 // at a later read stage.
192 DCHECK(DEFERRED_READ == deferred_stage_ ||
193 DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
194 DCHECK(is_transferring_);
196 // In some cases, a process transfer doesn't really happen and the
197 // request is resumed in the original process. Real transfers to a new process
198 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
199 int child_id = GetRequestInfo()->GetChildID();
200 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
201 request(), child_id);
202 ServiceWorkerRequestHandler* handler =
203 ServiceWorkerRequestHandler::GetHandler(request());
204 if (handler)
205 handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
207 is_transferring_ = false;
208 GetRequestInfo()->cross_site_handler()->ResumeResponse();
211 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
212 return ResourceRequestInfoImpl::ForRequest(request_.get());
215 void ResourceLoader::ClearLoginDelegate() {
216 login_delegate_ = NULL;
219 void ResourceLoader::OnUploadProgressACK() {
220 waiting_for_upload_progress_ack_ = false;
223 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
224 const net::RedirectInfo& redirect_info,
225 bool* defer) {
226 DCHECK_EQ(request_.get(), unused);
228 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
229 DCHECK(request_->status().is_success());
231 ResourceRequestInfoImpl* info = GetRequestInfo();
233 if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
234 !ChildProcessSecurityPolicyImpl::GetInstance()->
235 CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
236 DVLOG(1) << "Denied unauthorized request for "
237 << redirect_info.new_url.possibly_invalid_spec();
239 // Tell the renderer that this request was disallowed.
240 Cancel();
241 return;
244 delegate_->DidReceiveRedirect(this, redirect_info.new_url);
246 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
247 // The request is complete so we can remove it.
248 CancelAndIgnore();
249 return;
252 scoped_refptr<ResourceResponse> response(new ResourceResponse());
253 PopulateResourceResponse(info, request_.get(), response.get());
254 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
255 Cancel();
256 } else if (*defer) {
257 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
261 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
262 net::AuthChallengeInfo* auth_info) {
263 DCHECK_EQ(request_.get(), unused);
265 ResourceRequestInfoImpl* info = GetRequestInfo();
266 if (info->do_not_prompt_for_login()) {
267 request_->CancelAuth();
268 return;
271 // Create a login dialog on the UI thread to get authentication data, or pull
272 // from cache and continue on the IO thread.
274 DCHECK(!login_delegate_.get())
275 << "OnAuthRequired called with login_delegate pending";
276 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
277 if (!login_delegate_.get())
278 request_->CancelAuth();
281 void ResourceLoader::OnCertificateRequested(
282 net::URLRequest* unused,
283 net::SSLCertRequestInfo* cert_info) {
284 DCHECK_EQ(request_.get(), unused);
286 if (request_->load_flags() & net::LOAD_PREFETCH) {
287 request_->Cancel();
288 return;
291 DCHECK(!ssl_client_auth_handler_)
292 << "OnCertificateRequested called with ssl_client_auth_handler pending";
293 ssl_client_auth_handler_.reset(new SSLClientAuthHandler(
294 GetRequestInfo()->GetContext()->CreateClientCertStore(), request_.get(),
295 cert_info, this));
296 ssl_client_auth_handler_->SelectCertificate();
299 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
300 const net::SSLInfo& ssl_info,
301 bool fatal) {
302 ResourceRequestInfoImpl* info = GetRequestInfo();
304 int render_process_id;
305 int render_frame_id;
306 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
307 NOTREACHED();
309 SSLManager::OnSSLCertificateError(
310 weak_ptr_factory_.GetWeakPtr(),
311 info->GetResourceType(),
312 request_->url(),
313 render_process_id,
314 render_frame_id,
315 ssl_info,
316 fatal);
319 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
320 bool* defer) {
321 DCHECK_EQ(request_.get(), unused);
323 // Give the handler a chance to delay the URLRequest from using the network.
324 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
325 Cancel();
326 return;
327 } else if (*defer) {
328 deferred_stage_ = DEFERRED_NETWORK_START;
332 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
333 DCHECK_EQ(request_.get(), unused);
335 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
337 progress_timer_.Stop();
339 if (!request_->status().is_success()) {
340 ResponseCompleted();
341 return;
344 // We want to send a final upload progress message prior to sending the
345 // response complete message even if we're waiting for an ack to to a
346 // previous upload progress message.
347 ResourceRequestInfoImpl* info = GetRequestInfo();
348 if (info->is_upload_progress_enabled()) {
349 waiting_for_upload_progress_ack_ = false;
350 ReportUploadProgress();
353 CompleteResponseStarted();
355 if (is_deferred())
356 return;
358 if (request_->status().is_success())
359 StartReading(false); // Read the first chunk.
360 else
361 ResponseCompleted();
364 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
365 DCHECK_EQ(request_.get(), unused);
366 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
367 << " bytes_read = " << bytes_read;
369 // bytes_read == -1 always implies an error.
370 if (bytes_read == -1 || !request_->status().is_success()) {
371 ResponseCompleted();
372 return;
375 CompleteRead(bytes_read);
377 // If the handler cancelled or deferred the request, do not continue
378 // processing the read. If cancelled, the URLRequest has already been
379 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
380 // do nothing until resumed.
382 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
383 // ResponseCompleted().
384 if (is_deferred() || !request_->status().is_success())
385 return;
387 if (bytes_read > 0) {
388 StartReading(true); // Read the next chunk.
389 } else {
390 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
391 tracked_objects::ScopedTracker tracking_profile(
392 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
394 // URLRequest reported an EOF. Call ResponseCompleted.
395 DCHECK_EQ(0, bytes_read);
396 ResponseCompleted();
400 void ResourceLoader::CancelSSLRequest(int error,
401 const net::SSLInfo* ssl_info) {
402 DCHECK_CURRENTLY_ON(BrowserThread::IO);
404 // The request can be NULL if it was cancelled by the renderer (as the
405 // request of the user navigating to a new page from the location bar).
406 if (!request_->is_pending())
407 return;
408 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
410 if (ssl_info) {
411 request_->CancelWithSSLError(error, *ssl_info);
412 } else {
413 request_->CancelWithError(error);
417 void ResourceLoader::ContinueSSLRequest() {
418 DCHECK_CURRENTLY_ON(BrowserThread::IO);
420 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
422 request_->ContinueDespiteLastError();
425 void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
426 DCHECK(ssl_client_auth_handler_);
427 ssl_client_auth_handler_.reset();
428 request_->ContinueWithCertificate(cert);
431 void ResourceLoader::CancelCertificateSelection() {
432 DCHECK(ssl_client_auth_handler_);
433 ssl_client_auth_handler_.reset();
434 request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
437 void ResourceLoader::Resume() {
438 DCHECK(!is_transferring_);
440 DeferredStage stage = deferred_stage_;
441 deferred_stage_ = DEFERRED_NONE;
442 switch (stage) {
443 case DEFERRED_NONE:
444 NOTREACHED();
445 break;
446 case DEFERRED_START:
447 StartRequestInternal();
448 break;
449 case DEFERRED_NETWORK_START:
450 request_->ResumeNetworkStart();
451 break;
452 case DEFERRED_REDIRECT:
453 request_->FollowDeferredRedirect();
454 break;
455 case DEFERRED_READ:
456 base::ThreadTaskRunnerHandle::Get()->PostTask(
457 FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
458 weak_ptr_factory_.GetWeakPtr()));
459 break;
460 case DEFERRED_RESPONSE_COMPLETE:
461 base::ThreadTaskRunnerHandle::Get()->PostTask(
462 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
463 weak_ptr_factory_.GetWeakPtr()));
464 break;
465 case DEFERRED_FINISH:
466 // Delay self-destruction since we don't know how we were reached.
467 base::ThreadTaskRunnerHandle::Get()->PostTask(
468 FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
469 weak_ptr_factory_.GetWeakPtr()));
470 break;
474 void ResourceLoader::Cancel() {
475 CancelRequest(false);
478 void ResourceLoader::StartRequestInternal() {
479 DCHECK(!request_->is_pending());
481 if (!request_->status().is_success()) {
482 return;
485 started_request_ = true;
486 request_->Start();
488 delegate_->DidStartRequest(this);
490 if (GetRequestInfo()->is_upload_progress_enabled() &&
491 request_->has_upload()) {
492 progress_timer_.Start(
493 FROM_HERE,
494 base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec),
495 this,
496 &ResourceLoader::ReportUploadProgress);
500 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
501 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
503 ResourceRequestInfoImpl* info = GetRequestInfo();
505 // WebKit will send us a cancel for downloads since it no longer handles
506 // them. In this case, ignore the cancel since we handle downloads in the
507 // browser.
508 if (from_renderer && (info->IsDownload() || info->is_stream()))
509 return;
511 if (from_renderer && info->detachable_handler()) {
512 // TODO(davidben): Fix Blink handling of prefetches so they are not
513 // cancelled on navigate away and end up in the local cache.
514 info->detachable_handler()->Detach();
515 return;
518 // TODO(darin): Perhaps we should really be looking to see if the status is
519 // IO_PENDING?
520 bool was_pending = request_->is_pending();
522 if (login_delegate_.get()) {
523 login_delegate_->OnRequestCancelled();
524 login_delegate_ = NULL;
526 ssl_client_auth_handler_.reset();
528 if (!started_request_) {
529 times_cancelled_before_request_start_++;
530 } else {
531 times_cancelled_after_request_start_++;
534 request_->CancelWithError(error);
536 if (!was_pending) {
537 // If the request isn't in flight, then we won't get an asynchronous
538 // notification from the request, so we have to signal ourselves to finish
539 // this request.
540 base::ThreadTaskRunnerHandle::Get()->PostTask(
541 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
542 weak_ptr_factory_.GetWeakPtr()));
546 void ResourceLoader::StoreSignedCertificateTimestamps(
547 const net::SignedCertificateTimestampAndStatusList& sct_list,
548 int process_id,
549 SignedCertificateTimestampIDStatusList* sct_ids) {
550 SignedCertificateTimestampStore* sct_store(
551 SignedCertificateTimestampStore::GetInstance());
553 for (net::SignedCertificateTimestampAndStatusList::const_iterator iter =
554 sct_list.begin(); iter != sct_list.end(); ++iter) {
555 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
556 sct_ids->push_back(
557 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
561 void ResourceLoader::CompleteResponseStarted() {
562 ResourceRequestInfoImpl* info = GetRequestInfo();
563 scoped_refptr<ResourceResponse> response(new ResourceResponse());
564 PopulateResourceResponse(info, request_.get(), response.get());
566 if (request_->ssl_info().cert.get()) {
567 int cert_id = CertStore::GetInstance()->StoreCert(
568 request_->ssl_info().cert.get(), info->GetChildID());
570 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
571 StoreSignedCertificateTimestamps(
572 request_->ssl_info().signed_certificate_timestamps,
573 info->GetChildID(),
574 &signed_certificate_timestamp_ids);
576 response->head.security_info = SerializeSecurityInfo(
577 cert_id,
578 request_->ssl_info().cert_status,
579 request_->ssl_info().security_bits,
580 request_->ssl_info().connection_status,
581 signed_certificate_timestamp_ids);
582 } else {
583 // We should not have any SSL state.
584 DCHECK(!request_->ssl_info().cert_status &&
585 request_->ssl_info().security_bits == -1 &&
586 !request_->ssl_info().connection_status);
589 delegate_->DidReceiveResponse(this);
591 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
592 tracked_objects::ScopedTracker tracking_profile(
593 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
595 bool defer = false;
596 if (!handler_->OnResponseStarted(response.get(), &defer)) {
597 Cancel();
598 } else if (defer) {
599 read_deferral_start_time_ = base::TimeTicks::Now();
600 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
604 void ResourceLoader::StartReading(bool is_continuation) {
605 int bytes_read = 0;
606 ReadMore(&bytes_read);
608 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
609 if (request_->status().is_io_pending())
610 return;
612 if (!is_continuation || bytes_read <= 0) {
613 OnReadCompleted(request_.get(), bytes_read);
614 } else {
615 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
616 // thread in case the URLRequest can provide data synchronously.
617 base::ThreadTaskRunnerHandle::Get()->PostTask(
618 FROM_HERE,
619 base::Bind(&ResourceLoader::OnReadCompleted,
620 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
624 void ResourceLoader::ResumeReading() {
625 DCHECK(!is_deferred());
627 if (!read_deferral_start_time_.is_null()) {
628 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
629 base::TimeTicks::Now() - read_deferral_start_time_);
630 read_deferral_start_time_ = base::TimeTicks();
632 if (request_->status().is_success()) {
633 StartReading(false); // Read the next chunk (OK to complete synchronously).
634 } else {
635 ResponseCompleted();
639 void ResourceLoader::ReadMore(int* bytes_read) {
640 DCHECK(!is_deferred());
642 // Make sure we track the buffer in at least one place. This ensures it gets
643 // deleted even in the case the request has already finished its job and
644 // doesn't use the buffer.
645 scoped_refptr<net::IOBuffer> buf;
646 int buf_size;
648 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
649 tracked_objects::ScopedTracker tracking_profile2(
650 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()"));
652 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
653 Cancel();
654 return;
658 DCHECK(buf.get());
659 DCHECK(buf_size > 0);
661 request_->Read(buf.get(), buf_size, bytes_read);
663 // No need to check the return value here as we'll detect errors by
664 // inspecting the URLRequest's status.
667 void ResourceLoader::CompleteRead(int bytes_read) {
668 DCHECK(bytes_read >= 0);
669 DCHECK(request_->status().is_success());
671 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
672 tracked_objects::ScopedTracker tracking_profile(
673 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
675 bool defer = false;
676 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
677 Cancel();
678 } else if (defer) {
679 deferred_stage_ =
680 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
683 // Note: the request may still have been cancelled while OnReadCompleted
684 // returns true if OnReadCompleted caused request to get cancelled
685 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
686 // instance.)
689 void ResourceLoader::ResponseCompleted() {
690 DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
691 RecordHistograms();
692 ResourceRequestInfoImpl* info = GetRequestInfo();
694 std::string security_info;
695 const net::SSLInfo& ssl_info = request_->ssl_info();
696 if (ssl_info.cert.get() != NULL) {
697 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert.get(),
698 info->GetChildID());
699 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
700 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
701 info->GetChildID(),
702 &signed_certificate_timestamp_ids);
704 security_info = SerializeSecurityInfo(
705 cert_id, ssl_info.cert_status, ssl_info.security_bits,
706 ssl_info.connection_status, signed_certificate_timestamp_ids);
709 bool defer = false;
711 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
712 tracked_objects::ScopedTracker tracking_profile(
713 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
715 handler_->OnResponseCompleted(request_->status(), security_info, &defer);
717 if (defer) {
718 // The handler is not ready to die yet. We will call DidFinishLoading when
719 // we resume.
720 deferred_stage_ = DEFERRED_FINISH;
721 } else {
722 // This will result in our destruction.
723 CallDidFinishLoading();
727 void ResourceLoader::CallDidFinishLoading() {
728 delegate_->DidFinishLoading(this);
731 void ResourceLoader::RecordHistograms() {
732 ResourceRequestInfoImpl* info = GetRequestInfo();
734 if (info->GetResourceType() == RESOURCE_TYPE_PREFETCH) {
735 PrefetchStatus status = STATUS_UNDEFINED;
736 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
738 switch (request_->status().status()) {
739 case net::URLRequestStatus::SUCCESS:
740 if (request_->was_cached()) {
741 status = STATUS_SUCCESS_FROM_CACHE;
742 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
743 total_time);
744 } else {
745 status = STATUS_SUCCESS_FROM_NETWORK;
746 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
747 total_time);
749 break;
750 case net::URLRequestStatus::CANCELED:
751 status = STATUS_CANCELED;
752 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
753 break;
754 case net::URLRequestStatus::IO_PENDING:
755 case net::URLRequestStatus::FAILED:
756 status = STATUS_UNDEFINED;
757 break;
760 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
764 } // namespace content