content: Remove use of MessageLoopProxy and deprecated MessageLoop APIs
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blob63b9f9c8439c4129270c25686fcb4f37f46257cb
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(
69 &response->head.was_fetched_via_service_worker,
70 &response->head.was_fallback_required_by_service_worker,
71 &response->head.original_url_via_service_worker,
72 &response->head.response_type_via_service_worker,
73 &response->head.service_worker_start_time);
75 AppCacheInterceptor::GetExtraResponseInfo(
76 request,
77 &response->head.appcache_id,
78 &response->head.appcache_manifest_url);
79 if (info->is_load_timing_enabled())
80 request->GetLoadTimingInfo(&response->head.load_timing);
83 } // namespace
85 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
86 scoped_ptr<ResourceHandler> handler,
87 ResourceLoaderDelegate* delegate)
88 : deferred_stage_(DEFERRED_NONE),
89 request_(request.Pass()),
90 handler_(handler.Pass()),
91 delegate_(delegate),
92 last_upload_position_(0),
93 waiting_for_upload_progress_ack_(false),
94 is_transferring_(false),
95 weak_ptr_factory_(this) {
96 request_->set_delegate(this);
97 handler_->SetController(this);
100 ResourceLoader::~ResourceLoader() {
101 if (login_delegate_.get())
102 login_delegate_->OnRequestCancelled();
103 ssl_client_auth_handler_.reset();
105 // Run ResourceHandler destructor before we tear-down the rest of our state
106 // as the ResourceHandler may want to inspect the URLRequest and other state.
107 handler_.reset();
110 void ResourceLoader::StartRequest() {
111 if (delegate_->HandleExternalProtocol(this, request_->url())) {
112 CancelAndIgnore();
113 return;
116 // Give the handler a chance to delay the URLRequest from being started.
117 bool defer_start = false;
118 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
119 Cancel();
120 return;
123 if (defer_start) {
124 deferred_stage_ = DEFERRED_START;
125 } else {
126 StartRequestInternal();
130 void ResourceLoader::CancelRequest(bool from_renderer) {
131 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
134 void ResourceLoader::CancelAndIgnore() {
135 ResourceRequestInfoImpl* info = GetRequestInfo();
136 info->set_was_ignored_by_handler(true);
137 CancelRequest(false);
140 void ResourceLoader::CancelWithError(int error_code) {
141 CancelRequestInternal(error_code, false);
144 void ResourceLoader::ReportUploadProgress() {
145 DCHECK(GetRequestInfo()->is_upload_progress_enabled());
147 if (waiting_for_upload_progress_ack_)
148 return; // Send one progress event at a time.
150 net::UploadProgress progress = request_->GetUploadProgress();
151 if (!progress.size())
152 return; // Nothing to upload.
154 if (progress.position() == last_upload_position_)
155 return; // No progress made since last time.
157 const uint64 kHalfPercentIncrements = 200;
158 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
160 uint64 amt_since_last = progress.position() - last_upload_position_;
161 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
163 bool is_finished = (progress.size() == progress.position());
164 bool enough_new_progress =
165 (amt_since_last > (progress.size() / kHalfPercentIncrements));
166 bool too_much_time_passed = time_since_last > kOneSecond;
168 if (is_finished || enough_new_progress || too_much_time_passed) {
169 handler_->OnUploadProgress(progress.position(), progress.size());
170 waiting_for_upload_progress_ack_ = true;
171 last_upload_ticks_ = TimeTicks::Now();
172 last_upload_position_ = progress.position();
176 void ResourceLoader::MarkAsTransferring() {
177 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
178 << "Can only transfer for navigations";
179 is_transferring_ = true;
181 int child_id = GetRequestInfo()->GetChildID();
182 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
183 ServiceWorkerRequestHandler* handler =
184 ServiceWorkerRequestHandler::GetHandler(request());
185 if (handler)
186 handler->PrepareForCrossSiteTransfer(child_id);
189 void ResourceLoader::CompleteTransfer() {
190 // Although CrossSiteResourceHandler defers at OnResponseStarted
191 // (DEFERRED_READ), it may be seeing a replay of events via
192 // BufferedResourceHandler, and so the request itself is actually deferred at
193 // a later read stage.
194 DCHECK(DEFERRED_READ == deferred_stage_ ||
195 DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
196 DCHECK(is_transferring_);
198 // In some cases, a process transfer doesn't really happen and the
199 // request is resumed in the original process. Real transfers to a new process
200 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
201 int child_id = GetRequestInfo()->GetChildID();
202 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
203 request(), child_id);
204 ServiceWorkerRequestHandler* handler =
205 ServiceWorkerRequestHandler::GetHandler(request());
206 if (handler)
207 handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
209 is_transferring_ = false;
210 GetRequestInfo()->cross_site_handler()->ResumeResponse();
213 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
214 return ResourceRequestInfoImpl::ForRequest(request_.get());
217 void ResourceLoader::ClearLoginDelegate() {
218 login_delegate_ = NULL;
221 void ResourceLoader::OnUploadProgressACK() {
222 waiting_for_upload_progress_ack_ = false;
225 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
226 const net::RedirectInfo& redirect_info,
227 bool* defer) {
228 DCHECK_EQ(request_.get(), unused);
230 VLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
231 DCHECK(request_->status().is_success());
233 ResourceRequestInfoImpl* info = GetRequestInfo();
235 if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
236 !ChildProcessSecurityPolicyImpl::GetInstance()->
237 CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
238 VLOG(1) << "Denied unauthorized request for "
239 << redirect_info.new_url.possibly_invalid_spec();
241 // Tell the renderer that this request was disallowed.
242 Cancel();
243 return;
246 delegate_->DidReceiveRedirect(this, redirect_info.new_url);
248 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
249 // The request is complete so we can remove it.
250 CancelAndIgnore();
251 return;
254 scoped_refptr<ResourceResponse> response(new ResourceResponse());
255 PopulateResourceResponse(info, request_.get(), response.get());
256 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
257 Cancel();
258 } else if (*defer) {
259 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
263 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
264 net::AuthChallengeInfo* auth_info) {
265 DCHECK_EQ(request_.get(), unused);
267 ResourceRequestInfoImpl* info = GetRequestInfo();
268 if (info->do_not_prompt_for_login()) {
269 request_->CancelAuth();
270 return;
273 // Create a login dialog on the UI thread to get authentication data, or pull
274 // from cache and continue on the IO thread.
276 DCHECK(!login_delegate_.get())
277 << "OnAuthRequired called with login_delegate pending";
278 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
279 if (!login_delegate_.get())
280 request_->CancelAuth();
283 void ResourceLoader::OnCertificateRequested(
284 net::URLRequest* unused,
285 net::SSLCertRequestInfo* cert_info) {
286 DCHECK_EQ(request_.get(), unused);
288 if (request_->load_flags() & net::LOAD_PREFETCH) {
289 request_->Cancel();
290 return;
293 DCHECK(!ssl_client_auth_handler_)
294 << "OnCertificateRequested called with ssl_client_auth_handler pending";
295 ssl_client_auth_handler_.reset(new SSLClientAuthHandler(
296 GetRequestInfo()->GetContext()->CreateClientCertStore(), request_.get(),
297 cert_info, this));
298 ssl_client_auth_handler_->SelectCertificate();
301 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
302 const net::SSLInfo& ssl_info,
303 bool fatal) {
304 ResourceRequestInfoImpl* info = GetRequestInfo();
306 int render_process_id;
307 int render_frame_id;
308 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
309 NOTREACHED();
311 SSLManager::OnSSLCertificateError(
312 weak_ptr_factory_.GetWeakPtr(),
313 info->GetResourceType(),
314 request_->url(),
315 render_process_id,
316 render_frame_id,
317 ssl_info,
318 fatal);
321 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
322 bool* defer) {
323 DCHECK_EQ(request_.get(), unused);
325 // Give the handler a chance to delay the URLRequest from using the network.
326 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
327 Cancel();
328 return;
329 } else if (*defer) {
330 deferred_stage_ = DEFERRED_NETWORK_START;
334 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
335 DCHECK_EQ(request_.get(), unused);
337 VLOG(1) << "OnResponseStarted: " << request_->url().spec();
339 progress_timer_.Stop();
341 // The CanLoadPage check should take place after any server redirects have
342 // finished, at the point in time that we know a page will commit in the
343 // renderer process.
344 ResourceRequestInfoImpl* info = GetRequestInfo();
345 ChildProcessSecurityPolicyImpl* policy =
346 ChildProcessSecurityPolicyImpl::GetInstance();
347 if (!policy->CanLoadPage(info->GetChildID(),
348 request_->url(),
349 info->GetResourceType())) {
350 Cancel();
351 return;
354 if (!request_->status().is_success()) {
355 ResponseCompleted();
356 return;
359 // We want to send a final upload progress message prior to sending the
360 // response complete message even if we're waiting for an ack to to a
361 // previous upload progress message.
362 if (info->is_upload_progress_enabled()) {
363 waiting_for_upload_progress_ack_ = false;
364 ReportUploadProgress();
367 CompleteResponseStarted();
369 if (is_deferred())
370 return;
372 if (request_->status().is_success())
373 StartReading(false); // Read the first chunk.
374 else
375 ResponseCompleted();
378 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
379 DCHECK_EQ(request_.get(), unused);
380 VLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
381 << " bytes_read = " << bytes_read;
383 // bytes_read == -1 always implies an error.
384 if (bytes_read == -1 || !request_->status().is_success()) {
385 ResponseCompleted();
386 return;
389 CompleteRead(bytes_read);
391 // If the handler cancelled or deferred the request, do not continue
392 // processing the read. If cancelled, the URLRequest has already been
393 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
394 // do nothing until resumed.
396 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
397 // ResponseCompleted().
398 if (is_deferred() || !request_->status().is_success())
399 return;
401 if (bytes_read > 0) {
402 StartReading(true); // Read the next chunk.
403 } else {
404 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
405 tracked_objects::ScopedTracker tracking_profile(
406 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
408 // URLRequest reported an EOF. Call ResponseCompleted.
409 DCHECK_EQ(0, bytes_read);
410 ResponseCompleted();
414 void ResourceLoader::CancelSSLRequest(int error,
415 const net::SSLInfo* ssl_info) {
416 DCHECK_CURRENTLY_ON(BrowserThread::IO);
418 // The request can be NULL if it was cancelled by the renderer (as the
419 // request of the user navigating to a new page from the location bar).
420 if (!request_->is_pending())
421 return;
422 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
424 if (ssl_info) {
425 request_->CancelWithSSLError(error, *ssl_info);
426 } else {
427 request_->CancelWithError(error);
431 void ResourceLoader::ContinueSSLRequest() {
432 DCHECK_CURRENTLY_ON(BrowserThread::IO);
434 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
436 request_->ContinueDespiteLastError();
439 void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
440 DCHECK(ssl_client_auth_handler_);
441 ssl_client_auth_handler_.reset();
442 request_->ContinueWithCertificate(cert);
445 void ResourceLoader::CancelCertificateSelection() {
446 DCHECK(ssl_client_auth_handler_);
447 ssl_client_auth_handler_.reset();
448 request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
451 void ResourceLoader::Resume() {
452 DCHECK(!is_transferring_);
454 DeferredStage stage = deferred_stage_;
455 deferred_stage_ = DEFERRED_NONE;
456 switch (stage) {
457 case DEFERRED_NONE:
458 NOTREACHED();
459 break;
460 case DEFERRED_START:
461 StartRequestInternal();
462 break;
463 case DEFERRED_NETWORK_START:
464 request_->ResumeNetworkStart();
465 break;
466 case DEFERRED_REDIRECT:
467 request_->FollowDeferredRedirect();
468 break;
469 case DEFERRED_READ:
470 base::ThreadTaskRunnerHandle::Get()->PostTask(
471 FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
472 weak_ptr_factory_.GetWeakPtr()));
473 break;
474 case DEFERRED_RESPONSE_COMPLETE:
475 base::ThreadTaskRunnerHandle::Get()->PostTask(
476 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
477 weak_ptr_factory_.GetWeakPtr()));
478 break;
479 case DEFERRED_FINISH:
480 // Delay self-destruction since we don't know how we were reached.
481 base::ThreadTaskRunnerHandle::Get()->PostTask(
482 FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
483 weak_ptr_factory_.GetWeakPtr()));
484 break;
488 void ResourceLoader::Cancel() {
489 CancelRequest(false);
492 void ResourceLoader::StartRequestInternal() {
493 DCHECK(!request_->is_pending());
495 if (!request_->status().is_success()) {
496 return;
499 request_->Start();
501 delegate_->DidStartRequest(this);
503 if (GetRequestInfo()->is_upload_progress_enabled() &&
504 request_->has_upload()) {
505 progress_timer_.Start(
506 FROM_HERE,
507 base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec),
508 this,
509 &ResourceLoader::ReportUploadProgress);
513 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
514 VLOG(1) << "CancelRequestInternal: " << request_->url().spec();
516 ResourceRequestInfoImpl* info = GetRequestInfo();
518 // WebKit will send us a cancel for downloads since it no longer handles
519 // them. In this case, ignore the cancel since we handle downloads in the
520 // browser.
521 if (from_renderer && (info->IsDownload() || info->is_stream()))
522 return;
524 if (from_renderer && info->detachable_handler()) {
525 // TODO(davidben): Fix Blink handling of prefetches so they are not
526 // cancelled on navigate away and end up in the local cache.
527 info->detachable_handler()->Detach();
528 return;
531 // TODO(darin): Perhaps we should really be looking to see if the status is
532 // IO_PENDING?
533 bool was_pending = request_->is_pending();
535 if (login_delegate_.get()) {
536 login_delegate_->OnRequestCancelled();
537 login_delegate_ = NULL;
539 ssl_client_auth_handler_.reset();
541 request_->CancelWithError(error);
543 if (!was_pending) {
544 // If the request isn't in flight, then we won't get an asynchronous
545 // notification from the request, so we have to signal ourselves to finish
546 // this request.
547 base::ThreadTaskRunnerHandle::Get()->PostTask(
548 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
549 weak_ptr_factory_.GetWeakPtr()));
553 void ResourceLoader::StoreSignedCertificateTimestamps(
554 const net::SignedCertificateTimestampAndStatusList& sct_list,
555 int process_id,
556 SignedCertificateTimestampIDStatusList* sct_ids) {
557 SignedCertificateTimestampStore* sct_store(
558 SignedCertificateTimestampStore::GetInstance());
560 for (net::SignedCertificateTimestampAndStatusList::const_iterator iter =
561 sct_list.begin(); iter != sct_list.end(); ++iter) {
562 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
563 sct_ids->push_back(
564 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
568 void ResourceLoader::CompleteResponseStarted() {
569 ResourceRequestInfoImpl* info = GetRequestInfo();
570 scoped_refptr<ResourceResponse> response(new ResourceResponse());
571 PopulateResourceResponse(info, request_.get(), response.get());
573 if (request_->ssl_info().cert.get()) {
574 int cert_id = CertStore::GetInstance()->StoreCert(
575 request_->ssl_info().cert.get(), info->GetChildID());
577 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
578 StoreSignedCertificateTimestamps(
579 request_->ssl_info().signed_certificate_timestamps,
580 info->GetChildID(),
581 &signed_certificate_timestamp_ids);
583 response->head.security_info = SerializeSecurityInfo(
584 cert_id,
585 request_->ssl_info().cert_status,
586 request_->ssl_info().security_bits,
587 request_->ssl_info().connection_status,
588 signed_certificate_timestamp_ids);
589 } else {
590 // We should not have any SSL state.
591 DCHECK(!request_->ssl_info().cert_status &&
592 request_->ssl_info().security_bits == -1 &&
593 !request_->ssl_info().connection_status);
596 delegate_->DidReceiveResponse(this);
598 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
599 tracked_objects::ScopedTracker tracking_profile(
600 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
602 bool defer = false;
603 if (!handler_->OnResponseStarted(response.get(), &defer)) {
604 Cancel();
605 } else if (defer) {
606 read_deferral_start_time_ = base::TimeTicks::Now();
607 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
611 void ResourceLoader::StartReading(bool is_continuation) {
612 int bytes_read = 0;
613 ReadMore(&bytes_read);
615 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
616 if (request_->status().is_io_pending())
617 return;
619 if (!is_continuation || bytes_read <= 0) {
620 OnReadCompleted(request_.get(), bytes_read);
621 } else {
622 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
623 // thread in case the URLRequest can provide data synchronously.
624 base::ThreadTaskRunnerHandle::Get()->PostTask(
625 FROM_HERE,
626 base::Bind(&ResourceLoader::OnReadCompleted,
627 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
631 void ResourceLoader::ResumeReading() {
632 DCHECK(!is_deferred());
634 if (!read_deferral_start_time_.is_null()) {
635 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
636 base::TimeTicks::Now() - read_deferral_start_time_);
637 read_deferral_start_time_ = base::TimeTicks();
639 if (request_->status().is_success()) {
640 StartReading(false); // Read the next chunk (OK to complete synchronously).
641 } else {
642 ResponseCompleted();
646 void ResourceLoader::ReadMore(int* bytes_read) {
647 DCHECK(!is_deferred());
649 // Make sure we track the buffer in at least one place. This ensures it gets
650 // deleted even in the case the request has already finished its job and
651 // doesn't use the buffer.
652 scoped_refptr<net::IOBuffer> buf;
653 int buf_size;
655 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
656 tracked_objects::ScopedTracker tracking_profile2(
657 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()"));
659 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
660 Cancel();
661 return;
665 DCHECK(buf.get());
666 DCHECK(buf_size > 0);
668 request_->Read(buf.get(), buf_size, bytes_read);
670 // No need to check the return value here as we'll detect errors by
671 // inspecting the URLRequest's status.
674 void ResourceLoader::CompleteRead(int bytes_read) {
675 DCHECK(bytes_read >= 0);
676 DCHECK(request_->status().is_success());
678 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
679 tracked_objects::ScopedTracker tracking_profile(
680 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
682 bool defer = false;
683 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
684 Cancel();
685 } else if (defer) {
686 deferred_stage_ =
687 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
690 // Note: the request may still have been cancelled while OnReadCompleted
691 // returns true if OnReadCompleted caused request to get cancelled
692 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
693 // instance.)
696 void ResourceLoader::ResponseCompleted() {
697 VLOG(1) << "ResponseCompleted: " << request_->url().spec();
698 RecordHistograms();
699 ResourceRequestInfoImpl* info = GetRequestInfo();
701 std::string security_info;
702 const net::SSLInfo& ssl_info = request_->ssl_info();
703 if (ssl_info.cert.get() != NULL) {
704 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert.get(),
705 info->GetChildID());
706 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
707 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
708 info->GetChildID(),
709 &signed_certificate_timestamp_ids);
711 security_info = SerializeSecurityInfo(
712 cert_id, ssl_info.cert_status, ssl_info.security_bits,
713 ssl_info.connection_status, signed_certificate_timestamp_ids);
716 bool defer = false;
718 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
719 tracked_objects::ScopedTracker tracking_profile(
720 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
722 handler_->OnResponseCompleted(request_->status(), security_info, &defer);
724 if (defer) {
725 // The handler is not ready to die yet. We will call DidFinishLoading when
726 // we resume.
727 deferred_stage_ = DEFERRED_FINISH;
728 } else {
729 // This will result in our destruction.
730 CallDidFinishLoading();
734 void ResourceLoader::CallDidFinishLoading() {
735 delegate_->DidFinishLoading(this);
738 void ResourceLoader::RecordHistograms() {
739 ResourceRequestInfoImpl* info = GetRequestInfo();
741 if (info->GetResourceType() == RESOURCE_TYPE_PREFETCH) {
742 PrefetchStatus status = STATUS_UNDEFINED;
743 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
745 switch (request_->status().status()) {
746 case net::URLRequestStatus::SUCCESS:
747 if (request_->was_cached()) {
748 status = STATUS_SUCCESS_FROM_CACHE;
749 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
750 total_time);
751 } else {
752 status = STATUS_SUCCESS_FROM_NETWORK;
753 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
754 total_time);
756 break;
757 case net::URLRequestStatus::CANCELED:
758 status = STATUS_CANCELED;
759 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
760 break;
761 case net::URLRequestStatus::IO_PENDING:
762 case net::URLRequestStatus::FAILED:
763 status = STATUS_UNDEFINED;
764 break;
767 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
771 } // namespace content