base/threading: remove ScopedTracker placed for experiments
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blob0339cf11c0d5ade2f2f4ebe14a64cd3da4289c3b
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/browser/ssl/ssl_policy.h"
24 #include "content/common/ssl_status_serialization.h"
25 #include "content/public/browser/cert_store.h"
26 #include "content/public/browser/resource_context.h"
27 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
28 #include "content/public/browser/signed_certificate_timestamp_store.h"
29 #include "content/public/common/content_client.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/common/process_type.h"
32 #include "content/public/common/resource_response.h"
33 #include "content/public/common/security_style.h"
34 #include "net/base/io_buffer.h"
35 #include "net/base/load_flags.h"
36 #include "net/http/http_response_headers.h"
37 #include "net/ssl/client_cert_store.h"
38 #include "net/url_request/redirect_info.h"
39 #include "net/url_request/url_request_status.h"
41 using base::TimeDelta;
42 using base::TimeTicks;
44 namespace content {
45 namespace {
47 // The interval for calls to ResourceLoader::ReportUploadProgress.
48 const int kUploadProgressIntervalMsec = 100;
50 void PopulateResourceResponse(ResourceRequestInfoImpl* info,
51 net::URLRequest* request,
52 ResourceResponse* response) {
53 response->head.request_time = request->request_time();
54 response->head.response_time = request->response_time();
55 response->head.headers = request->response_headers();
56 request->GetCharset(&response->head.charset);
57 response->head.content_length = request->GetExpectedContentSize();
58 request->GetMimeType(&response->head.mime_type);
59 net::HttpResponseInfo response_info = request->response_info();
60 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
61 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
62 response->head.npn_negotiated_protocol =
63 response_info.npn_negotiated_protocol;
64 response->head.connection_info = response_info.connection_info;
65 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
66 response->head.proxy_server = response_info.proxy_server;
67 response->head.socket_address = request->GetSocketAddress();
68 if (ServiceWorkerRequestHandler* handler =
69 ServiceWorkerRequestHandler::GetHandler(request)) {
70 handler->GetExtraResponseInfo(&response->head);
72 AppCacheInterceptor::GetExtraResponseInfo(
73 request,
74 &response->head.appcache_id,
75 &response->head.appcache_manifest_url);
76 if (info->is_load_timing_enabled())
77 request->GetLoadTimingInfo(&response->head.load_timing);
80 void StoreSignedCertificateTimestamps(
81 const net::SignedCertificateTimestampAndStatusList& sct_list,
82 int process_id,
83 SignedCertificateTimestampIDStatusList* sct_ids) {
84 SignedCertificateTimestampStore* sct_store(
85 SignedCertificateTimestampStore::GetInstance());
87 for (auto iter = sct_list.begin(); iter != sct_list.end(); ++iter) {
88 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
89 sct_ids->push_back(
90 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
94 void GetSSLStatusForRequest(const GURL& url,
95 const net::SSLInfo& ssl_info,
96 int child_id,
97 SSLStatus* ssl_status) {
98 DCHECK(ssl_info.cert);
100 int cert_id =
101 CertStore::GetInstance()->StoreCert(ssl_info.cert.get(), child_id);
103 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
104 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
105 child_id, &signed_certificate_timestamp_ids);
107 ssl_status->cert_id = cert_id;
108 ssl_status->cert_status = ssl_info.cert_status;
109 ssl_status->security_bits = ssl_info.security_bits;
110 ssl_status->connection_status = ssl_info.connection_status;
111 ssl_status->signed_certificate_timestamp_ids =
112 signed_certificate_timestamp_ids;
113 ssl_status->security_style =
114 SSLPolicy::GetSecurityStyleForResource(url, *ssl_status);
117 } // namespace
119 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
120 scoped_ptr<ResourceHandler> handler,
121 ResourceLoaderDelegate* delegate)
122 : deferred_stage_(DEFERRED_NONE),
123 request_(request.Pass()),
124 handler_(handler.Pass()),
125 delegate_(delegate),
126 last_upload_position_(0),
127 waiting_for_upload_progress_ack_(false),
128 is_transferring_(false),
129 times_cancelled_before_request_start_(0),
130 started_request_(false),
131 times_cancelled_after_request_start_(0),
132 weak_ptr_factory_(this) {
133 request_->set_delegate(this);
134 handler_->SetController(this);
137 ResourceLoader::~ResourceLoader() {
138 if (login_delegate_.get())
139 login_delegate_->OnRequestCancelled();
140 ssl_client_auth_handler_.reset();
142 // Run ResourceHandler destructor before we tear-down the rest of our state
143 // as the ResourceHandler may want to inspect the URLRequest and other state.
144 handler_.reset();
147 void ResourceLoader::StartRequest() {
148 if (delegate_->HandleExternalProtocol(this, request_->url())) {
149 CancelAndIgnore();
150 return;
153 // Give the handler a chance to delay the URLRequest from being started.
154 bool defer_start = false;
155 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
156 Cancel();
157 return;
160 if (defer_start) {
161 deferred_stage_ = DEFERRED_START;
162 } else {
163 StartRequestInternal();
167 void ResourceLoader::CancelRequest(bool from_renderer) {
168 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
171 void ResourceLoader::CancelAndIgnore() {
172 ResourceRequestInfoImpl* info = GetRequestInfo();
173 info->set_was_ignored_by_handler(true);
174 CancelRequest(false);
177 void ResourceLoader::CancelWithError(int error_code) {
178 CancelRequestInternal(error_code, false);
181 void ResourceLoader::ReportUploadProgress() {
182 DCHECK(GetRequestInfo()->is_upload_progress_enabled());
184 if (waiting_for_upload_progress_ack_)
185 return; // Send one progress event at a time.
187 net::UploadProgress progress = request_->GetUploadProgress();
188 if (!progress.size())
189 return; // Nothing to upload.
191 if (progress.position() == last_upload_position_)
192 return; // No progress made since last time.
194 const uint64 kHalfPercentIncrements = 200;
195 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
197 uint64 amt_since_last = progress.position() - last_upload_position_;
198 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
200 bool is_finished = (progress.size() == progress.position());
201 bool enough_new_progress =
202 (amt_since_last > (progress.size() / kHalfPercentIncrements));
203 bool too_much_time_passed = time_since_last > kOneSecond;
205 if (is_finished || enough_new_progress || too_much_time_passed) {
206 handler_->OnUploadProgress(progress.position(), progress.size());
207 waiting_for_upload_progress_ack_ = true;
208 last_upload_ticks_ = TimeTicks::Now();
209 last_upload_position_ = progress.position();
213 void ResourceLoader::MarkAsTransferring() {
214 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
215 << "Can only transfer for navigations";
216 is_transferring_ = true;
218 int child_id = GetRequestInfo()->GetChildID();
219 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
220 ServiceWorkerRequestHandler* handler =
221 ServiceWorkerRequestHandler::GetHandler(request());
222 if (handler)
223 handler->PrepareForCrossSiteTransfer(child_id);
226 void ResourceLoader::CompleteTransfer() {
227 // Although CrossSiteResourceHandler defers at OnResponseStarted
228 // (DEFERRED_READ), it may be seeing a replay of events via
229 // MimeTypeResourceHandler, and so the request itself is actually deferred
230 // at a later read stage.
231 DCHECK(DEFERRED_READ == deferred_stage_ ||
232 DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
233 DCHECK(is_transferring_);
235 // In some cases, a process transfer doesn't really happen and the
236 // request is resumed in the original process. Real transfers to a new process
237 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
238 int child_id = GetRequestInfo()->GetChildID();
239 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
240 request(), child_id);
241 ServiceWorkerRequestHandler* handler =
242 ServiceWorkerRequestHandler::GetHandler(request());
243 if (handler)
244 handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
246 is_transferring_ = false;
247 GetRequestInfo()->cross_site_handler()->ResumeResponse();
250 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
251 return ResourceRequestInfoImpl::ForRequest(request_.get());
254 void ResourceLoader::ClearLoginDelegate() {
255 login_delegate_ = NULL;
258 void ResourceLoader::OnUploadProgressACK() {
259 waiting_for_upload_progress_ack_ = false;
262 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
263 const net::RedirectInfo& redirect_info,
264 bool* defer) {
265 DCHECK_EQ(request_.get(), unused);
267 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
268 DCHECK(request_->status().is_success());
270 ResourceRequestInfoImpl* info = GetRequestInfo();
272 if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
273 !ChildProcessSecurityPolicyImpl::GetInstance()->
274 CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
275 DVLOG(1) << "Denied unauthorized request for "
276 << redirect_info.new_url.possibly_invalid_spec();
278 // Tell the renderer that this request was disallowed.
279 Cancel();
280 return;
283 delegate_->DidReceiveRedirect(this, redirect_info.new_url);
285 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
286 // The request is complete so we can remove it.
287 CancelAndIgnore();
288 return;
291 scoped_refptr<ResourceResponse> response(new ResourceResponse());
292 PopulateResourceResponse(info, request_.get(), response.get());
293 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
294 Cancel();
295 } else if (*defer) {
296 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
300 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
301 net::AuthChallengeInfo* auth_info) {
302 DCHECK_EQ(request_.get(), unused);
304 ResourceRequestInfoImpl* info = GetRequestInfo();
305 if (info->do_not_prompt_for_login()) {
306 request_->CancelAuth();
307 return;
310 // Create a login dialog on the UI thread to get authentication data, or pull
311 // from cache and continue on the IO thread.
313 DCHECK(!login_delegate_.get())
314 << "OnAuthRequired called with login_delegate pending";
315 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
316 if (!login_delegate_.get())
317 request_->CancelAuth();
320 void ResourceLoader::OnCertificateRequested(
321 net::URLRequest* unused,
322 net::SSLCertRequestInfo* cert_info) {
323 DCHECK_EQ(request_.get(), unused);
325 if (request_->load_flags() & net::LOAD_PREFETCH) {
326 request_->Cancel();
327 return;
330 DCHECK(!ssl_client_auth_handler_)
331 << "OnCertificateRequested called with ssl_client_auth_handler pending";
332 ssl_client_auth_handler_.reset(new SSLClientAuthHandler(
333 GetRequestInfo()->GetContext()->CreateClientCertStore(), request_.get(),
334 cert_info, this));
335 ssl_client_auth_handler_->SelectCertificate();
338 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
339 const net::SSLInfo& ssl_info,
340 bool fatal) {
341 ResourceRequestInfoImpl* info = GetRequestInfo();
343 int render_process_id;
344 int render_frame_id;
345 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
346 NOTREACHED();
348 SSLManager::OnSSLCertificateError(
349 weak_ptr_factory_.GetWeakPtr(),
350 info->GetResourceType(),
351 request_->url(),
352 render_process_id,
353 render_frame_id,
354 ssl_info,
355 fatal);
358 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
359 bool* defer) {
360 DCHECK_EQ(request_.get(), unused);
362 // Give the handler a chance to delay the URLRequest from using the network.
363 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
364 Cancel();
365 return;
366 } else if (*defer) {
367 deferred_stage_ = DEFERRED_NETWORK_START;
371 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
372 DCHECK_EQ(request_.get(), unused);
374 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
376 progress_timer_.Stop();
378 if (!request_->status().is_success()) {
379 ResponseCompleted();
380 return;
383 // We want to send a final upload progress message prior to sending the
384 // response complete message even if we're waiting for an ack to to a
385 // previous upload progress message.
386 ResourceRequestInfoImpl* info = GetRequestInfo();
387 if (info->is_upload_progress_enabled()) {
388 waiting_for_upload_progress_ack_ = false;
389 ReportUploadProgress();
392 CompleteResponseStarted();
394 if (is_deferred())
395 return;
397 if (request_->status().is_success())
398 StartReading(false); // Read the first chunk.
399 else
400 ResponseCompleted();
403 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
404 DCHECK_EQ(request_.get(), unused);
405 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
406 << " bytes_read = " << bytes_read;
408 // bytes_read == -1 always implies an error.
409 if (bytes_read == -1 || !request_->status().is_success()) {
410 ResponseCompleted();
411 return;
414 CompleteRead(bytes_read);
416 // If the handler cancelled or deferred the request, do not continue
417 // processing the read. If cancelled, the URLRequest has already been
418 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
419 // do nothing until resumed.
421 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
422 // ResponseCompleted().
423 if (is_deferred() || !request_->status().is_success())
424 return;
426 if (bytes_read > 0) {
427 StartReading(true); // Read the next chunk.
428 } else {
429 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
430 tracked_objects::ScopedTracker tracking_profile(
431 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
433 // URLRequest reported an EOF. Call ResponseCompleted.
434 DCHECK_EQ(0, bytes_read);
435 ResponseCompleted();
439 void ResourceLoader::CancelSSLRequest(int error,
440 const net::SSLInfo* ssl_info) {
441 DCHECK_CURRENTLY_ON(BrowserThread::IO);
443 // The request can be NULL if it was cancelled by the renderer (as the
444 // request of the user navigating to a new page from the location bar).
445 if (!request_->is_pending())
446 return;
447 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
449 if (ssl_info) {
450 request_->CancelWithSSLError(error, *ssl_info);
451 } else {
452 request_->CancelWithError(error);
456 void ResourceLoader::ContinueSSLRequest() {
457 DCHECK_CURRENTLY_ON(BrowserThread::IO);
459 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
461 request_->ContinueDespiteLastError();
464 void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
465 DCHECK(ssl_client_auth_handler_);
466 ssl_client_auth_handler_.reset();
467 request_->ContinueWithCertificate(cert);
470 void ResourceLoader::CancelCertificateSelection() {
471 DCHECK(ssl_client_auth_handler_);
472 ssl_client_auth_handler_.reset();
473 request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
476 void ResourceLoader::Resume() {
477 DCHECK(!is_transferring_);
479 DeferredStage stage = deferred_stage_;
480 deferred_stage_ = DEFERRED_NONE;
481 switch (stage) {
482 case DEFERRED_NONE:
483 NOTREACHED();
484 break;
485 case DEFERRED_START:
486 StartRequestInternal();
487 break;
488 case DEFERRED_NETWORK_START:
489 request_->ResumeNetworkStart();
490 break;
491 case DEFERRED_REDIRECT:
492 request_->FollowDeferredRedirect();
493 break;
494 case DEFERRED_READ:
495 base::ThreadTaskRunnerHandle::Get()->PostTask(
496 FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
497 weak_ptr_factory_.GetWeakPtr()));
498 break;
499 case DEFERRED_RESPONSE_COMPLETE:
500 base::ThreadTaskRunnerHandle::Get()->PostTask(
501 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
502 weak_ptr_factory_.GetWeakPtr()));
503 break;
504 case DEFERRED_FINISH:
505 // Delay self-destruction since we don't know how we were reached.
506 base::ThreadTaskRunnerHandle::Get()->PostTask(
507 FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
508 weak_ptr_factory_.GetWeakPtr()));
509 break;
513 void ResourceLoader::Cancel() {
514 CancelRequest(false);
517 void ResourceLoader::StartRequestInternal() {
518 DCHECK(!request_->is_pending());
520 if (!request_->status().is_success()) {
521 return;
524 started_request_ = true;
525 request_->Start();
527 delegate_->DidStartRequest(this);
529 if (GetRequestInfo()->is_upload_progress_enabled() &&
530 request_->has_upload()) {
531 progress_timer_.Start(
532 FROM_HERE,
533 base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec),
534 this,
535 &ResourceLoader::ReportUploadProgress);
539 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
540 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
542 ResourceRequestInfoImpl* info = GetRequestInfo();
544 // WebKit will send us a cancel for downloads since it no longer handles
545 // them. In this case, ignore the cancel since we handle downloads in the
546 // browser.
547 if (from_renderer && (info->IsDownload() || info->is_stream()))
548 return;
550 if (from_renderer && info->detachable_handler()) {
551 // TODO(davidben): Fix Blink handling of prefetches so they are not
552 // cancelled on navigate away and end up in the local cache.
553 info->detachable_handler()->Detach();
554 return;
557 // TODO(darin): Perhaps we should really be looking to see if the status is
558 // IO_PENDING?
559 bool was_pending = request_->is_pending();
561 if (login_delegate_.get()) {
562 login_delegate_->OnRequestCancelled();
563 login_delegate_ = NULL;
565 ssl_client_auth_handler_.reset();
567 if (!started_request_) {
568 times_cancelled_before_request_start_++;
569 } else {
570 times_cancelled_after_request_start_++;
573 request_->CancelWithError(error);
575 if (!was_pending) {
576 // If the request isn't in flight, then we won't get an asynchronous
577 // notification from the request, so we have to signal ourselves to finish
578 // this request.
579 base::ThreadTaskRunnerHandle::Get()->PostTask(
580 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
581 weak_ptr_factory_.GetWeakPtr()));
585 void ResourceLoader::CompleteResponseStarted() {
586 ResourceRequestInfoImpl* info = GetRequestInfo();
587 scoped_refptr<ResourceResponse> response(new ResourceResponse());
588 PopulateResourceResponse(info, request_.get(), response.get());
590 if (request_->ssl_info().cert.get()) {
591 SSLStatus ssl_status;
592 GetSSLStatusForRequest(request_->url(), request_->ssl_info(),
593 info->GetChildID(), &ssl_status);
595 response->head.security_info = SerializeSecurityInfo(ssl_status);
596 } else {
597 // We should not have any SSL state.
598 DCHECK(!request_->ssl_info().cert_status &&
599 request_->ssl_info().security_bits == -1 &&
600 !request_->ssl_info().connection_status);
603 delegate_->DidReceiveResponse(this);
605 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
606 tracked_objects::ScopedTracker tracking_profile(
607 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
609 bool defer = false;
610 if (!handler_->OnResponseStarted(response.get(), &defer)) {
611 Cancel();
612 } else if (defer) {
613 read_deferral_start_time_ = base::TimeTicks::Now();
614 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
618 void ResourceLoader::StartReading(bool is_continuation) {
619 int bytes_read = 0;
620 ReadMore(&bytes_read);
622 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
623 if (request_->status().is_io_pending())
624 return;
626 if (!is_continuation || bytes_read <= 0) {
627 OnReadCompleted(request_.get(), bytes_read);
628 } else {
629 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
630 // thread in case the URLRequest can provide data synchronously.
631 base::ThreadTaskRunnerHandle::Get()->PostTask(
632 FROM_HERE,
633 base::Bind(&ResourceLoader::OnReadCompleted,
634 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
638 void ResourceLoader::ResumeReading() {
639 DCHECK(!is_deferred());
641 if (!read_deferral_start_time_.is_null()) {
642 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
643 base::TimeTicks::Now() - read_deferral_start_time_);
644 read_deferral_start_time_ = base::TimeTicks();
646 if (request_->status().is_success()) {
647 StartReading(false); // Read the next chunk (OK to complete synchronously).
648 } else {
649 ResponseCompleted();
653 void ResourceLoader::ReadMore(int* bytes_read) {
654 DCHECK(!is_deferred());
656 // Make sure we track the buffer in at least one place. This ensures it gets
657 // deleted even in the case the request has already finished its job and
658 // doesn't use the buffer.
659 scoped_refptr<net::IOBuffer> buf;
660 int buf_size;
662 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
663 tracked_objects::ScopedTracker tracking_profile2(
664 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()"));
666 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
667 Cancel();
668 return;
672 DCHECK(buf.get());
673 DCHECK(buf_size > 0);
675 request_->Read(buf.get(), buf_size, bytes_read);
677 // No need to check the return value here as we'll detect errors by
678 // inspecting the URLRequest's status.
681 void ResourceLoader::CompleteRead(int bytes_read) {
682 DCHECK(bytes_read >= 0);
683 DCHECK(request_->status().is_success());
685 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
686 tracked_objects::ScopedTracker tracking_profile(
687 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
689 bool defer = false;
690 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
691 Cancel();
692 } else if (defer) {
693 deferred_stage_ =
694 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
697 // Note: the request may still have been cancelled while OnReadCompleted
698 // returns true if OnReadCompleted caused request to get cancelled
699 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
700 // instance.)
703 void ResourceLoader::ResponseCompleted() {
704 DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
705 RecordHistograms();
706 ResourceRequestInfoImpl* info = GetRequestInfo();
708 std::string security_info;
709 const net::SSLInfo& ssl_info = request_->ssl_info();
710 if (ssl_info.cert.get() != NULL) {
711 SSLStatus ssl_status;
712 GetSSLStatusForRequest(request_->url(), ssl_info, info->GetChildID(),
713 &ssl_status);
715 security_info = SerializeSecurityInfo(ssl_status);
718 bool defer = false;
720 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
721 tracked_objects::ScopedTracker tracking_profile(
722 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseCompleted()"));
724 handler_->OnResponseCompleted(request_->status(), security_info, &defer);
726 if (defer) {
727 // The handler is not ready to die yet. We will call DidFinishLoading when
728 // we resume.
729 deferred_stage_ = DEFERRED_FINISH;
730 } else {
731 // This will result in our destruction.
732 CallDidFinishLoading();
736 void ResourceLoader::CallDidFinishLoading() {
737 delegate_->DidFinishLoading(this);
740 void ResourceLoader::RecordHistograms() {
741 ResourceRequestInfoImpl* info = GetRequestInfo();
743 if (info->GetResourceType() == RESOURCE_TYPE_PREFETCH) {
744 PrefetchStatus status = STATUS_UNDEFINED;
745 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
747 switch (request_->status().status()) {
748 case net::URLRequestStatus::SUCCESS:
749 if (request_->was_cached()) {
750 status = STATUS_SUCCESS_FROM_CACHE;
751 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
752 total_time);
753 } else {
754 status = STATUS_SUCCESS_FROM_NETWORK;
755 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
756 total_time);
758 break;
759 case net::URLRequestStatus::CANCELED:
760 status = STATUS_CANCELED;
761 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
762 break;
763 case net::URLRequestStatus::IO_PENDING:
764 case net::URLRequestStatus::FAILED:
765 status = STATUS_UNDEFINED;
766 break;
769 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
773 } // namespace content