Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blobe1f1bf9ef9ed81fa78bbb7f94501810844f7589c
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/browser/ssl/ssl_policy.h"
24 #include "content/common/ssl_status_serialization.h"
25 #include "content/public/browser/cert_store.h"
26 #include "content/public/browser/resource_context.h"
27 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
28 #include "content/public/browser/signed_certificate_timestamp_store.h"
29 #include "content/public/common/content_client.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/common/process_type.h"
32 #include "content/public/common/resource_response.h"
33 #include "content/public/common/security_style.h"
34 #include "net/base/io_buffer.h"
35 #include "net/base/load_flags.h"
36 #include "net/http/http_response_headers.h"
37 #include "net/ssl/client_cert_store.h"
38 #include "net/url_request/redirect_info.h"
39 #include "net/url_request/url_request_status.h"
41 using base::TimeDelta;
42 using base::TimeTicks;
44 namespace content {
45 namespace {
47 void StoreSignedCertificateTimestamps(
48 const net::SignedCertificateTimestampAndStatusList& sct_list,
49 int process_id,
50 SignedCertificateTimestampIDStatusList* sct_ids) {
51 SignedCertificateTimestampStore* sct_store(
52 SignedCertificateTimestampStore::GetInstance());
54 for (auto iter = sct_list.begin(); iter != sct_list.end(); ++iter) {
55 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
56 sct_ids->push_back(
57 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
61 void GetSSLStatusForRequest(const GURL& url,
62 const net::SSLInfo& ssl_info,
63 int child_id,
64 SSLStatus* ssl_status) {
65 DCHECK(ssl_info.cert);
67 int cert_id =
68 CertStore::GetInstance()->StoreCert(ssl_info.cert.get(), child_id);
70 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
71 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
72 child_id, &signed_certificate_timestamp_ids);
74 ssl_status->cert_id = cert_id;
75 ssl_status->cert_status = ssl_info.cert_status;
76 ssl_status->security_bits = ssl_info.security_bits;
77 ssl_status->connection_status = ssl_info.connection_status;
78 ssl_status->signed_certificate_timestamp_ids =
79 signed_certificate_timestamp_ids;
80 ssl_status->security_style =
81 SSLPolicy::GetSecurityStyleForResource(url, *ssl_status);
84 void PopulateResourceResponse(ResourceRequestInfoImpl* info,
85 net::URLRequest* request,
86 ResourceResponse* response) {
87 response->head.request_time = request->request_time();
88 response->head.response_time = request->response_time();
89 response->head.headers = request->response_headers();
90 request->GetCharset(&response->head.charset);
91 response->head.content_length = request->GetExpectedContentSize();
92 request->GetMimeType(&response->head.mime_type);
93 net::HttpResponseInfo response_info = request->response_info();
94 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
95 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
96 response->head.npn_negotiated_protocol =
97 response_info.npn_negotiated_protocol;
98 response->head.connection_info = response_info.connection_info;
99 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
100 response->head.proxy_server = response_info.proxy_server;
101 response->head.socket_address = request->GetSocketAddress();
102 if (ServiceWorkerRequestHandler* handler =
103 ServiceWorkerRequestHandler::GetHandler(request)) {
104 handler->GetExtraResponseInfo(&response->head);
106 AppCacheInterceptor::GetExtraResponseInfo(
107 request, &response->head.appcache_id,
108 &response->head.appcache_manifest_url);
109 if (info->is_load_timing_enabled())
110 request->GetLoadTimingInfo(&response->head.load_timing);
112 if (request->ssl_info().cert.get()) {
113 SSLStatus ssl_status;
114 GetSSLStatusForRequest(request->url(), request->ssl_info(),
115 info->GetChildID(), &ssl_status);
116 response->head.security_info = SerializeSecurityInfo(ssl_status);
117 } else {
118 // We should not have any SSL state.
119 DCHECK(!request->ssl_info().cert_status &&
120 request->ssl_info().security_bits == -1 &&
121 !request->ssl_info().connection_status);
125 } // namespace
127 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
128 scoped_ptr<ResourceHandler> handler,
129 ResourceLoaderDelegate* delegate)
130 : deferred_stage_(DEFERRED_NONE),
131 request_(request.Pass()),
132 handler_(handler.Pass()),
133 delegate_(delegate),
134 is_transferring_(false),
135 times_cancelled_before_request_start_(0),
136 started_request_(false),
137 times_cancelled_after_request_start_(0),
138 weak_ptr_factory_(this) {
139 request_->set_delegate(this);
140 handler_->SetController(this);
143 ResourceLoader::~ResourceLoader() {
144 if (login_delegate_.get())
145 login_delegate_->OnRequestCancelled();
146 ssl_client_auth_handler_.reset();
148 // Run ResourceHandler destructor before we tear-down the rest of our state
149 // as the ResourceHandler may want to inspect the URLRequest and other state.
150 handler_.reset();
153 void ResourceLoader::StartRequest() {
154 if (delegate_->HandleExternalProtocol(this, request_->url())) {
155 CancelAndIgnore();
156 return;
159 // Give the handler a chance to delay the URLRequest from being started.
160 bool defer_start = false;
161 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
162 Cancel();
163 return;
166 if (defer_start) {
167 deferred_stage_ = DEFERRED_START;
168 } else {
169 StartRequestInternal();
173 void ResourceLoader::CancelRequest(bool from_renderer) {
174 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
177 void ResourceLoader::CancelAndIgnore() {
178 ResourceRequestInfoImpl* info = GetRequestInfo();
179 info->set_was_ignored_by_handler(true);
180 CancelRequest(false);
183 void ResourceLoader::CancelWithError(int error_code) {
184 CancelRequestInternal(error_code, false);
187 void ResourceLoader::MarkAsTransferring() {
188 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
189 << "Can only transfer for navigations";
190 is_transferring_ = true;
192 int child_id = GetRequestInfo()->GetChildID();
193 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
194 ServiceWorkerRequestHandler* handler =
195 ServiceWorkerRequestHandler::GetHandler(request());
196 if (handler)
197 handler->PrepareForCrossSiteTransfer(child_id);
200 void ResourceLoader::CompleteTransfer() {
201 // Although CrossSiteResourceHandler defers at OnResponseStarted
202 // (DEFERRED_READ), it may be seeing a replay of events via
203 // MimeTypeResourceHandler, and so the request itself is actually deferred
204 // at a later read stage.
205 DCHECK(DEFERRED_READ == deferred_stage_ ||
206 DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
207 DCHECK(is_transferring_);
209 // In some cases, a process transfer doesn't really happen and the
210 // request is resumed in the original process. Real transfers to a new process
211 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
212 int child_id = GetRequestInfo()->GetChildID();
213 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
214 request(), child_id);
215 ServiceWorkerRequestHandler* handler =
216 ServiceWorkerRequestHandler::GetHandler(request());
217 if (handler)
218 handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
220 is_transferring_ = false;
221 GetRequestInfo()->cross_site_handler()->ResumeResponse();
224 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
225 return ResourceRequestInfoImpl::ForRequest(request_.get());
228 void ResourceLoader::ClearLoginDelegate() {
229 login_delegate_ = NULL;
232 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
233 const net::RedirectInfo& redirect_info,
234 bool* defer) {
235 DCHECK_EQ(request_.get(), unused);
237 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
238 DCHECK(request_->status().is_success());
240 ResourceRequestInfoImpl* info = GetRequestInfo();
242 if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
243 !ChildProcessSecurityPolicyImpl::GetInstance()->
244 CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
245 DVLOG(1) << "Denied unauthorized request for "
246 << redirect_info.new_url.possibly_invalid_spec();
248 // Tell the renderer that this request was disallowed.
249 Cancel();
250 return;
253 delegate_->DidReceiveRedirect(this, redirect_info.new_url);
255 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
256 // The request is complete so we can remove it.
257 CancelAndIgnore();
258 return;
261 scoped_refptr<ResourceResponse> response(new ResourceResponse());
262 PopulateResourceResponse(info, request_.get(), response.get());
263 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
264 Cancel();
265 } else if (*defer) {
266 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
270 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
271 net::AuthChallengeInfo* auth_info) {
272 DCHECK_EQ(request_.get(), unused);
274 ResourceRequestInfoImpl* info = GetRequestInfo();
275 if (info->do_not_prompt_for_login()) {
276 request_->CancelAuth();
277 return;
280 // Create a login dialog on the UI thread to get authentication data, or pull
281 // from cache and continue on the IO thread.
283 DCHECK(!login_delegate_.get())
284 << "OnAuthRequired called with login_delegate pending";
285 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
286 if (!login_delegate_.get())
287 request_->CancelAuth();
290 void ResourceLoader::OnCertificateRequested(
291 net::URLRequest* unused,
292 net::SSLCertRequestInfo* cert_info) {
293 DCHECK_EQ(request_.get(), unused);
295 if (request_->load_flags() & net::LOAD_PREFETCH) {
296 request_->Cancel();
297 return;
300 DCHECK(!ssl_client_auth_handler_)
301 << "OnCertificateRequested called with ssl_client_auth_handler pending";
302 ssl_client_auth_handler_.reset(new SSLClientAuthHandler(
303 GetRequestInfo()->GetContext()->CreateClientCertStore(), request_.get(),
304 cert_info, this));
305 ssl_client_auth_handler_->SelectCertificate();
308 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
309 const net::SSLInfo& ssl_info,
310 bool fatal) {
311 ResourceRequestInfoImpl* info = GetRequestInfo();
313 int render_process_id;
314 int render_frame_id;
315 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
316 NOTREACHED();
318 SSLManager::OnSSLCertificateError(
319 weak_ptr_factory_.GetWeakPtr(),
320 info->GetResourceType(),
321 request_->url(),
322 render_process_id,
323 render_frame_id,
324 ssl_info,
325 fatal);
328 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
329 bool* defer) {
330 DCHECK_EQ(request_.get(), unused);
332 // Give the handler a chance to delay the URLRequest from using the network.
333 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
334 Cancel();
335 return;
336 } else if (*defer) {
337 deferred_stage_ = DEFERRED_NETWORK_START;
341 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
342 DCHECK_EQ(request_.get(), unused);
344 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
346 if (!request_->status().is_success()) {
347 ResponseCompleted();
348 return;
351 CompleteResponseStarted();
353 if (is_deferred())
354 return;
356 if (request_->status().is_success())
357 StartReading(false); // Read the first chunk.
358 else
359 ResponseCompleted();
362 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
363 DCHECK_EQ(request_.get(), unused);
364 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
365 << " bytes_read = " << bytes_read;
367 // bytes_read == -1 always implies an error.
368 if (bytes_read == -1 || !request_->status().is_success()) {
369 ResponseCompleted();
370 return;
373 CompleteRead(bytes_read);
375 // If the handler cancelled or deferred the request, do not continue
376 // processing the read. If cancelled, the URLRequest has already been
377 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
378 // do nothing until resumed.
380 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
381 // ResponseCompleted().
382 if (is_deferred() || !request_->status().is_success())
383 return;
385 if (bytes_read > 0) {
386 StartReading(true); // Read the next chunk.
387 } else {
388 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
389 tracked_objects::ScopedTracker tracking_profile(
390 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
392 // URLRequest reported an EOF. Call ResponseCompleted.
393 DCHECK_EQ(0, bytes_read);
394 ResponseCompleted();
398 void ResourceLoader::CancelSSLRequest(int error,
399 const net::SSLInfo* ssl_info) {
400 DCHECK_CURRENTLY_ON(BrowserThread::IO);
402 // The request can be NULL if it was cancelled by the renderer (as the
403 // request of the user navigating to a new page from the location bar).
404 if (!request_->is_pending())
405 return;
406 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
408 if (ssl_info) {
409 request_->CancelWithSSLError(error, *ssl_info);
410 } else {
411 request_->CancelWithError(error);
415 void ResourceLoader::ContinueSSLRequest() {
416 DCHECK_CURRENTLY_ON(BrowserThread::IO);
418 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
420 request_->ContinueDespiteLastError();
423 void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
424 DCHECK(ssl_client_auth_handler_);
425 ssl_client_auth_handler_.reset();
426 request_->ContinueWithCertificate(cert);
429 void ResourceLoader::CancelCertificateSelection() {
430 DCHECK(ssl_client_auth_handler_);
431 ssl_client_auth_handler_.reset();
432 request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
435 void ResourceLoader::Resume() {
436 DCHECK(!is_transferring_);
438 DeferredStage stage = deferred_stage_;
439 deferred_stage_ = DEFERRED_NONE;
440 switch (stage) {
441 case DEFERRED_NONE:
442 NOTREACHED();
443 break;
444 case DEFERRED_START:
445 StartRequestInternal();
446 break;
447 case DEFERRED_NETWORK_START:
448 request_->ResumeNetworkStart();
449 break;
450 case DEFERRED_REDIRECT:
451 request_->FollowDeferredRedirect();
452 break;
453 case DEFERRED_READ:
454 base::ThreadTaskRunnerHandle::Get()->PostTask(
455 FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
456 weak_ptr_factory_.GetWeakPtr()));
457 break;
458 case DEFERRED_RESPONSE_COMPLETE:
459 base::ThreadTaskRunnerHandle::Get()->PostTask(
460 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
461 weak_ptr_factory_.GetWeakPtr()));
462 break;
463 case DEFERRED_FINISH:
464 // Delay self-destruction since we don't know how we were reached.
465 base::ThreadTaskRunnerHandle::Get()->PostTask(
466 FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
467 weak_ptr_factory_.GetWeakPtr()));
468 break;
472 void ResourceLoader::Cancel() {
473 CancelRequest(false);
476 void ResourceLoader::StartRequestInternal() {
477 DCHECK(!request_->is_pending());
479 if (!request_->status().is_success()) {
480 return;
483 started_request_ = true;
484 request_->Start();
486 delegate_->DidStartRequest(this);
489 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
490 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
492 ResourceRequestInfoImpl* info = GetRequestInfo();
494 // WebKit will send us a cancel for downloads since it no longer handles
495 // them. In this case, ignore the cancel since we handle downloads in the
496 // browser.
497 if (from_renderer && (info->IsDownload() || info->is_stream()))
498 return;
500 if (from_renderer && info->detachable_handler()) {
501 // TODO(davidben): Fix Blink handling of prefetches so they are not
502 // cancelled on navigate away and end up in the local cache.
503 info->detachable_handler()->Detach();
504 return;
507 // TODO(darin): Perhaps we should really be looking to see if the status is
508 // IO_PENDING?
509 bool was_pending = request_->is_pending();
511 if (login_delegate_.get()) {
512 login_delegate_->OnRequestCancelled();
513 login_delegate_ = NULL;
515 ssl_client_auth_handler_.reset();
517 if (!started_request_) {
518 times_cancelled_before_request_start_++;
519 } else {
520 times_cancelled_after_request_start_++;
523 request_->CancelWithError(error);
525 if (!was_pending) {
526 // If the request isn't in flight, then we won't get an asynchronous
527 // notification from the request, so we have to signal ourselves to finish
528 // this request.
529 base::ThreadTaskRunnerHandle::Get()->PostTask(
530 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
531 weak_ptr_factory_.GetWeakPtr()));
535 void ResourceLoader::CompleteResponseStarted() {
536 ResourceRequestInfoImpl* info = GetRequestInfo();
537 scoped_refptr<ResourceResponse> response(new ResourceResponse());
538 PopulateResourceResponse(info, request_.get(), response.get());
540 delegate_->DidReceiveResponse(this);
542 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
543 tracked_objects::ScopedTracker tracking_profile(
544 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
546 bool defer = false;
547 if (!handler_->OnResponseStarted(response.get(), &defer)) {
548 Cancel();
549 } else if (defer) {
550 read_deferral_start_time_ = base::TimeTicks::Now();
551 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
555 void ResourceLoader::StartReading(bool is_continuation) {
556 int bytes_read = 0;
557 ReadMore(&bytes_read);
559 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
560 if (request_->status().is_io_pending())
561 return;
563 if (!is_continuation || bytes_read <= 0) {
564 OnReadCompleted(request_.get(), bytes_read);
565 } else {
566 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
567 // thread in case the URLRequest can provide data synchronously.
568 base::ThreadTaskRunnerHandle::Get()->PostTask(
569 FROM_HERE,
570 base::Bind(&ResourceLoader::OnReadCompleted,
571 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
575 void ResourceLoader::ResumeReading() {
576 DCHECK(!is_deferred());
578 if (!read_deferral_start_time_.is_null()) {
579 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
580 base::TimeTicks::Now() - read_deferral_start_time_);
581 read_deferral_start_time_ = base::TimeTicks();
583 if (request_->status().is_success()) {
584 StartReading(false); // Read the next chunk (OK to complete synchronously).
585 } else {
586 ResponseCompleted();
590 void ResourceLoader::ReadMore(int* bytes_read) {
591 DCHECK(!is_deferred());
593 // Make sure we track the buffer in at least one place. This ensures it gets
594 // deleted even in the case the request has already finished its job and
595 // doesn't use the buffer.
596 scoped_refptr<net::IOBuffer> buf;
597 int buf_size;
599 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
600 tracked_objects::ScopedTracker tracking_profile2(
601 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()"));
603 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
604 Cancel();
605 return;
609 DCHECK(buf.get());
610 DCHECK(buf_size > 0);
612 request_->Read(buf.get(), buf_size, bytes_read);
614 // No need to check the return value here as we'll detect errors by
615 // inspecting the URLRequest's status.
618 void ResourceLoader::CompleteRead(int bytes_read) {
619 DCHECK(bytes_read >= 0);
620 DCHECK(request_->status().is_success());
622 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
623 tracked_objects::ScopedTracker tracking_profile(
624 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
626 bool defer = false;
627 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
628 Cancel();
629 } else if (defer) {
630 deferred_stage_ =
631 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
634 // Note: the request may still have been cancelled while OnReadCompleted
635 // returns true if OnReadCompleted caused request to get cancelled
636 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
637 // instance.)
640 void ResourceLoader::ResponseCompleted() {
641 DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
642 RecordHistograms();
643 ResourceRequestInfoImpl* info = GetRequestInfo();
645 std::string security_info;
646 const net::SSLInfo& ssl_info = request_->ssl_info();
647 if (ssl_info.cert.get() != NULL) {
648 SSLStatus ssl_status;
649 GetSSLStatusForRequest(request_->url(), ssl_info, info->GetChildID(),
650 &ssl_status);
652 security_info = SerializeSecurityInfo(ssl_status);
655 bool defer = false;
657 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
658 tracked_objects::ScopedTracker tracking_profile(
659 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
661 handler_->OnResponseCompleted(request_->status(), security_info, &defer);
663 if (defer) {
664 // The handler is not ready to die yet. We will call DidFinishLoading when
665 // we resume.
666 deferred_stage_ = DEFERRED_FINISH;
667 } else {
668 // This will result in our destruction.
669 CallDidFinishLoading();
673 void ResourceLoader::CallDidFinishLoading() {
674 delegate_->DidFinishLoading(this);
677 void ResourceLoader::RecordHistograms() {
678 ResourceRequestInfoImpl* info = GetRequestInfo();
680 if (info->GetResourceType() == RESOURCE_TYPE_PREFETCH) {
681 PrefetchStatus status = STATUS_UNDEFINED;
682 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
684 switch (request_->status().status()) {
685 case net::URLRequestStatus::SUCCESS:
686 if (request_->was_cached()) {
687 status = STATUS_SUCCESS_FROM_CACHE;
688 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
689 total_time);
690 } else {
691 status = STATUS_SUCCESS_FROM_NETWORK;
692 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
693 total_time);
695 break;
696 case net::URLRequestStatus::CANCELED:
697 status = STATUS_CANCELED;
698 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
699 break;
700 case net::URLRequestStatus::IO_PENDING:
701 case net::URLRequestStatus::FAILED:
702 status = STATUS_UNDEFINED;
703 break;
706 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
710 } // namespace content