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
;
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(
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
);
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()),
87 last_upload_position_(0),
88 waiting_for_upload_progress_ack_(false),
89 is_transferring_(false),
90 weak_ptr_factory_(this) {
91 request_
->set_delegate(this);
92 handler_
->SetController(this);
95 ResourceLoader::~ResourceLoader() {
96 if (login_delegate_
.get())
97 login_delegate_
->OnRequestCancelled();
98 ssl_client_auth_handler_
.reset();
100 // Run ResourceHandler destructor before we tear-down the rest of our state
101 // as the ResourceHandler may want to inspect the URLRequest and other state.
105 void ResourceLoader::StartRequest() {
106 if (delegate_
->HandleExternalProtocol(this, request_
->url())) {
111 // Give the handler a chance to delay the URLRequest from being started.
112 bool defer_start
= false;
113 if (!handler_
->OnWillStart(request_
->url(), &defer_start
)) {
119 deferred_stage_
= DEFERRED_START
;
121 StartRequestInternal();
125 void ResourceLoader::CancelRequest(bool from_renderer
) {
126 CancelRequestInternal(net::ERR_ABORTED
, from_renderer
);
129 void ResourceLoader::CancelAndIgnore() {
130 ResourceRequestInfoImpl
* info
= GetRequestInfo();
131 info
->set_was_ignored_by_handler(true);
132 CancelRequest(false);
135 void ResourceLoader::CancelWithError(int error_code
) {
136 CancelRequestInternal(error_code
, false);
139 void ResourceLoader::ReportUploadProgress() {
140 DCHECK(GetRequestInfo()->is_upload_progress_enabled());
142 if (waiting_for_upload_progress_ack_
)
143 return; // Send one progress event at a time.
145 net::UploadProgress progress
= request_
->GetUploadProgress();
146 if (!progress
.size())
147 return; // Nothing to upload.
149 if (progress
.position() == last_upload_position_
)
150 return; // No progress made since last time.
152 const uint64 kHalfPercentIncrements
= 200;
153 const TimeDelta kOneSecond
= TimeDelta::FromMilliseconds(1000);
155 uint64 amt_since_last
= progress
.position() - last_upload_position_
;
156 TimeDelta time_since_last
= TimeTicks::Now() - last_upload_ticks_
;
158 bool is_finished
= (progress
.size() == progress
.position());
159 bool enough_new_progress
=
160 (amt_since_last
> (progress
.size() / kHalfPercentIncrements
));
161 bool too_much_time_passed
= time_since_last
> kOneSecond
;
163 if (is_finished
|| enough_new_progress
|| too_much_time_passed
) {
164 handler_
->OnUploadProgress(progress
.position(), progress
.size());
165 waiting_for_upload_progress_ack_
= true;
166 last_upload_ticks_
= TimeTicks::Now();
167 last_upload_position_
= progress
.position();
171 void ResourceLoader::MarkAsTransferring() {
172 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
173 << "Can only transfer for navigations";
174 is_transferring_
= true;
176 int child_id
= GetRequestInfo()->GetChildID();
177 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id
);
178 ServiceWorkerRequestHandler
* handler
=
179 ServiceWorkerRequestHandler::GetHandler(request());
181 handler
->PrepareForCrossSiteTransfer(child_id
);
184 void ResourceLoader::CompleteTransfer() {
185 // Although CrossSiteResourceHandler defers at OnResponseStarted
186 // (DEFERRED_READ), it may be seeing a replay of events via
187 // BufferedResourceHandler, and so the request itself is actually deferred at
188 // a later read stage.
189 DCHECK(DEFERRED_READ
== deferred_stage_
||
190 DEFERRED_RESPONSE_COMPLETE
== deferred_stage_
);
191 DCHECK(is_transferring_
);
193 // In some cases, a process transfer doesn't really happen and the
194 // request is resumed in the original process. Real transfers to a new process
195 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
196 int child_id
= GetRequestInfo()->GetChildID();
197 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
198 request(), child_id
);
199 ServiceWorkerRequestHandler
* handler
=
200 ServiceWorkerRequestHandler::GetHandler(request());
202 handler
->MaybeCompleteCrossSiteTransferInOldProcess(child_id
);
204 is_transferring_
= false;
205 GetRequestInfo()->cross_site_handler()->ResumeResponse();
208 ResourceRequestInfoImpl
* ResourceLoader::GetRequestInfo() {
209 return ResourceRequestInfoImpl::ForRequest(request_
.get());
212 void ResourceLoader::ClearLoginDelegate() {
213 login_delegate_
= NULL
;
216 void ResourceLoader::OnUploadProgressACK() {
217 waiting_for_upload_progress_ack_
= false;
220 void ResourceLoader::OnReceivedRedirect(net::URLRequest
* unused
,
221 const net::RedirectInfo
& redirect_info
,
223 DCHECK_EQ(request_
.get(), unused
);
225 VLOG(1) << "OnReceivedRedirect: " << request_
->url().spec();
226 DCHECK(request_
->status().is_success());
228 ResourceRequestInfoImpl
* info
= GetRequestInfo();
230 if (info
->GetProcessType() != PROCESS_TYPE_PLUGIN
&&
231 !ChildProcessSecurityPolicyImpl::GetInstance()->
232 CanRequestURL(info
->GetChildID(), redirect_info
.new_url
)) {
233 VLOG(1) << "Denied unauthorized request for "
234 << redirect_info
.new_url
.possibly_invalid_spec();
236 // Tell the renderer that this request was disallowed.
241 delegate_
->DidReceiveRedirect(this, redirect_info
.new_url
);
243 if (delegate_
->HandleExternalProtocol(this, redirect_info
.new_url
)) {
244 // The request is complete so we can remove it.
249 scoped_refptr
<ResourceResponse
> response(new ResourceResponse());
250 PopulateResourceResponse(info
, request_
.get(), response
.get());
251 if (!handler_
->OnRequestRedirected(redirect_info
, response
.get(), defer
)) {
254 deferred_stage_
= DEFERRED_REDIRECT
; // Follow redirect when resumed.
258 void ResourceLoader::OnAuthRequired(net::URLRequest
* unused
,
259 net::AuthChallengeInfo
* auth_info
) {
260 DCHECK_EQ(request_
.get(), unused
);
262 ResourceRequestInfoImpl
* info
= GetRequestInfo();
263 if (info
->do_not_prompt_for_login()) {
264 request_
->CancelAuth();
268 // Create a login dialog on the UI thread to get authentication data, or pull
269 // from cache and continue on the IO thread.
271 DCHECK(!login_delegate_
.get())
272 << "OnAuthRequired called with login_delegate pending";
273 login_delegate_
= delegate_
->CreateLoginDelegate(this, auth_info
);
274 if (!login_delegate_
.get())
275 request_
->CancelAuth();
278 void ResourceLoader::OnCertificateRequested(
279 net::URLRequest
* unused
,
280 net::SSLCertRequestInfo
* cert_info
) {
281 DCHECK_EQ(request_
.get(), unused
);
283 if (request_
->load_flags() & net::LOAD_PREFETCH
) {
288 DCHECK(!ssl_client_auth_handler_
)
289 << "OnCertificateRequested called with ssl_client_auth_handler pending";
290 ssl_client_auth_handler_
.reset(new SSLClientAuthHandler(
291 GetRequestInfo()->GetContext()->CreateClientCertStore(), request_
.get(),
293 ssl_client_auth_handler_
->SelectCertificate();
296 void ResourceLoader::OnSSLCertificateError(net::URLRequest
* request
,
297 const net::SSLInfo
& ssl_info
,
299 ResourceRequestInfoImpl
* info
= GetRequestInfo();
301 int render_process_id
;
303 if (!info
->GetAssociatedRenderFrame(&render_process_id
, &render_frame_id
))
306 SSLManager::OnSSLCertificateError(
307 weak_ptr_factory_
.GetWeakPtr(),
308 info
->GetResourceType(),
316 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest
* unused
,
318 DCHECK_EQ(request_
.get(), unused
);
320 // Give the handler a chance to delay the URLRequest from using the network.
321 if (!handler_
->OnBeforeNetworkStart(request_
->url(), defer
)) {
325 deferred_stage_
= DEFERRED_NETWORK_START
;
329 void ResourceLoader::OnResponseStarted(net::URLRequest
* unused
) {
330 DCHECK_EQ(request_
.get(), unused
);
332 VLOG(1) << "OnResponseStarted: " << request_
->url().spec();
334 progress_timer_
.Stop();
336 // The CanLoadPage check should take place after any server redirects have
337 // finished, at the point in time that we know a page will commit in the
339 ResourceRequestInfoImpl
* info
= GetRequestInfo();
340 ChildProcessSecurityPolicyImpl
* policy
=
341 ChildProcessSecurityPolicyImpl::GetInstance();
342 if (!policy
->CanLoadPage(info
->GetChildID(),
344 info
->GetResourceType())) {
349 if (!request_
->status().is_success()) {
354 // We want to send a final upload progress message prior to sending the
355 // response complete message even if we're waiting for an ack to to a
356 // previous upload progress message.
357 if (info
->is_upload_progress_enabled()) {
358 waiting_for_upload_progress_ack_
= false;
359 ReportUploadProgress();
362 CompleteResponseStarted();
367 if (request_
->status().is_success())
368 StartReading(false); // Read the first chunk.
373 void ResourceLoader::OnReadCompleted(net::URLRequest
* unused
, int bytes_read
) {
374 DCHECK_EQ(request_
.get(), unused
);
375 VLOG(1) << "OnReadCompleted: \"" << request_
->url().spec() << "\""
376 << " bytes_read = " << bytes_read
;
378 // bytes_read == -1 always implies an error.
379 if (bytes_read
== -1 || !request_
->status().is_success()) {
384 CompleteRead(bytes_read
);
386 // If the handler cancelled or deferred the request, do not continue
387 // processing the read. If cancelled, the URLRequest has already been
388 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
389 // do nothing until resumed.
391 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
392 // ResponseCompleted().
393 if (is_deferred() || !request_
->status().is_success())
396 if (bytes_read
> 0) {
397 StartReading(true); // Read the next chunk.
399 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
400 tracked_objects::ScopedTracker
tracking_profile(
401 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
403 // URLRequest reported an EOF. Call ResponseCompleted.
404 DCHECK_EQ(0, bytes_read
);
409 void ResourceLoader::CancelSSLRequest(int error
,
410 const net::SSLInfo
* ssl_info
) {
411 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
413 // The request can be NULL if it was cancelled by the renderer (as the
414 // request of the user navigating to a new page from the location bar).
415 if (!request_
->is_pending())
417 DVLOG(1) << "CancelSSLRequest() url: " << request_
->url().spec();
420 request_
->CancelWithSSLError(error
, *ssl_info
);
422 request_
->CancelWithError(error
);
426 void ResourceLoader::ContinueSSLRequest() {
427 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
429 DVLOG(1) << "ContinueSSLRequest() url: " << request_
->url().spec();
431 request_
->ContinueDespiteLastError();
434 void ResourceLoader::ContinueWithCertificate(net::X509Certificate
* cert
) {
435 DCHECK(ssl_client_auth_handler_
);
436 ssl_client_auth_handler_
.reset();
437 request_
->ContinueWithCertificate(cert
);
440 void ResourceLoader::CancelCertificateSelection() {
441 DCHECK(ssl_client_auth_handler_
);
442 ssl_client_auth_handler_
.reset();
443 request_
->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED
);
446 void ResourceLoader::Resume() {
447 DCHECK(!is_transferring_
);
449 DeferredStage stage
= deferred_stage_
;
450 deferred_stage_
= DEFERRED_NONE
;
456 StartRequestInternal();
458 case DEFERRED_NETWORK_START
:
459 request_
->ResumeNetworkStart();
461 case DEFERRED_REDIRECT
:
462 request_
->FollowDeferredRedirect();
465 base::ThreadTaskRunnerHandle::Get()->PostTask(
466 FROM_HERE
, base::Bind(&ResourceLoader::ResumeReading
,
467 weak_ptr_factory_
.GetWeakPtr()));
469 case DEFERRED_RESPONSE_COMPLETE
:
470 base::ThreadTaskRunnerHandle::Get()->PostTask(
471 FROM_HERE
, base::Bind(&ResourceLoader::ResponseCompleted
,
472 weak_ptr_factory_
.GetWeakPtr()));
474 case DEFERRED_FINISH
:
475 // Delay self-destruction since we don't know how we were reached.
476 base::ThreadTaskRunnerHandle::Get()->PostTask(
477 FROM_HERE
, base::Bind(&ResourceLoader::CallDidFinishLoading
,
478 weak_ptr_factory_
.GetWeakPtr()));
483 void ResourceLoader::Cancel() {
484 CancelRequest(false);
487 void ResourceLoader::StartRequestInternal() {
488 DCHECK(!request_
->is_pending());
490 if (!request_
->status().is_success()) {
496 delegate_
->DidStartRequest(this);
498 if (GetRequestInfo()->is_upload_progress_enabled() &&
499 request_
->has_upload()) {
500 progress_timer_
.Start(
502 base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec
),
504 &ResourceLoader::ReportUploadProgress
);
508 void ResourceLoader::CancelRequestInternal(int error
, bool from_renderer
) {
509 VLOG(1) << "CancelRequestInternal: " << request_
->url().spec();
511 ResourceRequestInfoImpl
* info
= GetRequestInfo();
513 // WebKit will send us a cancel for downloads since it no longer handles
514 // them. In this case, ignore the cancel since we handle downloads in the
516 if (from_renderer
&& (info
->IsDownload() || info
->is_stream()))
519 if (from_renderer
&& info
->detachable_handler()) {
520 // TODO(davidben): Fix Blink handling of prefetches so they are not
521 // cancelled on navigate away and end up in the local cache.
522 info
->detachable_handler()->Detach();
526 // TODO(darin): Perhaps we should really be looking to see if the status is
528 bool was_pending
= request_
->is_pending();
530 if (login_delegate_
.get()) {
531 login_delegate_
->OnRequestCancelled();
532 login_delegate_
= NULL
;
534 ssl_client_auth_handler_
.reset();
536 request_
->CancelWithError(error
);
539 // If the request isn't in flight, then we won't get an asynchronous
540 // notification from the request, so we have to signal ourselves to finish
542 base::ThreadTaskRunnerHandle::Get()->PostTask(
543 FROM_HERE
, base::Bind(&ResourceLoader::ResponseCompleted
,
544 weak_ptr_factory_
.GetWeakPtr()));
548 void ResourceLoader::StoreSignedCertificateTimestamps(
549 const net::SignedCertificateTimestampAndStatusList
& sct_list
,
551 SignedCertificateTimestampIDStatusList
* sct_ids
) {
552 SignedCertificateTimestampStore
* sct_store(
553 SignedCertificateTimestampStore::GetInstance());
555 for (net::SignedCertificateTimestampAndStatusList::const_iterator iter
=
556 sct_list
.begin(); iter
!= sct_list
.end(); ++iter
) {
557 const int sct_id(sct_store
->Store(iter
->sct
.get(), process_id
));
559 SignedCertificateTimestampIDAndStatus(sct_id
, iter
->status
));
563 void ResourceLoader::CompleteResponseStarted() {
564 ResourceRequestInfoImpl
* info
= GetRequestInfo();
565 scoped_refptr
<ResourceResponse
> response(new ResourceResponse());
566 PopulateResourceResponse(info
, request_
.get(), response
.get());
568 if (request_
->ssl_info().cert
.get()) {
569 int cert_id
= CertStore::GetInstance()->StoreCert(
570 request_
->ssl_info().cert
.get(), info
->GetChildID());
572 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids
;
573 StoreSignedCertificateTimestamps(
574 request_
->ssl_info().signed_certificate_timestamps
,
576 &signed_certificate_timestamp_ids
);
578 response
->head
.security_info
= SerializeSecurityInfo(
580 request_
->ssl_info().cert_status
,
581 request_
->ssl_info().security_bits
,
582 request_
->ssl_info().connection_status
,
583 signed_certificate_timestamp_ids
);
585 // We should not have any SSL state.
586 DCHECK(!request_
->ssl_info().cert_status
&&
587 request_
->ssl_info().security_bits
== -1 &&
588 !request_
->ssl_info().connection_status
);
591 delegate_
->DidReceiveResponse(this);
593 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
594 tracked_objects::ScopedTracker
tracking_profile(
595 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
598 if (!handler_
->OnResponseStarted(response
.get(), &defer
)) {
601 read_deferral_start_time_
= base::TimeTicks::Now();
602 deferred_stage_
= DEFERRED_READ
; // Read first chunk when resumed.
606 void ResourceLoader::StartReading(bool is_continuation
) {
608 ReadMore(&bytes_read
);
610 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
611 if (request_
->status().is_io_pending())
614 if (!is_continuation
|| bytes_read
<= 0) {
615 OnReadCompleted(request_
.get(), bytes_read
);
617 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
618 // thread in case the URLRequest can provide data synchronously.
619 base::ThreadTaskRunnerHandle::Get()->PostTask(
621 base::Bind(&ResourceLoader::OnReadCompleted
,
622 weak_ptr_factory_
.GetWeakPtr(), request_
.get(), bytes_read
));
626 void ResourceLoader::ResumeReading() {
627 DCHECK(!is_deferred());
629 if (!read_deferral_start_time_
.is_null()) {
630 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
631 base::TimeTicks::Now() - read_deferral_start_time_
);
632 read_deferral_start_time_
= base::TimeTicks();
634 if (request_
->status().is_success()) {
635 StartReading(false); // Read the next chunk (OK to complete synchronously).
641 void ResourceLoader::ReadMore(int* bytes_read
) {
642 DCHECK(!is_deferred());
644 // Make sure we track the buffer in at least one place. This ensures it gets
645 // deleted even in the case the request has already finished its job and
646 // doesn't use the buffer.
647 scoped_refptr
<net::IOBuffer
> buf
;
650 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
651 tracked_objects::ScopedTracker
tracking_profile2(
652 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()"));
654 if (!handler_
->OnWillRead(&buf
, &buf_size
, -1)) {
661 DCHECK(buf_size
> 0);
663 request_
->Read(buf
.get(), buf_size
, bytes_read
);
665 // No need to check the return value here as we'll detect errors by
666 // inspecting the URLRequest's status.
669 void ResourceLoader::CompleteRead(int bytes_read
) {
670 DCHECK(bytes_read
>= 0);
671 DCHECK(request_
->status().is_success());
673 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
674 tracked_objects::ScopedTracker
tracking_profile(
675 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
678 if (!handler_
->OnReadCompleted(bytes_read
, &defer
)) {
682 bytes_read
> 0 ? DEFERRED_READ
: DEFERRED_RESPONSE_COMPLETE
;
685 // Note: the request may still have been cancelled while OnReadCompleted
686 // returns true if OnReadCompleted caused request to get cancelled
687 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
691 void ResourceLoader::ResponseCompleted() {
692 VLOG(1) << "ResponseCompleted: " << request_
->url().spec();
694 ResourceRequestInfoImpl
* info
= GetRequestInfo();
696 std::string security_info
;
697 const net::SSLInfo
& ssl_info
= request_
->ssl_info();
698 if (ssl_info
.cert
.get() != NULL
) {
699 int cert_id
= CertStore::GetInstance()->StoreCert(ssl_info
.cert
.get(),
701 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids
;
702 StoreSignedCertificateTimestamps(ssl_info
.signed_certificate_timestamps
,
704 &signed_certificate_timestamp_ids
);
706 security_info
= SerializeSecurityInfo(
707 cert_id
, ssl_info
.cert_status
, ssl_info
.security_bits
,
708 ssl_info
.connection_status
, signed_certificate_timestamp_ids
);
713 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
714 tracked_objects::ScopedTracker
tracking_profile(
715 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
717 handler_
->OnResponseCompleted(request_
->status(), security_info
, &defer
);
720 // The handler is not ready to die yet. We will call DidFinishLoading when
722 deferred_stage_
= DEFERRED_FINISH
;
724 // This will result in our destruction.
725 CallDidFinishLoading();
729 void ResourceLoader::CallDidFinishLoading() {
730 delegate_
->DidFinishLoading(this);
733 void ResourceLoader::RecordHistograms() {
734 ResourceRequestInfoImpl
* info
= GetRequestInfo();
736 if (info
->GetResourceType() == RESOURCE_TYPE_PREFETCH
) {
737 PrefetchStatus status
= STATUS_UNDEFINED
;
738 TimeDelta total_time
= base::TimeTicks::Now() - request_
->creation_time();
740 switch (request_
->status().status()) {
741 case net::URLRequestStatus::SUCCESS
:
742 if (request_
->was_cached()) {
743 status
= STATUS_SUCCESS_FROM_CACHE
;
744 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
747 status
= STATUS_SUCCESS_FROM_NETWORK
;
748 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
752 case net::URLRequestStatus::CANCELED
:
753 status
= STATUS_CANCELED
;
754 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time
);
756 case net::URLRequestStatus::IO_PENDING
:
757 case net::URLRequestStatus::FAILED
:
758 status
= STATUS_UNDEFINED
;
762 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status
, STATUS_MAX
);
766 } // namespace content