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.
4
5 #include "content/browser/loader/resource_loader.h"
6
7 #include "base/command_line.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/time/time.h"
11 #include "content/browser/child_process_security_policy_impl.h"
12 #include "content/browser/loader/cross_site_resource_handler.h"
13 #include "content/browser/loader/detachable_resource_handler.h"
14 #include "content/browser/loader/resource_loader_delegate.h"
15 #include "content/browser/loader/resource_request_info_impl.h"
16 #include "content/browser/ssl/ssl_client_auth_handler.h"
17 #include "content/browser/ssl/ssl_manager.h"
18 #include "content/common/ssl_status_serialization.h"
19 #include "content/public/browser/cert_store.h"
20 #include "content/public/browser/resource_context.h"
21 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
22 #include "content/public/browser/signed_certificate_timestamp_store.h"
23 #include "content/public/common/content_client.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/public/common/process_type.h"
26 #include "content/public/common/resource_response.h"
27 #include "net/base/io_buffer.h"
28 #include "net/base/load_flags.h"
29 #include "net/http/http_response_headers.h"
30 #include "net/ssl/client_cert_store.h"
31 #include "net/url_request/url_request_status.h"
32 #include "webkit/browser/appcache/appcache_interceptor.h"
33
34 using base::TimeDelta;
35 using base::TimeTicks;
36
37 namespace content {
38 namespace {
39
PopulateResourceResponse(net::URLRequest * request,ResourceResponse * response)40 void PopulateResourceResponse(net::URLRequest* request,
41 ResourceResponse* response) {
42 response->head.error_code = request->status().error();
43 response->head.request_time = request->request_time();
44 response->head.response_time = request->response_time();
45 response->head.headers = request->response_headers();
46 request->GetCharset(&response->head.charset);
47 response->head.content_length = request->GetExpectedContentSize();
48 request->GetMimeType(&response->head.mime_type);
49 net::HttpResponseInfo response_info = request->response_info();
50 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
51 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
52 response->head.npn_negotiated_protocol =
53 response_info.npn_negotiated_protocol;
54 response->head.connection_info = response_info.connection_info;
55 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
56 response->head.socket_address = request->GetSocketAddress();
57 appcache::AppCacheInterceptor::GetExtraResponseInfo(
58 request,
59 &response->head.appcache_id,
60 &response->head.appcache_manifest_url);
61 // TODO(mmenke): Figure out if LOAD_ENABLE_LOAD_TIMING is safe to remove.
62 if (request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)
63 request->GetLoadTimingInfo(&response->head.load_timing);
64 }
65
66 } // namespace
67
ResourceLoader(scoped_ptr<net::URLRequest> request,scoped_ptr<ResourceHandler> handler,ResourceLoaderDelegate * delegate)68 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
69 scoped_ptr<ResourceHandler> handler,
70 ResourceLoaderDelegate* delegate)
71 : deferred_stage_(DEFERRED_NONE),
72 request_(request.Pass()),
73 handler_(handler.Pass()),
74 delegate_(delegate),
75 last_upload_position_(0),
76 waiting_for_upload_progress_ack_(false),
77 is_transferring_(false),
78 weak_ptr_factory_(this) {
79 request_->set_delegate(this);
80 handler_->SetController(this);
81 }
82
~ResourceLoader()83 ResourceLoader::~ResourceLoader() {
84 if (login_delegate_.get())
85 login_delegate_->OnRequestCancelled();
86 if (ssl_client_auth_handler_.get())
87 ssl_client_auth_handler_->OnRequestCancelled();
88
89 // Run ResourceHandler destructor before we tear-down the rest of our state
90 // as the ResourceHandler may want to inspect the URLRequest and other state.
91 handler_.reset();
92 }
93
StartRequest()94 void ResourceLoader::StartRequest() {
95 if (delegate_->HandleExternalProtocol(this, request_->url())) {
96 CancelAndIgnore();
97 return;
98 }
99
100 // Give the handler a chance to delay the URLRequest from being started.
101 bool defer_start = false;
102 if (!handler_->OnWillStart(GetRequestInfo()->GetRequestID(), request_->url(),
103 &defer_start)) {
104 Cancel();
105 return;
106 }
107
108 if (defer_start) {
109 deferred_stage_ = DEFERRED_START;
110 } else {
111 StartRequestInternal();
112 }
113 }
114
CancelRequest(bool from_renderer)115 void ResourceLoader::CancelRequest(bool from_renderer) {
116 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
117 }
118
CancelAndIgnore()119 void ResourceLoader::CancelAndIgnore() {
120 ResourceRequestInfoImpl* info = GetRequestInfo();
121 info->set_was_ignored_by_handler(true);
122 CancelRequest(false);
123 }
124
CancelWithError(int error_code)125 void ResourceLoader::CancelWithError(int error_code) {
126 CancelRequestInternal(error_code, false);
127 }
128
ReportUploadProgress()129 void ResourceLoader::ReportUploadProgress() {
130 ResourceRequestInfoImpl* info = GetRequestInfo();
131
132 if (waiting_for_upload_progress_ack_)
133 return; // Send one progress event at a time.
134
135 net::UploadProgress progress = request_->GetUploadProgress();
136 if (!progress.size())
137 return; // Nothing to upload.
138
139 if (progress.position() == last_upload_position_)
140 return; // No progress made since last time.
141
142 const uint64 kHalfPercentIncrements = 200;
143 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
144
145 uint64 amt_since_last = progress.position() - last_upload_position_;
146 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
147
148 bool is_finished = (progress.size() == progress.position());
149 bool enough_new_progress =
150 (amt_since_last > (progress.size() / kHalfPercentIncrements));
151 bool too_much_time_passed = time_since_last > kOneSecond;
152
153 if (is_finished || enough_new_progress || too_much_time_passed) {
154 if (request_->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
155 handler_->OnUploadProgress(
156 info->GetRequestID(), progress.position(), progress.size());
157 waiting_for_upload_progress_ack_ = true;
158 }
159 last_upload_ticks_ = TimeTicks::Now();
160 last_upload_position_ = progress.position();
161 }
162 }
163
MarkAsTransferring(const GURL & target_url)164 void ResourceLoader::MarkAsTransferring(const GURL& target_url) {
165 CHECK_EQ(GetRequestInfo()->GetResourceType(), ResourceType::MAIN_FRAME)
166 << "Cannot transfer non-main frame navigations";
167 is_transferring_ = true;
168
169 // When transferring a request to another process, the renderer doesn't get
170 // a chance to update the cookie policy URL. Do it here instead.
171 request()->set_first_party_for_cookies(target_url);
172 }
173
CompleteTransfer()174 void ResourceLoader::CompleteTransfer() {
175 DCHECK_EQ(DEFERRED_READ, deferred_stage_);
176
177 is_transferring_ = false;
178 GetRequestInfo()->cross_site_handler()->ResumeResponse();
179 }
180
GetRequestInfo()181 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
182 return ResourceRequestInfoImpl::ForRequest(request_.get());
183 }
184
ClearLoginDelegate()185 void ResourceLoader::ClearLoginDelegate() {
186 login_delegate_ = NULL;
187 }
188
ClearSSLClientAuthHandler()189 void ResourceLoader::ClearSSLClientAuthHandler() {
190 ssl_client_auth_handler_ = NULL;
191 }
192
OnUploadProgressACK()193 void ResourceLoader::OnUploadProgressACK() {
194 waiting_for_upload_progress_ack_ = false;
195 }
196
OnReceivedRedirect(net::URLRequest * unused,const GURL & new_url,bool * defer)197 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
198 const GURL& new_url,
199 bool* defer) {
200 DCHECK_EQ(request_.get(), unused);
201
202 VLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
203 DCHECK(request_->status().is_success());
204
205 ResourceRequestInfoImpl* info = GetRequestInfo();
206
207 if (info->process_type() != PROCESS_TYPE_PLUGIN &&
208 !ChildProcessSecurityPolicyImpl::GetInstance()->
209 CanRequestURL(info->GetChildID(), new_url)) {
210 VLOG(1) << "Denied unauthorized request for "
211 << new_url.possibly_invalid_spec();
212
213 // Tell the renderer that this request was disallowed.
214 Cancel();
215 return;
216 }
217
218 delegate_->DidReceiveRedirect(this, new_url);
219
220 if (delegate_->HandleExternalProtocol(this, new_url)) {
221 // The request is complete so we can remove it.
222 CancelAndIgnore();
223 return;
224 }
225
226 scoped_refptr<ResourceResponse> response(new ResourceResponse());
227 PopulateResourceResponse(request_.get(), response.get());
228
229 if (!handler_->OnRequestRedirected(
230 info->GetRequestID(), new_url, response.get(), defer)) {
231 Cancel();
232 } else if (*defer) {
233 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
234 }
235 }
236
OnAuthRequired(net::URLRequest * unused,net::AuthChallengeInfo * auth_info)237 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
238 net::AuthChallengeInfo* auth_info) {
239 DCHECK_EQ(request_.get(), unused);
240
241 if (request_->load_flags() & net::LOAD_DO_NOT_PROMPT_FOR_LOGIN) {
242 request_->CancelAuth();
243 return;
244 }
245
246 if (!delegate_->AcceptAuthRequest(this, auth_info)) {
247 request_->CancelAuth();
248 return;
249 }
250
251 // Create a login dialog on the UI thread to get authentication data, or pull
252 // from cache and continue on the IO thread.
253
254 DCHECK(!login_delegate_.get())
255 << "OnAuthRequired called with login_delegate pending";
256 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
257 if (!login_delegate_.get())
258 request_->CancelAuth();
259 }
260
OnCertificateRequested(net::URLRequest * unused,net::SSLCertRequestInfo * cert_info)261 void ResourceLoader::OnCertificateRequested(
262 net::URLRequest* unused,
263 net::SSLCertRequestInfo* cert_info) {
264 DCHECK_EQ(request_.get(), unused);
265
266 if (!delegate_->AcceptSSLClientCertificateRequest(this, cert_info)) {
267 request_->Cancel();
268 return;
269 }
270
271 DCHECK(!ssl_client_auth_handler_.get())
272 << "OnCertificateRequested called with ssl_client_auth_handler pending";
273 ssl_client_auth_handler_ = new SSLClientAuthHandler(
274 GetRequestInfo()->GetContext()->CreateClientCertStore(),
275 request_.get(),
276 cert_info);
277 ssl_client_auth_handler_->SelectCertificate();
278 }
279
OnSSLCertificateError(net::URLRequest * request,const net::SSLInfo & ssl_info,bool fatal)280 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
281 const net::SSLInfo& ssl_info,
282 bool fatal) {
283 ResourceRequestInfoImpl* info = GetRequestInfo();
284
285 int render_process_id;
286 int render_view_id;
287 if (!info->GetAssociatedRenderView(&render_process_id, &render_view_id))
288 NOTREACHED();
289
290 SSLManager::OnSSLCertificateError(
291 weak_ptr_factory_.GetWeakPtr(),
292 info->GetGlobalRequestID(),
293 info->GetResourceType(),
294 request_->url(),
295 render_process_id,
296 render_view_id,
297 ssl_info,
298 fatal);
299 }
300
OnResponseStarted(net::URLRequest * unused)301 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
302 DCHECK_EQ(request_.get(), unused);
303
304 VLOG(1) << "OnResponseStarted: " << request_->url().spec();
305
306 // The CanLoadPage check should take place after any server redirects have
307 // finished, at the point in time that we know a page will commit in the
308 // renderer process.
309 ResourceRequestInfoImpl* info = GetRequestInfo();
310 ChildProcessSecurityPolicyImpl* policy =
311 ChildProcessSecurityPolicyImpl::GetInstance();
312 if (!policy->CanLoadPage(info->GetChildID(),
313 request_->url(),
314 info->GetResourceType())) {
315 Cancel();
316 return;
317 }
318
319 if (!request_->status().is_success()) {
320 ResponseCompleted();
321 return;
322 }
323
324 // We want to send a final upload progress message prior to sending the
325 // response complete message even if we're waiting for an ack to to a
326 // previous upload progress message.
327 waiting_for_upload_progress_ack_ = false;
328 ReportUploadProgress();
329
330 CompleteResponseStarted();
331
332 if (is_deferred())
333 return;
334
335 if (request_->status().is_success()) {
336 StartReading(false); // Read the first chunk.
337 } else {
338 ResponseCompleted();
339 }
340 }
341
OnReadCompleted(net::URLRequest * unused,int bytes_read)342 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
343 DCHECK_EQ(request_.get(), unused);
344 VLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
345 << " bytes_read = " << bytes_read;
346
347 // bytes_read == -1 always implies an error.
348 if (bytes_read == -1 || !request_->status().is_success()) {
349 ResponseCompleted();
350 return;
351 }
352
353 CompleteRead(bytes_read);
354
355 if (is_deferred())
356 return;
357
358 if (request_->status().is_success() && bytes_read > 0) {
359 StartReading(true); // Read the next chunk.
360 } else {
361 ResponseCompleted();
362 }
363 }
364
CancelSSLRequest(const GlobalRequestID & id,int error,const net::SSLInfo * ssl_info)365 void ResourceLoader::CancelSSLRequest(const GlobalRequestID& id,
366 int error,
367 const net::SSLInfo* ssl_info) {
368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
369
370 // The request can be NULL if it was cancelled by the renderer (as the
371 // request of the user navigating to a new page from the location bar).
372 if (!request_->is_pending())
373 return;
374 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
375
376 if (ssl_info) {
377 request_->CancelWithSSLError(error, *ssl_info);
378 } else {
379 request_->CancelWithError(error);
380 }
381 }
382
ContinueSSLRequest(const GlobalRequestID & id)383 void ResourceLoader::ContinueSSLRequest(const GlobalRequestID& id) {
384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
385
386 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
387
388 request_->ContinueDespiteLastError();
389 }
390
Resume()391 void ResourceLoader::Resume() {
392 DCHECK(!is_transferring_);
393
394 DeferredStage stage = deferred_stage_;
395 deferred_stage_ = DEFERRED_NONE;
396 switch (stage) {
397 case DEFERRED_NONE:
398 NOTREACHED();
399 break;
400 case DEFERRED_START:
401 StartRequestInternal();
402 break;
403 case DEFERRED_REDIRECT:
404 request_->FollowDeferredRedirect();
405 break;
406 case DEFERRED_READ:
407 base::MessageLoop::current()->PostTask(
408 FROM_HERE,
409 base::Bind(&ResourceLoader::ResumeReading,
410 weak_ptr_factory_.GetWeakPtr()));
411 break;
412 case DEFERRED_FINISH:
413 // Delay self-destruction since we don't know how we were reached.
414 base::MessageLoop::current()->PostTask(
415 FROM_HERE,
416 base::Bind(&ResourceLoader::CallDidFinishLoading,
417 weak_ptr_factory_.GetWeakPtr()));
418 break;
419 }
420 }
421
Cancel()422 void ResourceLoader::Cancel() {
423 CancelRequest(false);
424 }
425
StartRequestInternal()426 void ResourceLoader::StartRequestInternal() {
427 DCHECK(!request_->is_pending());
428 request_->Start();
429
430 delegate_->DidStartRequest(this);
431 }
432
CancelRequestInternal(int error,bool from_renderer)433 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
434 VLOG(1) << "CancelRequestInternal: " << request_->url().spec();
435
436 ResourceRequestInfoImpl* info = GetRequestInfo();
437
438 // WebKit will send us a cancel for downloads since it no longer handles
439 // them. In this case, ignore the cancel since we handle downloads in the
440 // browser.
441 if (from_renderer && (info->IsDownload() || info->is_stream()))
442 return;
443
444 if (from_renderer && info->detachable_handler()) {
445 // TODO(davidben): Fix Blink handling of prefetches so they are not
446 // cancelled on navigate away and end up in the local cache.
447 info->detachable_handler()->Detach();
448 return;
449 }
450
451 // TODO(darin): Perhaps we should really be looking to see if the status is
452 // IO_PENDING?
453 bool was_pending = request_->is_pending();
454
455 if (login_delegate_.get()) {
456 login_delegate_->OnRequestCancelled();
457 login_delegate_ = NULL;
458 }
459 if (ssl_client_auth_handler_.get()) {
460 ssl_client_auth_handler_->OnRequestCancelled();
461 ssl_client_auth_handler_ = NULL;
462 }
463
464 request_->CancelWithError(error);
465
466 if (!was_pending) {
467 // If the request isn't in flight, then we won't get an asynchronous
468 // notification from the request, so we have to signal ourselves to finish
469 // this request.
470 base::MessageLoop::current()->PostTask(
471 FROM_HERE,
472 base::Bind(&ResourceLoader::ResponseCompleted,
473 weak_ptr_factory_.GetWeakPtr()));
474 }
475 }
476
StoreSignedCertificateTimestamps(const net::SignedCertificateTimestampAndStatusList & sct_list,int process_id,SignedCertificateTimestampIDStatusList * sct_ids)477 void ResourceLoader::StoreSignedCertificateTimestamps(
478 const net::SignedCertificateTimestampAndStatusList& sct_list,
479 int process_id,
480 SignedCertificateTimestampIDStatusList* sct_ids) {
481 SignedCertificateTimestampStore* sct_store(
482 SignedCertificateTimestampStore::GetInstance());
483
484 for (net::SignedCertificateTimestampAndStatusList::const_iterator iter =
485 sct_list.begin(); iter != sct_list.end(); ++iter) {
486 const int sct_id(sct_store->Store(iter->sct_, process_id));
487 sct_ids->push_back(
488 SignedCertificateTimestampIDAndStatus(sct_id, iter->status_));
489 }
490 }
491
CompleteResponseStarted()492 void ResourceLoader::CompleteResponseStarted() {
493 ResourceRequestInfoImpl* info = GetRequestInfo();
494
495 scoped_refptr<ResourceResponse> response(new ResourceResponse());
496 PopulateResourceResponse(request_.get(), response.get());
497
498 if (request_->ssl_info().cert.get()) {
499 int cert_id = CertStore::GetInstance()->StoreCert(
500 request_->ssl_info().cert.get(), info->GetChildID());
501
502 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
503 StoreSignedCertificateTimestamps(
504 request_->ssl_info().signed_certificate_timestamps,
505 info->GetChildID(),
506 &signed_certificate_timestamp_ids);
507
508 response->head.security_info = SerializeSecurityInfo(
509 cert_id,
510 request_->ssl_info().cert_status,
511 request_->ssl_info().security_bits,
512 request_->ssl_info().connection_status,
513 signed_certificate_timestamp_ids);
514 } else {
515 // We should not have any SSL state.
516 DCHECK(!request_->ssl_info().cert_status &&
517 request_->ssl_info().security_bits == -1 &&
518 !request_->ssl_info().connection_status);
519 }
520
521 delegate_->DidReceiveResponse(this);
522
523 bool defer = false;
524 if (!handler_->OnResponseStarted(
525 info->GetRequestID(), response.get(), &defer)) {
526 Cancel();
527 } else if (defer) {
528 read_deferral_start_time_ = base::TimeTicks::Now();
529 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
530 }
531 }
532
StartReading(bool is_continuation)533 void ResourceLoader::StartReading(bool is_continuation) {
534 int bytes_read = 0;
535 ReadMore(&bytes_read);
536
537 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
538 if (request_->status().is_io_pending())
539 return;
540
541 if (!is_continuation || bytes_read <= 0) {
542 OnReadCompleted(request_.get(), bytes_read);
543 } else {
544 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
545 // thread in case the URLRequest can provide data synchronously.
546 base::MessageLoop::current()->PostTask(
547 FROM_HERE,
548 base::Bind(&ResourceLoader::OnReadCompleted,
549 weak_ptr_factory_.GetWeakPtr(),
550 request_.get(),
551 bytes_read));
552 }
553 }
554
ResumeReading()555 void ResourceLoader::ResumeReading() {
556 DCHECK(!is_deferred());
557
558 if (!read_deferral_start_time_.is_null()) {
559 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
560 base::TimeTicks::Now() - read_deferral_start_time_);
561 read_deferral_start_time_ = base::TimeTicks();
562 }
563 if (request_->status().is_success()) {
564 StartReading(false); // Read the next chunk (OK to complete synchronously).
565 } else {
566 ResponseCompleted();
567 }
568 }
569
ReadMore(int * bytes_read)570 void ResourceLoader::ReadMore(int* bytes_read) {
571 ResourceRequestInfoImpl* info = GetRequestInfo();
572 DCHECK(!is_deferred());
573
574 // Make sure we track the buffer in at least one place. This ensures it gets
575 // deleted even in the case the request has already finished its job and
576 // doesn't use the buffer.
577 scoped_refptr<net::IOBuffer> buf;
578 int buf_size;
579 if (!handler_->OnWillRead(info->GetRequestID(), &buf, &buf_size, -1)) {
580 Cancel();
581 return;
582 }
583
584 DCHECK(buf);
585 DCHECK(buf_size > 0);
586
587 request_->Read(buf.get(), buf_size, bytes_read);
588
589 // No need to check the return value here as we'll detect errors by
590 // inspecting the URLRequest's status.
591 }
592
CompleteRead(int bytes_read)593 void ResourceLoader::CompleteRead(int bytes_read) {
594 DCHECK(bytes_read >= 0);
595 DCHECK(request_->status().is_success());
596
597 ResourceRequestInfoImpl* info = GetRequestInfo();
598
599 bool defer = false;
600 if (!handler_->OnReadCompleted(info->GetRequestID(), bytes_read, &defer)) {
601 Cancel();
602 } else if (defer) {
603 deferred_stage_ = DEFERRED_READ; // Read next chunk when resumed.
604 }
605 }
606
ResponseCompleted()607 void ResourceLoader::ResponseCompleted() {
608 VLOG(1) << "ResponseCompleted: " << request_->url().spec();
609 RecordHistograms();
610 ResourceRequestInfoImpl* info = GetRequestInfo();
611
612 std::string security_info;
613 const net::SSLInfo& ssl_info = request_->ssl_info();
614 if (ssl_info.cert.get() != NULL) {
615 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert.get(),
616 info->GetChildID());
617 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
618 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
619 info->GetChildID(),
620 &signed_certificate_timestamp_ids);
621
622 security_info = SerializeSecurityInfo(
623 cert_id, ssl_info.cert_status, ssl_info.security_bits,
624 ssl_info.connection_status, signed_certificate_timestamp_ids);
625 }
626
627 bool defer = false;
628 handler_->OnResponseCompleted(info->GetRequestID(), request_->status(),
629 security_info, &defer);
630 if (defer) {
631 // The handler is not ready to die yet. We will call DidFinishLoading when
632 // we resume.
633 deferred_stage_ = DEFERRED_FINISH;
634 } else {
635 // This will result in our destruction.
636 CallDidFinishLoading();
637 }
638 }
639
CallDidFinishLoading()640 void ResourceLoader::CallDidFinishLoading() {
641 delegate_->DidFinishLoading(this);
642 }
643
RecordHistograms()644 void ResourceLoader::RecordHistograms() {
645 ResourceRequestInfoImpl* info = GetRequestInfo();
646
647 if (info->GetResourceType() == ResourceType::PREFETCH) {
648 PrefetchStatus status = STATUS_UNDEFINED;
649 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
650
651 switch (request_->status().status()) {
652 case net::URLRequestStatus::SUCCESS:
653 if (request_->was_cached()) {
654 status = STATUS_SUCCESS_FROM_CACHE;
655 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
656 total_time);
657 } else {
658 status = STATUS_SUCCESS_FROM_NETWORK;
659 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
660 total_time);
661 }
662 break;
663 case net::URLRequestStatus::CANCELED:
664 status = STATUS_CANCELED;
665 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
666 break;
667 case net::URLRequestStatus::IO_PENDING:
668 case net::URLRequestStatus::FAILED:
669 status = STATUS_UNDEFINED;
670 break;
671 }
672
673 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
674 }
675 }
676
677 } // namespace content
678