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