chrome/browser/extensions: Remove use of MessageLoopProxy and deprecated MessageLoop...
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blobba39867c8a0bed96cee52ba61269d8c5170836c9
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/loader/resource_loader.h"
7 #include "base/command_line.h"
8 #include "base/location.h"
9 #include "base/metrics/histogram.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "content/browser/appcache/appcache_interceptor.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/loader/cross_site_resource_handler.h"
17 #include "content/browser/loader/detachable_resource_handler.h"
18 #include "content/browser/loader/resource_loader_delegate.h"
19 #include "content/browser/loader/resource_request_info_impl.h"
20 #include "content/browser/service_worker/service_worker_request_handler.h"
21 #include "content/browser/ssl/ssl_client_auth_handler.h"
22 #include "content/browser/ssl/ssl_manager.h"
23 #include "content/common/ssl_status_serialization.h"
24 #include "content/public/browser/cert_store.h"
25 #include "content/public/browser/resource_context.h"
26 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
27 #include "content/public/browser/signed_certificate_timestamp_store.h"
28 #include "content/public/common/content_client.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/process_type.h"
31 #include "content/public/common/resource_response.h"
32 #include "net/base/io_buffer.h"
33 #include "net/base/load_flags.h"
34 #include "net/http/http_response_headers.h"
35 #include "net/ssl/client_cert_store.h"
36 #include "net/url_request/redirect_info.h"
37 #include "net/url_request/url_request_status.h"
39 using base::TimeDelta;
40 using base::TimeTicks;
42 namespace content {
43 namespace {
45 // The interval for calls to ResourceLoader::ReportUploadProgress.
46 const int kUploadProgressIntervalMsec = 100;
48 void PopulateResourceResponse(ResourceRequestInfoImpl* info,
49 net::URLRequest* request,
50 ResourceResponse* response) {
51 response->head.request_time = request->request_time();
52 response->head.response_time = request->response_time();
53 response->head.headers = request->response_headers();
54 request->GetCharset(&response->head.charset);
55 response->head.content_length = request->GetExpectedContentSize();
56 request->GetMimeType(&response->head.mime_type);
57 net::HttpResponseInfo response_info = request->response_info();
58 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
59 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
60 response->head.npn_negotiated_protocol =
61 response_info.npn_negotiated_protocol;
62 response->head.connection_info = response_info.connection_info;
63 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
64 response->head.proxy_server = response_info.proxy_server;
65 response->head.socket_address = request->GetSocketAddress();
66 if (ServiceWorkerRequestHandler* handler =
67 ServiceWorkerRequestHandler::GetHandler(request)) {
68 handler->GetExtraResponseInfo(&response->head);
70 AppCacheInterceptor::GetExtraResponseInfo(
71 request,
72 &response->head.appcache_id,
73 &response->head.appcache_manifest_url);
74 if (info->is_load_timing_enabled())
75 request->GetLoadTimingInfo(&response->head.load_timing);
78 } // namespace
80 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
81 scoped_ptr<ResourceHandler> handler,
82 ResourceLoaderDelegate* delegate)
83 : deferred_stage_(DEFERRED_NONE),
84 request_(request.Pass()),
85 handler_(handler.Pass()),
86 delegate_(delegate),
87 last_upload_position_(0),
88 waiting_for_upload_progress_ack_(false),
89 is_transferring_(false),
90 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.
102 handler_.reset();
105 void ResourceLoader::StartRequest() {
106 if (delegate_->HandleExternalProtocol(this, request_->url())) {
107 CancelAndIgnore();
108 return;
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)) {
114 Cancel();
115 return;
118 if (defer_start) {
119 deferred_stage_ = DEFERRED_START;
120 } else {
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());
180 if (handler)
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());
201 if (handler)
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,
222 bool* defer) {
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.
237 Cancel();
238 return;
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.
245 CancelAndIgnore();
246 return;
249 scoped_refptr<ResourceResponse> response(new ResourceResponse());
250 PopulateResourceResponse(info, request_.get(), response.get());
251 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
252 Cancel();
253 } else if (*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();
265 return;
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) {
284 request_->Cancel();
285 return;
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(),
292 cert_info, this));
293 ssl_client_auth_handler_->SelectCertificate();
296 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
297 const net::SSLInfo& ssl_info,
298 bool fatal) {
299 ResourceRequestInfoImpl* info = GetRequestInfo();
301 int render_process_id;
302 int render_frame_id;
303 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
304 NOTREACHED();
306 SSLManager::OnSSLCertificateError(
307 weak_ptr_factory_.GetWeakPtr(),
308 info->GetResourceType(),
309 request_->url(),
310 render_process_id,
311 render_frame_id,
312 ssl_info,
313 fatal);
316 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
317 bool* defer) {
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)) {
322 Cancel();
323 return;
324 } else if (*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
338 // renderer process.
339 ResourceRequestInfoImpl* info = GetRequestInfo();
340 ChildProcessSecurityPolicyImpl* policy =
341 ChildProcessSecurityPolicyImpl::GetInstance();
342 if (!policy->CanLoadPage(info->GetChildID(),
343 request_->url(),
344 info->GetResourceType())) {
345 Cancel();
346 return;
349 if (!request_->status().is_success()) {
350 ResponseCompleted();
351 return;
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();
364 if (is_deferred())
365 return;
367 if (request_->status().is_success())
368 StartReading(false); // Read the first chunk.
369 else
370 ResponseCompleted();
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()) {
380 ResponseCompleted();
381 return;
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())
394 return;
396 if (bytes_read > 0) {
397 StartReading(true); // Read the next chunk.
398 } else {
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);
405 ResponseCompleted();
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())
416 return;
417 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
419 if (ssl_info) {
420 request_->CancelWithSSLError(error, *ssl_info);
421 } else {
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;
451 switch (stage) {
452 case DEFERRED_NONE:
453 NOTREACHED();
454 break;
455 case DEFERRED_START:
456 StartRequestInternal();
457 break;
458 case DEFERRED_NETWORK_START:
459 request_->ResumeNetworkStart();
460 break;
461 case DEFERRED_REDIRECT:
462 request_->FollowDeferredRedirect();
463 break;
464 case DEFERRED_READ:
465 base::ThreadTaskRunnerHandle::Get()->PostTask(
466 FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
467 weak_ptr_factory_.GetWeakPtr()));
468 break;
469 case DEFERRED_RESPONSE_COMPLETE:
470 base::ThreadTaskRunnerHandle::Get()->PostTask(
471 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
472 weak_ptr_factory_.GetWeakPtr()));
473 break;
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()));
479 break;
483 void ResourceLoader::Cancel() {
484 CancelRequest(false);
487 void ResourceLoader::StartRequestInternal() {
488 DCHECK(!request_->is_pending());
490 if (!request_->status().is_success()) {
491 return;
494 request_->Start();
496 delegate_->DidStartRequest(this);
498 if (GetRequestInfo()->is_upload_progress_enabled() &&
499 request_->has_upload()) {
500 progress_timer_.Start(
501 FROM_HERE,
502 base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec),
503 this,
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
515 // browser.
516 if (from_renderer && (info->IsDownload() || info->is_stream()))
517 return;
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();
523 return;
526 // TODO(darin): Perhaps we should really be looking to see if the status is
527 // IO_PENDING?
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);
538 if (!was_pending) {
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
541 // this request.
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,
550 int process_id,
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));
558 sct_ids->push_back(
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,
575 info->GetChildID(),
576 &signed_certificate_timestamp_ids);
578 response->head.security_info = SerializeSecurityInfo(
579 cert_id,
580 request_->ssl_info().cert_status,
581 request_->ssl_info().security_bits,
582 request_->ssl_info().connection_status,
583 signed_certificate_timestamp_ids);
584 } else {
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()"));
597 bool defer = false;
598 if (!handler_->OnResponseStarted(response.get(), &defer)) {
599 Cancel();
600 } else if (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) {
607 int bytes_read = 0;
608 ReadMore(&bytes_read);
610 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
611 if (request_->status().is_io_pending())
612 return;
614 if (!is_continuation || bytes_read <= 0) {
615 OnReadCompleted(request_.get(), bytes_read);
616 } else {
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(
620 FROM_HERE,
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).
636 } else {
637 ResponseCompleted();
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;
648 int buf_size;
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)) {
655 Cancel();
656 return;
660 DCHECK(buf.get());
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()"));
677 bool defer = false;
678 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
679 Cancel();
680 } else if (defer) {
681 deferred_stage_ =
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
688 // instance.)
691 void ResourceLoader::ResponseCompleted() {
692 VLOG(1) << "ResponseCompleted: " << request_->url().spec();
693 RecordHistograms();
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(),
700 info->GetChildID());
701 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
702 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
703 info->GetChildID(),
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);
711 bool defer = false;
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);
719 if (defer) {
720 // The handler is not ready to die yet. We will call DidFinishLoading when
721 // we resume.
722 deferred_stage_ = DEFERRED_FINISH;
723 } else {
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",
745 total_time);
746 } else {
747 status = STATUS_SUCCESS_FROM_NETWORK;
748 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
749 total_time);
751 break;
752 case net::URLRequestStatus::CANCELED:
753 status = STATUS_CANCELED;
754 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
755 break;
756 case net::URLRequestStatus::IO_PENDING:
757 case net::URLRequestStatus::FAILED:
758 status = STATUS_UNDEFINED;
759 break;
762 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
766 } // namespace content