Revert of Mac Overlays: Make ImageTransportSurfaceOverlayMac observe GPU switches...
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blob22e776ca5d9704a72ed0b333c5cc15896d1b30f8
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 StoreSignedCertificateTimestamps(
51 const net::SignedCertificateTimestampAndStatusList& sct_list,
52 int process_id,
53 SignedCertificateTimestampIDStatusList* sct_ids) {
54 SignedCertificateTimestampStore* sct_store(
55 SignedCertificateTimestampStore::GetInstance());
57 for (auto iter = sct_list.begin(); iter != sct_list.end(); ++iter) {
58 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
59 sct_ids->push_back(
60 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
64 void GetSSLStatusForRequest(const GURL& url,
65 const net::SSLInfo& ssl_info,
66 int child_id,
67 SSLStatus* ssl_status) {
68 DCHECK(ssl_info.cert);
70 int cert_id =
71 CertStore::GetInstance()->StoreCert(ssl_info.cert.get(), child_id);
73 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
74 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
75 child_id, &signed_certificate_timestamp_ids);
77 ssl_status->cert_id = cert_id;
78 ssl_status->cert_status = ssl_info.cert_status;
79 ssl_status->security_bits = ssl_info.security_bits;
80 ssl_status->connection_status = ssl_info.connection_status;
81 ssl_status->signed_certificate_timestamp_ids =
82 signed_certificate_timestamp_ids;
83 ssl_status->security_style =
84 SSLPolicy::GetSecurityStyleForResource(url, *ssl_status);
87 void PopulateResourceResponse(ResourceRequestInfoImpl* info,
88 net::URLRequest* request,
89 ResourceResponse* response) {
90 response->head.request_time = request->request_time();
91 response->head.response_time = request->response_time();
92 response->head.headers = request->response_headers();
93 request->GetCharset(&response->head.charset);
94 response->head.content_length = request->GetExpectedContentSize();
95 request->GetMimeType(&response->head.mime_type);
96 net::HttpResponseInfo response_info = request->response_info();
97 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
98 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
99 response->head.npn_negotiated_protocol =
100 response_info.npn_negotiated_protocol;
101 response->head.connection_info = response_info.connection_info;
102 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
103 response->head.proxy_server = response_info.proxy_server;
104 response->head.socket_address = request->GetSocketAddress();
105 if (ServiceWorkerRequestHandler* handler =
106 ServiceWorkerRequestHandler::GetHandler(request)) {
107 handler->GetExtraResponseInfo(&response->head);
109 AppCacheInterceptor::GetExtraResponseInfo(
110 request, &response->head.appcache_id,
111 &response->head.appcache_manifest_url);
112 if (info->is_load_timing_enabled())
113 request->GetLoadTimingInfo(&response->head.load_timing);
115 if (request->ssl_info().cert.get()) {
116 SSLStatus ssl_status;
117 GetSSLStatusForRequest(request->url(), request->ssl_info(),
118 info->GetChildID(), &ssl_status);
119 response->head.security_info = SerializeSecurityInfo(ssl_status);
120 } else {
121 // We should not have any SSL state.
122 DCHECK(!request->ssl_info().cert_status &&
123 request->ssl_info().security_bits == -1 &&
124 !request->ssl_info().connection_status);
128 } // namespace
130 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
131 scoped_ptr<ResourceHandler> handler,
132 ResourceLoaderDelegate* delegate)
133 : deferred_stage_(DEFERRED_NONE),
134 request_(request.Pass()),
135 handler_(handler.Pass()),
136 delegate_(delegate),
137 last_upload_position_(0),
138 waiting_for_upload_progress_ack_(false),
139 is_transferring_(false),
140 times_cancelled_before_request_start_(0),
141 started_request_(false),
142 times_cancelled_after_request_start_(0),
143 weak_ptr_factory_(this) {
144 request_->set_delegate(this);
145 handler_->SetController(this);
148 ResourceLoader::~ResourceLoader() {
149 if (login_delegate_.get())
150 login_delegate_->OnRequestCancelled();
151 ssl_client_auth_handler_.reset();
153 // Run ResourceHandler destructor before we tear-down the rest of our state
154 // as the ResourceHandler may want to inspect the URLRequest and other state.
155 handler_.reset();
158 void ResourceLoader::StartRequest() {
159 if (delegate_->HandleExternalProtocol(this, request_->url())) {
160 CancelAndIgnore();
161 return;
164 // Give the handler a chance to delay the URLRequest from being started.
165 bool defer_start = false;
166 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
167 Cancel();
168 return;
171 if (defer_start) {
172 deferred_stage_ = DEFERRED_START;
173 } else {
174 StartRequestInternal();
178 void ResourceLoader::CancelRequest(bool from_renderer) {
179 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
182 void ResourceLoader::CancelAndIgnore() {
183 ResourceRequestInfoImpl* info = GetRequestInfo();
184 info->set_was_ignored_by_handler(true);
185 CancelRequest(false);
188 void ResourceLoader::CancelWithError(int error_code) {
189 CancelRequestInternal(error_code, false);
192 void ResourceLoader::ReportUploadProgress() {
193 DCHECK(GetRequestInfo()->is_upload_progress_enabled());
195 if (waiting_for_upload_progress_ack_)
196 return; // Send one progress event at a time.
198 net::UploadProgress progress = request_->GetUploadProgress();
199 if (!progress.size())
200 return; // Nothing to upload.
202 if (progress.position() == last_upload_position_)
203 return; // No progress made since last time.
205 const uint64 kHalfPercentIncrements = 200;
206 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
208 uint64 amt_since_last = progress.position() - last_upload_position_;
209 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
211 bool is_finished = (progress.size() == progress.position());
212 bool enough_new_progress =
213 (amt_since_last > (progress.size() / kHalfPercentIncrements));
214 bool too_much_time_passed = time_since_last > kOneSecond;
216 if (is_finished || enough_new_progress || too_much_time_passed) {
217 handler_->OnUploadProgress(progress.position(), progress.size());
218 waiting_for_upload_progress_ack_ = true;
219 last_upload_ticks_ = TimeTicks::Now();
220 last_upload_position_ = progress.position();
224 void ResourceLoader::MarkAsTransferring() {
225 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
226 << "Can only transfer for navigations";
227 is_transferring_ = true;
229 int child_id = GetRequestInfo()->GetChildID();
230 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
231 ServiceWorkerRequestHandler* handler =
232 ServiceWorkerRequestHandler::GetHandler(request());
233 if (handler)
234 handler->PrepareForCrossSiteTransfer(child_id);
237 void ResourceLoader::CompleteTransfer() {
238 // Although CrossSiteResourceHandler defers at OnResponseStarted
239 // (DEFERRED_READ), it may be seeing a replay of events via
240 // MimeTypeResourceHandler, and so the request itself is actually deferred
241 // at a later read stage.
242 DCHECK(DEFERRED_READ == deferred_stage_ ||
243 DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
244 DCHECK(is_transferring_);
246 // In some cases, a process transfer doesn't really happen and the
247 // request is resumed in the original process. Real transfers to a new process
248 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
249 int child_id = GetRequestInfo()->GetChildID();
250 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
251 request(), child_id);
252 ServiceWorkerRequestHandler* handler =
253 ServiceWorkerRequestHandler::GetHandler(request());
254 if (handler)
255 handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
257 is_transferring_ = false;
258 GetRequestInfo()->cross_site_handler()->ResumeResponse();
261 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
262 return ResourceRequestInfoImpl::ForRequest(request_.get());
265 void ResourceLoader::ClearLoginDelegate() {
266 login_delegate_ = NULL;
269 void ResourceLoader::OnUploadProgressACK() {
270 waiting_for_upload_progress_ack_ = false;
273 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
274 const net::RedirectInfo& redirect_info,
275 bool* defer) {
276 DCHECK_EQ(request_.get(), unused);
278 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
279 DCHECK(request_->status().is_success());
281 ResourceRequestInfoImpl* info = GetRequestInfo();
283 if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
284 !ChildProcessSecurityPolicyImpl::GetInstance()->
285 CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
286 DVLOG(1) << "Denied unauthorized request for "
287 << redirect_info.new_url.possibly_invalid_spec();
289 // Tell the renderer that this request was disallowed.
290 Cancel();
291 return;
294 delegate_->DidReceiveRedirect(this, redirect_info.new_url);
296 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
297 // The request is complete so we can remove it.
298 CancelAndIgnore();
299 return;
302 scoped_refptr<ResourceResponse> response(new ResourceResponse());
303 PopulateResourceResponse(info, request_.get(), response.get());
304 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
305 Cancel();
306 } else if (*defer) {
307 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
311 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
312 net::AuthChallengeInfo* auth_info) {
313 DCHECK_EQ(request_.get(), unused);
315 ResourceRequestInfoImpl* info = GetRequestInfo();
316 if (info->do_not_prompt_for_login()) {
317 request_->CancelAuth();
318 return;
321 // Create a login dialog on the UI thread to get authentication data, or pull
322 // from cache and continue on the IO thread.
324 DCHECK(!login_delegate_.get())
325 << "OnAuthRequired called with login_delegate pending";
326 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
327 if (!login_delegate_.get())
328 request_->CancelAuth();
331 void ResourceLoader::OnCertificateRequested(
332 net::URLRequest* unused,
333 net::SSLCertRequestInfo* cert_info) {
334 DCHECK_EQ(request_.get(), unused);
336 if (request_->load_flags() & net::LOAD_PREFETCH) {
337 request_->Cancel();
338 return;
341 DCHECK(!ssl_client_auth_handler_)
342 << "OnCertificateRequested called with ssl_client_auth_handler pending";
343 ssl_client_auth_handler_.reset(new SSLClientAuthHandler(
344 GetRequestInfo()->GetContext()->CreateClientCertStore(), request_.get(),
345 cert_info, this));
346 ssl_client_auth_handler_->SelectCertificate();
349 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
350 const net::SSLInfo& ssl_info,
351 bool fatal) {
352 ResourceRequestInfoImpl* info = GetRequestInfo();
354 int render_process_id;
355 int render_frame_id;
356 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
357 NOTREACHED();
359 SSLManager::OnSSLCertificateError(
360 weak_ptr_factory_.GetWeakPtr(),
361 info->GetResourceType(),
362 request_->url(),
363 render_process_id,
364 render_frame_id,
365 ssl_info,
366 fatal);
369 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
370 bool* defer) {
371 DCHECK_EQ(request_.get(), unused);
373 // Give the handler a chance to delay the URLRequest from using the network.
374 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
375 Cancel();
376 return;
377 } else if (*defer) {
378 deferred_stage_ = DEFERRED_NETWORK_START;
382 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
383 DCHECK_EQ(request_.get(), unused);
385 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
387 progress_timer_.Stop();
389 if (!request_->status().is_success()) {
390 ResponseCompleted();
391 return;
394 // We want to send a final upload progress message prior to sending the
395 // response complete message even if we're waiting for an ack to to a
396 // previous upload progress message.
397 ResourceRequestInfoImpl* info = GetRequestInfo();
398 if (info->is_upload_progress_enabled()) {
399 waiting_for_upload_progress_ack_ = false;
400 ReportUploadProgress();
403 CompleteResponseStarted();
405 if (is_deferred())
406 return;
408 if (request_->status().is_success())
409 StartReading(false); // Read the first chunk.
410 else
411 ResponseCompleted();
414 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
415 DCHECK_EQ(request_.get(), unused);
416 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
417 << " bytes_read = " << bytes_read;
419 // bytes_read == -1 always implies an error.
420 if (bytes_read == -1 || !request_->status().is_success()) {
421 ResponseCompleted();
422 return;
425 CompleteRead(bytes_read);
427 // If the handler cancelled or deferred the request, do not continue
428 // processing the read. If cancelled, the URLRequest has already been
429 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
430 // do nothing until resumed.
432 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
433 // ResponseCompleted().
434 if (is_deferred() || !request_->status().is_success())
435 return;
437 if (bytes_read > 0) {
438 StartReading(true); // Read the next chunk.
439 } else {
440 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
441 tracked_objects::ScopedTracker tracking_profile(
442 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 ResponseCompleted()"));
444 // URLRequest reported an EOF. Call ResponseCompleted.
445 DCHECK_EQ(0, bytes_read);
446 ResponseCompleted();
450 void ResourceLoader::CancelSSLRequest(int error,
451 const net::SSLInfo* ssl_info) {
452 DCHECK_CURRENTLY_ON(BrowserThread::IO);
454 // The request can be NULL if it was cancelled by the renderer (as the
455 // request of the user navigating to a new page from the location bar).
456 if (!request_->is_pending())
457 return;
458 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
460 if (ssl_info) {
461 request_->CancelWithSSLError(error, *ssl_info);
462 } else {
463 request_->CancelWithError(error);
467 void ResourceLoader::ContinueSSLRequest() {
468 DCHECK_CURRENTLY_ON(BrowserThread::IO);
470 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
472 request_->ContinueDespiteLastError();
475 void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
476 DCHECK(ssl_client_auth_handler_);
477 ssl_client_auth_handler_.reset();
478 request_->ContinueWithCertificate(cert);
481 void ResourceLoader::CancelCertificateSelection() {
482 DCHECK(ssl_client_auth_handler_);
483 ssl_client_auth_handler_.reset();
484 request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
487 void ResourceLoader::Resume() {
488 DCHECK(!is_transferring_);
490 DeferredStage stage = deferred_stage_;
491 deferred_stage_ = DEFERRED_NONE;
492 switch (stage) {
493 case DEFERRED_NONE:
494 NOTREACHED();
495 break;
496 case DEFERRED_START:
497 StartRequestInternal();
498 break;
499 case DEFERRED_NETWORK_START:
500 request_->ResumeNetworkStart();
501 break;
502 case DEFERRED_REDIRECT:
503 request_->FollowDeferredRedirect();
504 break;
505 case DEFERRED_READ:
506 base::ThreadTaskRunnerHandle::Get()->PostTask(
507 FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
508 weak_ptr_factory_.GetWeakPtr()));
509 break;
510 case DEFERRED_RESPONSE_COMPLETE:
511 base::ThreadTaskRunnerHandle::Get()->PostTask(
512 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
513 weak_ptr_factory_.GetWeakPtr()));
514 break;
515 case DEFERRED_FINISH:
516 // Delay self-destruction since we don't know how we were reached.
517 base::ThreadTaskRunnerHandle::Get()->PostTask(
518 FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
519 weak_ptr_factory_.GetWeakPtr()));
520 break;
524 void ResourceLoader::Cancel() {
525 CancelRequest(false);
528 void ResourceLoader::StartRequestInternal() {
529 DCHECK(!request_->is_pending());
531 if (!request_->status().is_success()) {
532 return;
535 started_request_ = true;
536 request_->Start();
538 delegate_->DidStartRequest(this);
540 if (GetRequestInfo()->is_upload_progress_enabled() &&
541 request_->has_upload()) {
542 progress_timer_.Start(
543 FROM_HERE,
544 base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec),
545 this,
546 &ResourceLoader::ReportUploadProgress);
550 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
551 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
553 ResourceRequestInfoImpl* info = GetRequestInfo();
555 // WebKit will send us a cancel for downloads since it no longer handles
556 // them. In this case, ignore the cancel since we handle downloads in the
557 // browser.
558 if (from_renderer && (info->IsDownload() || info->is_stream()))
559 return;
561 if (from_renderer && info->detachable_handler()) {
562 // TODO(davidben): Fix Blink handling of prefetches so they are not
563 // cancelled on navigate away and end up in the local cache.
564 info->detachable_handler()->Detach();
565 return;
568 // TODO(darin): Perhaps we should really be looking to see if the status is
569 // IO_PENDING?
570 bool was_pending = request_->is_pending();
572 if (login_delegate_.get()) {
573 login_delegate_->OnRequestCancelled();
574 login_delegate_ = NULL;
576 ssl_client_auth_handler_.reset();
578 if (!started_request_) {
579 times_cancelled_before_request_start_++;
580 } else {
581 times_cancelled_after_request_start_++;
584 request_->CancelWithError(error);
586 if (!was_pending) {
587 // If the request isn't in flight, then we won't get an asynchronous
588 // notification from the request, so we have to signal ourselves to finish
589 // this request.
590 base::ThreadTaskRunnerHandle::Get()->PostTask(
591 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
592 weak_ptr_factory_.GetWeakPtr()));
596 void ResourceLoader::CompleteResponseStarted() {
597 ResourceRequestInfoImpl* info = GetRequestInfo();
598 scoped_refptr<ResourceResponse> response(new ResourceResponse());
599 PopulateResourceResponse(info, request_.get(), response.get());
601 delegate_->DidReceiveResponse(this);
603 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
604 tracked_objects::ScopedTracker tracking_profile(
605 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnResponseStarted()"));
607 bool defer = false;
608 if (!handler_->OnResponseStarted(response.get(), &defer)) {
609 Cancel();
610 } else if (defer) {
611 read_deferral_start_time_ = base::TimeTicks::Now();
612 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
616 void ResourceLoader::StartReading(bool is_continuation) {
617 int bytes_read = 0;
618 ReadMore(&bytes_read);
620 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
621 if (request_->status().is_io_pending())
622 return;
624 if (!is_continuation || bytes_read <= 0) {
625 OnReadCompleted(request_.get(), bytes_read);
626 } else {
627 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
628 // thread in case the URLRequest can provide data synchronously.
629 base::ThreadTaskRunnerHandle::Get()->PostTask(
630 FROM_HERE,
631 base::Bind(&ResourceLoader::OnReadCompleted,
632 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
636 void ResourceLoader::ResumeReading() {
637 DCHECK(!is_deferred());
639 if (!read_deferral_start_time_.is_null()) {
640 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
641 base::TimeTicks::Now() - read_deferral_start_time_);
642 read_deferral_start_time_ = base::TimeTicks();
644 if (request_->status().is_success()) {
645 StartReading(false); // Read the next chunk (OK to complete synchronously).
646 } else {
647 ResponseCompleted();
651 void ResourceLoader::ReadMore(int* bytes_read) {
652 DCHECK(!is_deferred());
654 // Make sure we track the buffer in at least one place. This ensures it gets
655 // deleted even in the case the request has already finished its job and
656 // doesn't use the buffer.
657 scoped_refptr<net::IOBuffer> buf;
658 int buf_size;
660 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
661 tracked_objects::ScopedTracker tracking_profile2(
662 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnWillRead()"));
664 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
665 Cancel();
666 return;
670 DCHECK(buf.get());
671 DCHECK(buf_size > 0);
673 request_->Read(buf.get(), buf_size, bytes_read);
675 // No need to check the return value here as we'll detect errors by
676 // inspecting the URLRequest's status.
679 void ResourceLoader::CompleteRead(int bytes_read) {
680 DCHECK(bytes_read >= 0);
681 DCHECK(request_->status().is_success());
683 // TODO(darin): Remove ScopedTracker below once crbug.com/475761 is fixed.
684 tracked_objects::ScopedTracker tracking_profile(
685 FROM_HERE_WITH_EXPLICIT_FUNCTION("475761 OnReadCompleted()"));
687 bool defer = false;
688 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
689 Cancel();
690 } else if (defer) {
691 deferred_stage_ =
692 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
695 // Note: the request may still have been cancelled while OnReadCompleted
696 // returns true if OnReadCompleted caused request to get cancelled
697 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
698 // instance.)
701 void ResourceLoader::ResponseCompleted() {
702 DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
703 RecordHistograms();
704 ResourceRequestInfoImpl* info = GetRequestInfo();
706 std::string security_info;
707 const net::SSLInfo& ssl_info = request_->ssl_info();
708 if (ssl_info.cert.get() != NULL) {
709 SSLStatus ssl_status;
710 GetSSLStatusForRequest(request_->url(), ssl_info, info->GetChildID(),
711 &ssl_status);
713 security_info = SerializeSecurityInfo(ssl_status);
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