Rename isSystemLocationEnabled to isLocationEnabled, as per internal review (185995).
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blob83cdf38f60a74bd34d6812c628128a3fec50e43a
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/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/time/time.h"
12 #include "content/browser/appcache/appcache_interceptor.h"
13 #include "content/browser/child_process_security_policy_impl.h"
14 #include "content/browser/loader/cross_site_resource_handler.h"
15 #include "content/browser/loader/detachable_resource_handler.h"
16 #include "content/browser/loader/resource_loader_delegate.h"
17 #include "content/browser/loader/resource_request_info_impl.h"
18 #include "content/browser/service_worker/service_worker_request_handler.h"
19 #include "content/browser/ssl/ssl_client_auth_handler.h"
20 #include "content/browser/ssl/ssl_manager.h"
21 #include "content/common/ssl_status_serialization.h"
22 #include "content/public/browser/cert_store.h"
23 #include "content/public/browser/resource_context.h"
24 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
25 #include "content/public/browser/signed_certificate_timestamp_store.h"
26 #include "content/public/common/content_client.h"
27 #include "content/public/common/content_switches.h"
28 #include "content/public/common/process_type.h"
29 #include "content/public/common/resource_response.h"
30 #include "net/base/io_buffer.h"
31 #include "net/base/load_flags.h"
32 #include "net/http/http_response_headers.h"
33 #include "net/ssl/client_cert_store.h"
34 #include "net/url_request/redirect_info.h"
35 #include "net/url_request/url_request_status.h"
37 using base::TimeDelta;
38 using base::TimeTicks;
40 namespace content {
41 namespace {
43 void PopulateResourceResponse(ResourceRequestInfoImpl* info,
44 net::URLRequest* request,
45 ResourceResponse* response) {
46 response->head.request_time = request->request_time();
47 response->head.response_time = request->response_time();
48 response->head.headers = request->response_headers();
49 request->GetCharset(&response->head.charset);
50 response->head.content_length = request->GetExpectedContentSize();
51 request->GetMimeType(&response->head.mime_type);
52 net::HttpResponseInfo response_info = request->response_info();
53 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
54 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
55 response->head.npn_negotiated_protocol =
56 response_info.npn_negotiated_protocol;
57 response->head.connection_info = response_info.connection_info;
58 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
59 response->head.proxy_server = response_info.proxy_server;
60 response->head.socket_address = request->GetSocketAddress();
61 if (ServiceWorkerRequestHandler* handler =
62 ServiceWorkerRequestHandler::GetHandler(request)) {
63 handler->GetExtraResponseInfo(
64 &response->head.was_fetched_via_service_worker,
65 &response->head.was_fallback_required_by_service_worker,
66 &response->head.original_url_via_service_worker,
67 &response->head.response_type_via_service_worker,
68 &response->head.service_worker_fetch_start,
69 &response->head.service_worker_fetch_ready,
70 &response->head.service_worker_fetch_end);
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 } // namespace
82 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
83 scoped_ptr<ResourceHandler> handler,
84 ResourceLoaderDelegate* delegate)
85 : deferred_stage_(DEFERRED_NONE),
86 request_(request.Pass()),
87 handler_(handler.Pass()),
88 delegate_(delegate),
89 last_upload_position_(0),
90 waiting_for_upload_progress_ack_(false),
91 is_transferring_(false),
92 weak_ptr_factory_(this) {
93 request_->set_delegate(this);
94 handler_->SetController(this);
97 ResourceLoader::~ResourceLoader() {
98 if (login_delegate_.get())
99 login_delegate_->OnRequestCancelled();
100 if (ssl_client_auth_handler_.get())
101 ssl_client_auth_handler_->OnRequestCancelled();
103 // Run ResourceHandler destructor before we tear-down the rest of our state
104 // as the ResourceHandler may want to inspect the URLRequest and other state.
105 handler_.reset();
108 void ResourceLoader::StartRequest() {
109 if (delegate_->HandleExternalProtocol(this, request_->url())) {
110 CancelAndIgnore();
111 return;
114 // Give the handler a chance to delay the URLRequest from being started.
115 bool defer_start = false;
117 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
118 tracked_objects::ScopedTracker tracking_profile(
119 FROM_HERE_WITH_EXPLICIT_FUNCTION(
120 "423948 ResourceLoader::StartRequest"));
122 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
123 Cancel();
124 return;
128 if (defer_start) {
129 deferred_stage_ = DEFERRED_START;
130 } else {
131 StartRequestInternal();
135 void ResourceLoader::CancelRequest(bool from_renderer) {
136 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
139 void ResourceLoader::CancelAndIgnore() {
140 ResourceRequestInfoImpl* info = GetRequestInfo();
141 info->set_was_ignored_by_handler(true);
142 CancelRequest(false);
145 void ResourceLoader::CancelWithError(int error_code) {
146 CancelRequestInternal(error_code, false);
149 void ResourceLoader::ReportUploadProgress() {
150 if (waiting_for_upload_progress_ack_)
151 return; // Send one progress event at a time.
153 net::UploadProgress progress = request_->GetUploadProgress();
154 if (!progress.size())
155 return; // Nothing to upload.
157 if (progress.position() == last_upload_position_)
158 return; // No progress made since last time.
160 const uint64 kHalfPercentIncrements = 200;
161 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
163 uint64 amt_since_last = progress.position() - last_upload_position_;
164 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
166 bool is_finished = (progress.size() == progress.position());
167 bool enough_new_progress =
168 (amt_since_last > (progress.size() / kHalfPercentIncrements));
169 bool too_much_time_passed = time_since_last > kOneSecond;
171 if (is_finished || enough_new_progress || too_much_time_passed) {
172 ResourceRequestInfoImpl* info = GetRequestInfo();
173 if (info->is_upload_progress_enabled()) {
174 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is
175 // fixed.
176 tracked_objects::ScopedTracker tracking_profile(
177 FROM_HERE_WITH_EXPLICIT_FUNCTION(
178 "423948 ResourceLoader::ReportUploadProgress"));
180 handler_->OnUploadProgress(progress.position(), progress.size());
181 waiting_for_upload_progress_ack_ = true;
183 last_upload_ticks_ = TimeTicks::Now();
184 last_upload_position_ = progress.position();
188 void ResourceLoader::MarkAsTransferring() {
189 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
190 << "Can only transfer for navigations";
191 is_transferring_ = true;
193 int child_id = GetRequestInfo()->GetChildID();
194 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
195 ServiceWorkerRequestHandler* handler =
196 ServiceWorkerRequestHandler::GetHandler(request());
197 if (handler)
198 handler->PrepareForCrossSiteTransfer(child_id);
201 void ResourceLoader::CompleteTransfer() {
202 // Although CrossSiteResourceHandler defers at OnResponseStarted
203 // (DEFERRED_READ), it may be seeing a replay of events via
204 // BufferedResourceHandler, and so the request itself is actually deferred at
205 // a later read stage.
206 DCHECK(DEFERRED_READ == deferred_stage_ ||
207 DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
208 DCHECK(is_transferring_);
210 // In some cases, a process transfer doesn't really happen and the
211 // request is resumed in the original process. Real transfers to a new process
212 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
213 int child_id = GetRequestInfo()->GetChildID();
214 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
215 request(), child_id);
216 ServiceWorkerRequestHandler* handler =
217 ServiceWorkerRequestHandler::GetHandler(request());
218 if (handler)
219 handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
221 is_transferring_ = false;
222 GetRequestInfo()->cross_site_handler()->ResumeResponse();
225 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
226 return ResourceRequestInfoImpl::ForRequest(request_.get());
229 void ResourceLoader::ClearLoginDelegate() {
230 login_delegate_ = NULL;
233 void ResourceLoader::OnUploadProgressACK() {
234 waiting_for_upload_progress_ack_ = false;
237 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
238 const net::RedirectInfo& redirect_info,
239 bool* defer) {
240 DCHECK_EQ(request_.get(), unused);
242 VLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
243 DCHECK(request_->status().is_success());
245 ResourceRequestInfoImpl* info = GetRequestInfo();
247 if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
248 !ChildProcessSecurityPolicyImpl::GetInstance()->
249 CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
250 VLOG(1) << "Denied unauthorized request for "
251 << redirect_info.new_url.possibly_invalid_spec();
253 // Tell the renderer that this request was disallowed.
254 Cancel();
255 return;
258 delegate_->DidReceiveRedirect(this, redirect_info.new_url);
260 if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
261 // The request is complete so we can remove it.
262 CancelAndIgnore();
263 return;
266 scoped_refptr<ResourceResponse> response(new ResourceResponse());
267 PopulateResourceResponse(info, request_.get(), response.get());
269 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
270 tracked_objects::ScopedTracker tracking_profile(
271 FROM_HERE_WITH_EXPLICIT_FUNCTION(
272 "423948 ResourceLoader::OnReceivedRedirect"));
274 if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
275 Cancel();
276 } else if (*defer) {
277 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
281 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
282 net::AuthChallengeInfo* auth_info) {
283 DCHECK_EQ(request_.get(), unused);
285 if (request_->load_flags() & net::LOAD_DO_NOT_PROMPT_FOR_LOGIN) {
286 request_->CancelAuth();
287 return;
290 // Create a login dialog on the UI thread to get authentication data, or pull
291 // from cache and continue on the IO thread.
293 DCHECK(!login_delegate_.get())
294 << "OnAuthRequired called with login_delegate pending";
295 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
296 if (!login_delegate_.get())
297 request_->CancelAuth();
300 void ResourceLoader::OnCertificateRequested(
301 net::URLRequest* unused,
302 net::SSLCertRequestInfo* cert_info) {
303 DCHECK_EQ(request_.get(), unused);
305 if (request_->load_flags() & net::LOAD_PREFETCH) {
306 request_->Cancel();
307 return;
310 DCHECK(!ssl_client_auth_handler_.get())
311 << "OnCertificateRequested called with ssl_client_auth_handler pending";
312 ssl_client_auth_handler_ = new SSLClientAuthHandler(
313 GetRequestInfo()->GetContext()->CreateClientCertStore(),
314 request_.get(),
315 cert_info,
316 base::Bind(&ResourceLoader::ContinueWithCertificate,
317 weak_ptr_factory_.GetWeakPtr()));
318 ssl_client_auth_handler_->SelectCertificate();
321 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
322 const net::SSLInfo& ssl_info,
323 bool fatal) {
324 ResourceRequestInfoImpl* info = GetRequestInfo();
326 int render_process_id;
327 int render_frame_id;
328 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
329 NOTREACHED();
331 SSLManager::OnSSLCertificateError(
332 weak_ptr_factory_.GetWeakPtr(),
333 info->GetResourceType(),
334 request_->url(),
335 render_process_id,
336 render_frame_id,
337 ssl_info,
338 fatal);
341 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
342 bool* defer) {
343 DCHECK_EQ(request_.get(), unused);
345 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
346 tracked_objects::ScopedTracker tracking_profile(
347 FROM_HERE_WITH_EXPLICIT_FUNCTION(
348 "423948 ResourceLoader::OnBeforeNetworkStart"));
350 // Give the handler a chance to delay the URLRequest from using the network.
351 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
352 Cancel();
353 return;
354 } else if (*defer) {
355 deferred_stage_ = DEFERRED_NETWORK_START;
359 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
360 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
361 tracked_objects::ScopedTracker tracking_profile(
362 FROM_HERE_WITH_EXPLICIT_FUNCTION(
363 "423948 ResourceLoader::OnResponseStarted"));
365 DCHECK_EQ(request_.get(), unused);
367 VLOG(1) << "OnResponseStarted: " << request_->url().spec();
369 // The CanLoadPage check should take place after any server redirects have
370 // finished, at the point in time that we know a page will commit in the
371 // renderer process.
372 ResourceRequestInfoImpl* info = GetRequestInfo();
373 ChildProcessSecurityPolicyImpl* policy =
374 ChildProcessSecurityPolicyImpl::GetInstance();
375 if (!policy->CanLoadPage(info->GetChildID(),
376 request_->url(),
377 info->GetResourceType())) {
378 Cancel();
379 return;
382 if (!request_->status().is_success()) {
383 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
384 tracked_objects::ScopedTracker tracking_profile1(
385 FROM_HERE_WITH_EXPLICIT_FUNCTION(
386 "423948 ResourceLoader::OnResponseStarted1"));
388 ResponseCompleted();
389 return;
392 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
393 tracked_objects::ScopedTracker tracking_profile2(
394 FROM_HERE_WITH_EXPLICIT_FUNCTION(
395 "423948 ResourceLoader::OnResponseStarted2"));
397 // We want to send a final upload progress message prior to sending the
398 // response complete message even if we're waiting for an ack to to a
399 // previous upload progress message.
400 waiting_for_upload_progress_ack_ = false;
401 ReportUploadProgress();
403 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
404 tracked_objects::ScopedTracker tracking_profile3(
405 FROM_HERE_WITH_EXPLICIT_FUNCTION(
406 "423948 ResourceLoader::OnResponseStarted3"));
408 CompleteResponseStarted();
410 if (is_deferred())
411 return;
413 if (request_->status().is_success()) {
414 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
415 tracked_objects::ScopedTracker tracking_profile4(
416 FROM_HERE_WITH_EXPLICIT_FUNCTION(
417 "423948 ResourceLoader::OnResponseStarted4"));
419 StartReading(false); // Read the first chunk.
420 } else {
421 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
422 tracked_objects::ScopedTracker tracking_profile5(
423 FROM_HERE_WITH_EXPLICIT_FUNCTION(
424 "423948 ResourceLoader::OnResponseStarted5"));
426 ResponseCompleted();
430 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
431 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
432 tracked_objects::ScopedTracker tracking_profile(
433 FROM_HERE_WITH_EXPLICIT_FUNCTION(
434 "423948 ResourceLoader::OnReadCompleted"));
436 DCHECK_EQ(request_.get(), unused);
437 VLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
438 << " bytes_read = " << bytes_read;
440 // bytes_read == -1 always implies an error.
441 if (bytes_read == -1 || !request_->status().is_success()) {
442 tracked_objects::ScopedTracker tracking_profile1(
443 FROM_HERE_WITH_EXPLICIT_FUNCTION(
444 "423948 ResourceLoader::OnReadCompleted1"));
446 ResponseCompleted();
447 return;
450 tracked_objects::ScopedTracker tracking_profile2(
451 FROM_HERE_WITH_EXPLICIT_FUNCTION(
452 "423948 ResourceLoader::OnReadCompleted2"));
454 CompleteRead(bytes_read);
456 // If the handler cancelled or deferred the request, do not continue
457 // processing the read. If cancelled, the URLRequest has already been
458 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
459 // do nothing until resumed.
461 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
462 // ResponseCompleted().
463 if (is_deferred() || !request_->status().is_success())
464 return;
466 if (bytes_read > 0) {
467 tracked_objects::ScopedTracker tracking_profile3(
468 FROM_HERE_WITH_EXPLICIT_FUNCTION(
469 "423948 ResourceLoader::OnReadCompleted3"));
471 StartReading(true); // Read the next chunk.
472 } else {
473 tracked_objects::ScopedTracker tracking_profile4(
474 FROM_HERE_WITH_EXPLICIT_FUNCTION(
475 "423948 ResourceLoader::OnReadCompleted4"));
477 // URLRequest reported an EOF. Call ResponseCompleted.
478 DCHECK_EQ(0, bytes_read);
479 ResponseCompleted();
483 void ResourceLoader::CancelSSLRequest(int error,
484 const net::SSLInfo* ssl_info) {
485 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
487 // The request can be NULL if it was cancelled by the renderer (as the
488 // request of the user navigating to a new page from the location bar).
489 if (!request_->is_pending())
490 return;
491 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
493 if (ssl_info) {
494 request_->CancelWithSSLError(error, *ssl_info);
495 } else {
496 request_->CancelWithError(error);
500 void ResourceLoader::ContinueSSLRequest() {
501 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
503 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
505 request_->ContinueDespiteLastError();
508 void ResourceLoader::Resume() {
509 DCHECK(!is_transferring_);
511 DeferredStage stage = deferred_stage_;
512 deferred_stage_ = DEFERRED_NONE;
513 switch (stage) {
514 case DEFERRED_NONE:
515 NOTREACHED();
516 break;
517 case DEFERRED_START:
518 StartRequestInternal();
519 break;
520 case DEFERRED_NETWORK_START:
521 request_->ResumeNetworkStart();
522 break;
523 case DEFERRED_REDIRECT:
524 request_->FollowDeferredRedirect();
525 break;
526 case DEFERRED_READ:
527 base::MessageLoop::current()->PostTask(
528 FROM_HERE,
529 base::Bind(&ResourceLoader::ResumeReading,
530 weak_ptr_factory_.GetWeakPtr()));
531 break;
532 case DEFERRED_RESPONSE_COMPLETE:
533 base::MessageLoop::current()->PostTask(
534 FROM_HERE,
535 base::Bind(&ResourceLoader::ResponseCompleted,
536 weak_ptr_factory_.GetWeakPtr()));
537 break;
538 case DEFERRED_FINISH:
539 // Delay self-destruction since we don't know how we were reached.
540 base::MessageLoop::current()->PostTask(
541 FROM_HERE,
542 base::Bind(&ResourceLoader::CallDidFinishLoading,
543 weak_ptr_factory_.GetWeakPtr()));
544 break;
548 void ResourceLoader::Cancel() {
549 CancelRequest(false);
552 void ResourceLoader::StartRequestInternal() {
553 DCHECK(!request_->is_pending());
555 if (!request_->status().is_success()) {
556 return;
559 request_->Start();
561 delegate_->DidStartRequest(this);
564 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
565 VLOG(1) << "CancelRequestInternal: " << request_->url().spec();
567 ResourceRequestInfoImpl* info = GetRequestInfo();
569 // WebKit will send us a cancel for downloads since it no longer handles
570 // them. In this case, ignore the cancel since we handle downloads in the
571 // browser.
572 if (from_renderer && (info->IsDownload() || info->is_stream()))
573 return;
575 if (from_renderer && info->detachable_handler()) {
576 // TODO(davidben): Fix Blink handling of prefetches so they are not
577 // cancelled on navigate away and end up in the local cache.
578 info->detachable_handler()->Detach();
579 return;
582 // TODO(darin): Perhaps we should really be looking to see if the status is
583 // IO_PENDING?
584 bool was_pending = request_->is_pending();
586 if (login_delegate_.get()) {
587 login_delegate_->OnRequestCancelled();
588 login_delegate_ = NULL;
590 if (ssl_client_auth_handler_.get()) {
591 ssl_client_auth_handler_->OnRequestCancelled();
592 ssl_client_auth_handler_ = NULL;
595 request_->CancelWithError(error);
597 if (!was_pending) {
598 // If the request isn't in flight, then we won't get an asynchronous
599 // notification from the request, so we have to signal ourselves to finish
600 // this request.
601 base::MessageLoop::current()->PostTask(
602 FROM_HERE,
603 base::Bind(&ResourceLoader::ResponseCompleted,
604 weak_ptr_factory_.GetWeakPtr()));
608 void ResourceLoader::StoreSignedCertificateTimestamps(
609 const net::SignedCertificateTimestampAndStatusList& sct_list,
610 int process_id,
611 SignedCertificateTimestampIDStatusList* sct_ids) {
612 SignedCertificateTimestampStore* sct_store(
613 SignedCertificateTimestampStore::GetInstance());
615 for (net::SignedCertificateTimestampAndStatusList::const_iterator iter =
616 sct_list.begin(); iter != sct_list.end(); ++iter) {
617 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
618 sct_ids->push_back(
619 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
623 void ResourceLoader::CompleteResponseStarted() {
624 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
625 tracked_objects::ScopedTracker tracking_profile1(
626 FROM_HERE_WITH_EXPLICIT_FUNCTION(
627 "423948 ResourceLoader::CompleteResponseStarted1"));
629 ResourceRequestInfoImpl* info = GetRequestInfo();
631 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
632 tracked_objects::ScopedTracker tracking_profile2(
633 FROM_HERE_WITH_EXPLICIT_FUNCTION(
634 "423948 ResourceLoader::CompleteResponseStarted2"));
636 scoped_refptr<ResourceResponse> response(new ResourceResponse());
637 PopulateResourceResponse(info, request_.get(), response.get());
639 if (request_->ssl_info().cert.get()) {
640 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
641 tracked_objects::ScopedTracker tracking_profile3(
642 FROM_HERE_WITH_EXPLICIT_FUNCTION(
643 "423948 ResourceLoader::CompleteResponseStarted3"));
645 int cert_id = CertStore::GetInstance()->StoreCert(
646 request_->ssl_info().cert.get(), info->GetChildID());
648 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
649 StoreSignedCertificateTimestamps(
650 request_->ssl_info().signed_certificate_timestamps,
651 info->GetChildID(),
652 &signed_certificate_timestamp_ids);
654 response->head.security_info = SerializeSecurityInfo(
655 cert_id,
656 request_->ssl_info().cert_status,
657 request_->ssl_info().security_bits,
658 request_->ssl_info().connection_status,
659 signed_certificate_timestamp_ids);
660 } else {
661 // We should not have any SSL state.
662 DCHECK(!request_->ssl_info().cert_status &&
663 request_->ssl_info().security_bits == -1 &&
664 !request_->ssl_info().connection_status);
667 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
668 tracked_objects::ScopedTracker tracking_profile5(
669 FROM_HERE_WITH_EXPLICIT_FUNCTION(
670 "423948 ResourceLoader::CompleteResponseStarted5"));
672 delegate_->DidReceiveResponse(this);
674 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
675 tracked_objects::ScopedTracker tracking_profile(
676 FROM_HERE_WITH_EXPLICIT_FUNCTION(
677 "423948 ResourceLoader::CompleteResponseStarted"));
679 bool defer = false;
680 if (!handler_->OnResponseStarted(response.get(), &defer)) {
681 Cancel();
682 } else if (defer) {
683 read_deferral_start_time_ = base::TimeTicks::Now();
684 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
688 void ResourceLoader::StartReading(bool is_continuation) {
689 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
690 tracked_objects::ScopedTracker tracking_profile(
691 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::StartReading"));
693 int bytes_read = 0;
694 ReadMore(&bytes_read);
696 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
697 if (request_->status().is_io_pending())
698 return;
700 if (!is_continuation || bytes_read <= 0) {
701 OnReadCompleted(request_.get(), bytes_read);
702 } else {
703 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
704 // thread in case the URLRequest can provide data synchronously.
705 base::MessageLoop::current()->PostTask(
706 FROM_HERE,
707 base::Bind(&ResourceLoader::OnReadCompleted,
708 weak_ptr_factory_.GetWeakPtr(),
709 request_.get(),
710 bytes_read));
714 void ResourceLoader::ResumeReading() {
715 DCHECK(!is_deferred());
717 if (!read_deferral_start_time_.is_null()) {
718 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
719 base::TimeTicks::Now() - read_deferral_start_time_);
720 read_deferral_start_time_ = base::TimeTicks();
722 if (request_->status().is_success()) {
723 StartReading(false); // Read the next chunk (OK to complete synchronously).
724 } else {
725 ResponseCompleted();
729 void ResourceLoader::ReadMore(int* bytes_read) {
730 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
731 tracked_objects::ScopedTracker tracking_profile1(
732 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore1"));
734 DCHECK(!is_deferred());
736 // Make sure we track the buffer in at least one place. This ensures it gets
737 // deleted even in the case the request has already finished its job and
738 // doesn't use the buffer.
739 scoped_refptr<net::IOBuffer> buf;
740 int buf_size;
742 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
743 tracked_objects::ScopedTracker tracking_profile2(
744 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore2"));
746 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
747 Cancel();
748 return;
752 DCHECK(buf.get());
753 DCHECK(buf_size > 0);
755 request_->Read(buf.get(), buf_size, bytes_read);
757 // No need to check the return value here as we'll detect errors by
758 // inspecting the URLRequest's status.
761 void ResourceLoader::CompleteRead(int bytes_read) {
762 DCHECK(bytes_read >= 0);
763 DCHECK(request_->status().is_success());
765 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
766 tracked_objects::ScopedTracker tracking_profile(
767 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::CompleteRead"));
769 bool defer = false;
770 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
771 Cancel();
772 } else if (defer) {
773 deferred_stage_ =
774 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
777 // Note: the request may still have been cancelled while OnReadCompleted
778 // returns true if OnReadCompleted caused request to get cancelled
779 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
780 // instance.)
783 void ResourceLoader::ResponseCompleted() {
784 VLOG(1) << "ResponseCompleted: " << request_->url().spec();
785 RecordHistograms();
786 ResourceRequestInfoImpl* info = GetRequestInfo();
788 std::string security_info;
789 const net::SSLInfo& ssl_info = request_->ssl_info();
790 if (ssl_info.cert.get() != NULL) {
791 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert.get(),
792 info->GetChildID());
793 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
794 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
795 info->GetChildID(),
796 &signed_certificate_timestamp_ids);
798 security_info = SerializeSecurityInfo(
799 cert_id, ssl_info.cert_status, ssl_info.security_bits,
800 ssl_info.connection_status, signed_certificate_timestamp_ids);
803 bool defer = false;
805 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
806 tracked_objects::ScopedTracker tracking_profile(
807 FROM_HERE_WITH_EXPLICIT_FUNCTION(
808 "423948 ResourceLoader::ResponseCompleted"));
810 handler_->OnResponseCompleted(request_->status(), security_info, &defer);
812 if (defer) {
813 // The handler is not ready to die yet. We will call DidFinishLoading when
814 // we resume.
815 deferred_stage_ = DEFERRED_FINISH;
816 } else {
817 // This will result in our destruction.
818 CallDidFinishLoading();
822 void ResourceLoader::CallDidFinishLoading() {
823 delegate_->DidFinishLoading(this);
826 void ResourceLoader::RecordHistograms() {
827 ResourceRequestInfoImpl* info = GetRequestInfo();
829 if (info->GetResourceType() == RESOURCE_TYPE_PREFETCH) {
830 PrefetchStatus status = STATUS_UNDEFINED;
831 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
833 switch (request_->status().status()) {
834 case net::URLRequestStatus::SUCCESS:
835 if (request_->was_cached()) {
836 status = STATUS_SUCCESS_FROM_CACHE;
837 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
838 total_time);
839 } else {
840 status = STATUS_SUCCESS_FROM_NETWORK;
841 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
842 total_time);
844 break;
845 case net::URLRequestStatus::CANCELED:
846 status = STATUS_CANCELED;
847 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
848 break;
849 case net::URLRequestStatus::IO_PENDING:
850 case net::URLRequestStatus::FAILED:
851 status = STATUS_UNDEFINED;
852 break;
855 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
859 void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
860 ssl_client_auth_handler_ = NULL;
861 request_->ContinueWithCertificate(cert);
864 } // namespace content