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
;
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(
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
);
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()),
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 ssl_client_auth_handler_
.reset();
102 // Run ResourceHandler destructor before we tear-down the rest of our state
103 // as the ResourceHandler may want to inspect the URLRequest and other state.
107 void ResourceLoader::StartRequest() {
108 if (delegate_
->HandleExternalProtocol(this, request_
->url())) {
113 // Give the handler a chance to delay the URLRequest from being started.
114 bool defer_start
= false;
116 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
117 tracked_objects::ScopedTracker
tracking_profile(
118 FROM_HERE_WITH_EXPLICIT_FUNCTION(
119 "423948 ResourceLoader::StartRequest"));
121 if (!handler_
->OnWillStart(request_
->url(), &defer_start
)) {
128 deferred_stage_
= DEFERRED_START
;
130 StartRequestInternal();
134 void ResourceLoader::CancelRequest(bool from_renderer
) {
135 CancelRequestInternal(net::ERR_ABORTED
, from_renderer
);
138 void ResourceLoader::CancelAndIgnore() {
139 ResourceRequestInfoImpl
* info
= GetRequestInfo();
140 info
->set_was_ignored_by_handler(true);
141 CancelRequest(false);
144 void ResourceLoader::CancelWithError(int error_code
) {
145 CancelRequestInternal(error_code
, false);
148 void ResourceLoader::ReportUploadProgress() {
149 if (waiting_for_upload_progress_ack_
)
150 return; // Send one progress event at a time.
152 net::UploadProgress progress
= request_
->GetUploadProgress();
153 if (!progress
.size())
154 return; // Nothing to upload.
156 if (progress
.position() == last_upload_position_
)
157 return; // No progress made since last time.
159 const uint64 kHalfPercentIncrements
= 200;
160 const TimeDelta kOneSecond
= TimeDelta::FromMilliseconds(1000);
162 uint64 amt_since_last
= progress
.position() - last_upload_position_
;
163 TimeDelta time_since_last
= TimeTicks::Now() - last_upload_ticks_
;
165 bool is_finished
= (progress
.size() == progress
.position());
166 bool enough_new_progress
=
167 (amt_since_last
> (progress
.size() / kHalfPercentIncrements
));
168 bool too_much_time_passed
= time_since_last
> kOneSecond
;
170 if (is_finished
|| enough_new_progress
|| too_much_time_passed
) {
171 ResourceRequestInfoImpl
* info
= GetRequestInfo();
172 if (info
->is_upload_progress_enabled()) {
173 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is
175 tracked_objects::ScopedTracker
tracking_profile(
176 FROM_HERE_WITH_EXPLICIT_FUNCTION(
177 "423948 ResourceLoader::ReportUploadProgress"));
179 handler_
->OnUploadProgress(progress
.position(), progress
.size());
180 waiting_for_upload_progress_ack_
= true;
182 last_upload_ticks_
= TimeTicks::Now();
183 last_upload_position_
= progress
.position();
187 void ResourceLoader::MarkAsTransferring() {
188 CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
189 << "Can only transfer for navigations";
190 is_transferring_
= true;
192 int child_id
= GetRequestInfo()->GetChildID();
193 AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id
);
194 ServiceWorkerRequestHandler
* handler
=
195 ServiceWorkerRequestHandler::GetHandler(request());
197 handler
->PrepareForCrossSiteTransfer(child_id
);
200 void ResourceLoader::CompleteTransfer() {
201 // Although CrossSiteResourceHandler defers at OnResponseStarted
202 // (DEFERRED_READ), it may be seeing a replay of events via
203 // BufferedResourceHandler, and so the request itself is actually deferred at
204 // a later read stage.
205 DCHECK(DEFERRED_READ
== deferred_stage_
||
206 DEFERRED_RESPONSE_COMPLETE
== deferred_stage_
);
207 DCHECK(is_transferring_
);
209 // In some cases, a process transfer doesn't really happen and the
210 // request is resumed in the original process. Real transfers to a new process
211 // are completed via ResourceDispatcherHostImpl::UpdateRequestForTransfer.
212 int child_id
= GetRequestInfo()->GetChildID();
213 AppCacheInterceptor::MaybeCompleteCrossSiteTransferInOldProcess(
214 request(), child_id
);
215 ServiceWorkerRequestHandler
* handler
=
216 ServiceWorkerRequestHandler::GetHandler(request());
218 handler
->MaybeCompleteCrossSiteTransferInOldProcess(child_id
);
220 is_transferring_
= false;
221 GetRequestInfo()->cross_site_handler()->ResumeResponse();
224 ResourceRequestInfoImpl
* ResourceLoader::GetRequestInfo() {
225 return ResourceRequestInfoImpl::ForRequest(request_
.get());
228 void ResourceLoader::ClearLoginDelegate() {
229 login_delegate_
= NULL
;
232 void ResourceLoader::OnUploadProgressACK() {
233 waiting_for_upload_progress_ack_
= false;
236 void ResourceLoader::OnReceivedRedirect(net::URLRequest
* unused
,
237 const net::RedirectInfo
& redirect_info
,
239 DCHECK_EQ(request_
.get(), unused
);
241 VLOG(1) << "OnReceivedRedirect: " << request_
->url().spec();
242 DCHECK(request_
->status().is_success());
244 ResourceRequestInfoImpl
* info
= GetRequestInfo();
246 if (info
->GetProcessType() != PROCESS_TYPE_PLUGIN
&&
247 !ChildProcessSecurityPolicyImpl::GetInstance()->
248 CanRequestURL(info
->GetChildID(), redirect_info
.new_url
)) {
249 VLOG(1) << "Denied unauthorized request for "
250 << redirect_info
.new_url
.possibly_invalid_spec();
252 // Tell the renderer that this request was disallowed.
257 delegate_
->DidReceiveRedirect(this, redirect_info
.new_url
);
259 if (delegate_
->HandleExternalProtocol(this, redirect_info
.new_url
)) {
260 // The request is complete so we can remove it.
265 scoped_refptr
<ResourceResponse
> response(new ResourceResponse());
266 PopulateResourceResponse(info
, request_
.get(), response
.get());
268 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
269 tracked_objects::ScopedTracker
tracking_profile(
270 FROM_HERE_WITH_EXPLICIT_FUNCTION(
271 "423948 ResourceLoader::OnReceivedRedirect"));
273 if (!handler_
->OnRequestRedirected(redirect_info
, response
.get(), defer
)) {
276 deferred_stage_
= DEFERRED_REDIRECT
; // Follow redirect when resumed.
280 void ResourceLoader::OnAuthRequired(net::URLRequest
* unused
,
281 net::AuthChallengeInfo
* auth_info
) {
282 DCHECK_EQ(request_
.get(), unused
);
284 ResourceRequestInfoImpl
* info
= GetRequestInfo();
285 if (info
->do_not_prompt_for_login()) {
286 request_
->CancelAuth();
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
) {
310 DCHECK(!ssl_client_auth_handler_
)
311 << "OnCertificateRequested called with ssl_client_auth_handler pending";
312 ssl_client_auth_handler_
.reset(new SSLClientAuthHandler(
313 GetRequestInfo()->GetContext()->CreateClientCertStore(), request_
.get(),
314 cert_info
, base::Bind(&ResourceLoader::ContinueWithCertificate
,
315 weak_ptr_factory_
.GetWeakPtr())));
316 ssl_client_auth_handler_
->SelectCertificate();
319 void ResourceLoader::OnSSLCertificateError(net::URLRequest
* request
,
320 const net::SSLInfo
& ssl_info
,
322 ResourceRequestInfoImpl
* info
= GetRequestInfo();
324 int render_process_id
;
326 if (!info
->GetAssociatedRenderFrame(&render_process_id
, &render_frame_id
))
329 SSLManager::OnSSLCertificateError(
330 weak_ptr_factory_
.GetWeakPtr(),
331 info
->GetResourceType(),
339 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest
* unused
,
341 DCHECK_EQ(request_
.get(), unused
);
343 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
344 tracked_objects::ScopedTracker
tracking_profile(
345 FROM_HERE_WITH_EXPLICIT_FUNCTION(
346 "423948 ResourceLoader::OnBeforeNetworkStart"));
348 // Give the handler a chance to delay the URLRequest from using the network.
349 if (!handler_
->OnBeforeNetworkStart(request_
->url(), defer
)) {
353 deferred_stage_
= DEFERRED_NETWORK_START
;
357 void ResourceLoader::OnResponseStarted(net::URLRequest
* unused
) {
358 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
359 tracked_objects::ScopedTracker
tracking_profile(
360 FROM_HERE_WITH_EXPLICIT_FUNCTION(
361 "423948 ResourceLoader::OnResponseStarted"));
363 DCHECK_EQ(request_
.get(), unused
);
365 VLOG(1) << "OnResponseStarted: " << request_
->url().spec();
367 // The CanLoadPage check should take place after any server redirects have
368 // finished, at the point in time that we know a page will commit in the
370 ResourceRequestInfoImpl
* info
= GetRequestInfo();
371 ChildProcessSecurityPolicyImpl
* policy
=
372 ChildProcessSecurityPolicyImpl::GetInstance();
373 if (!policy
->CanLoadPage(info
->GetChildID(),
375 info
->GetResourceType())) {
380 if (!request_
->status().is_success()) {
381 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
382 tracked_objects::ScopedTracker
tracking_profile1(
383 FROM_HERE_WITH_EXPLICIT_FUNCTION(
384 "423948 ResourceLoader::OnResponseStarted1"));
390 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
391 tracked_objects::ScopedTracker
tracking_profile2(
392 FROM_HERE_WITH_EXPLICIT_FUNCTION(
393 "423948 ResourceLoader::OnResponseStarted2"));
395 // We want to send a final upload progress message prior to sending the
396 // response complete message even if we're waiting for an ack to to a
397 // previous upload progress message.
398 waiting_for_upload_progress_ack_
= false;
399 ReportUploadProgress();
401 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
402 tracked_objects::ScopedTracker
tracking_profile3(
403 FROM_HERE_WITH_EXPLICIT_FUNCTION(
404 "423948 ResourceLoader::OnResponseStarted3"));
406 CompleteResponseStarted();
411 if (request_
->status().is_success()) {
412 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
413 tracked_objects::ScopedTracker
tracking_profile4(
414 FROM_HERE_WITH_EXPLICIT_FUNCTION(
415 "423948 ResourceLoader::OnResponseStarted4"));
417 StartReading(false); // Read the first chunk.
419 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
420 tracked_objects::ScopedTracker
tracking_profile5(
421 FROM_HERE_WITH_EXPLICIT_FUNCTION(
422 "423948 ResourceLoader::OnResponseStarted5"));
428 void ResourceLoader::OnReadCompleted(net::URLRequest
* unused
, int bytes_read
) {
429 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
430 tracked_objects::ScopedTracker
tracking_profile(
431 FROM_HERE_WITH_EXPLICIT_FUNCTION(
432 "423948 ResourceLoader::OnReadCompleted"));
434 DCHECK_EQ(request_
.get(), unused
);
435 VLOG(1) << "OnReadCompleted: \"" << request_
->url().spec() << "\""
436 << " bytes_read = " << bytes_read
;
438 // bytes_read == -1 always implies an error.
439 if (bytes_read
== -1 || !request_
->status().is_success()) {
440 tracked_objects::ScopedTracker
tracking_profile1(
441 FROM_HERE_WITH_EXPLICIT_FUNCTION(
442 "423948 ResourceLoader::OnReadCompleted1"));
448 tracked_objects::ScopedTracker
tracking_profile2(
449 FROM_HERE_WITH_EXPLICIT_FUNCTION(
450 "423948 ResourceLoader::OnReadCompleted2"));
452 CompleteRead(bytes_read
);
454 // If the handler cancelled or deferred the request, do not continue
455 // processing the read. If cancelled, the URLRequest has already been
456 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
457 // do nothing until resumed.
459 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
460 // ResponseCompleted().
461 if (is_deferred() || !request_
->status().is_success())
464 if (bytes_read
> 0) {
465 tracked_objects::ScopedTracker
tracking_profile3(
466 FROM_HERE_WITH_EXPLICIT_FUNCTION(
467 "423948 ResourceLoader::OnReadCompleted3"));
469 StartReading(true); // Read the next chunk.
471 tracked_objects::ScopedTracker
tracking_profile4(
472 FROM_HERE_WITH_EXPLICIT_FUNCTION(
473 "423948 ResourceLoader::OnReadCompleted4"));
475 // URLRequest reported an EOF. Call ResponseCompleted.
476 DCHECK_EQ(0, bytes_read
);
481 void ResourceLoader::CancelSSLRequest(int error
,
482 const net::SSLInfo
* ssl_info
) {
483 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
485 // The request can be NULL if it was cancelled by the renderer (as the
486 // request of the user navigating to a new page from the location bar).
487 if (!request_
->is_pending())
489 DVLOG(1) << "CancelSSLRequest() url: " << request_
->url().spec();
492 request_
->CancelWithSSLError(error
, *ssl_info
);
494 request_
->CancelWithError(error
);
498 void ResourceLoader::ContinueSSLRequest() {
499 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
501 DVLOG(1) << "ContinueSSLRequest() url: " << request_
->url().spec();
503 request_
->ContinueDespiteLastError();
506 void ResourceLoader::Resume() {
507 DCHECK(!is_transferring_
);
509 DeferredStage stage
= deferred_stage_
;
510 deferred_stage_
= DEFERRED_NONE
;
516 StartRequestInternal();
518 case DEFERRED_NETWORK_START
:
519 request_
->ResumeNetworkStart();
521 case DEFERRED_REDIRECT
:
522 request_
->FollowDeferredRedirect();
525 base::MessageLoop::current()->PostTask(
527 base::Bind(&ResourceLoader::ResumeReading
,
528 weak_ptr_factory_
.GetWeakPtr()));
530 case DEFERRED_RESPONSE_COMPLETE
:
531 base::MessageLoop::current()->PostTask(
533 base::Bind(&ResourceLoader::ResponseCompleted
,
534 weak_ptr_factory_
.GetWeakPtr()));
536 case DEFERRED_FINISH
:
537 // Delay self-destruction since we don't know how we were reached.
538 base::MessageLoop::current()->PostTask(
540 base::Bind(&ResourceLoader::CallDidFinishLoading
,
541 weak_ptr_factory_
.GetWeakPtr()));
546 void ResourceLoader::Cancel() {
547 CancelRequest(false);
550 void ResourceLoader::StartRequestInternal() {
551 DCHECK(!request_
->is_pending());
553 if (!request_
->status().is_success()) {
559 delegate_
->DidStartRequest(this);
562 void ResourceLoader::CancelRequestInternal(int error
, bool from_renderer
) {
563 VLOG(1) << "CancelRequestInternal: " << request_
->url().spec();
565 ResourceRequestInfoImpl
* info
= GetRequestInfo();
567 // WebKit will send us a cancel for downloads since it no longer handles
568 // them. In this case, ignore the cancel since we handle downloads in the
570 if (from_renderer
&& (info
->IsDownload() || info
->is_stream()))
573 if (from_renderer
&& info
->detachable_handler()) {
574 // TODO(davidben): Fix Blink handling of prefetches so they are not
575 // cancelled on navigate away and end up in the local cache.
576 info
->detachable_handler()->Detach();
580 // TODO(darin): Perhaps we should really be looking to see if the status is
582 bool was_pending
= request_
->is_pending();
584 if (login_delegate_
.get()) {
585 login_delegate_
->OnRequestCancelled();
586 login_delegate_
= NULL
;
588 ssl_client_auth_handler_
.reset();
590 request_
->CancelWithError(error
);
593 // If the request isn't in flight, then we won't get an asynchronous
594 // notification from the request, so we have to signal ourselves to finish
596 base::MessageLoop::current()->PostTask(
598 base::Bind(&ResourceLoader::ResponseCompleted
,
599 weak_ptr_factory_
.GetWeakPtr()));
603 void ResourceLoader::StoreSignedCertificateTimestamps(
604 const net::SignedCertificateTimestampAndStatusList
& sct_list
,
606 SignedCertificateTimestampIDStatusList
* sct_ids
) {
607 SignedCertificateTimestampStore
* sct_store(
608 SignedCertificateTimestampStore::GetInstance());
610 for (net::SignedCertificateTimestampAndStatusList::const_iterator iter
=
611 sct_list
.begin(); iter
!= sct_list
.end(); ++iter
) {
612 const int sct_id(sct_store
->Store(iter
->sct
.get(), process_id
));
614 SignedCertificateTimestampIDAndStatus(sct_id
, iter
->status
));
618 void ResourceLoader::CompleteResponseStarted() {
619 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
620 tracked_objects::ScopedTracker
tracking_profile1(
621 FROM_HERE_WITH_EXPLICIT_FUNCTION(
622 "423948 ResourceLoader::CompleteResponseStarted1"));
624 ResourceRequestInfoImpl
* info
= GetRequestInfo();
626 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
627 tracked_objects::ScopedTracker
tracking_profile2(
628 FROM_HERE_WITH_EXPLICIT_FUNCTION(
629 "423948 ResourceLoader::CompleteResponseStarted2"));
631 scoped_refptr
<ResourceResponse
> response(new ResourceResponse());
632 PopulateResourceResponse(info
, request_
.get(), response
.get());
634 if (request_
->ssl_info().cert
.get()) {
635 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
636 tracked_objects::ScopedTracker
tracking_profile3(
637 FROM_HERE_WITH_EXPLICIT_FUNCTION(
638 "423948 ResourceLoader::CompleteResponseStarted3"));
640 int cert_id
= CertStore::GetInstance()->StoreCert(
641 request_
->ssl_info().cert
.get(), info
->GetChildID());
643 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids
;
644 StoreSignedCertificateTimestamps(
645 request_
->ssl_info().signed_certificate_timestamps
,
647 &signed_certificate_timestamp_ids
);
649 response
->head
.security_info
= SerializeSecurityInfo(
651 request_
->ssl_info().cert_status
,
652 request_
->ssl_info().security_bits
,
653 request_
->ssl_info().connection_status
,
654 signed_certificate_timestamp_ids
);
656 // We should not have any SSL state.
657 DCHECK(!request_
->ssl_info().cert_status
&&
658 request_
->ssl_info().security_bits
== -1 &&
659 !request_
->ssl_info().connection_status
);
662 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
663 tracked_objects::ScopedTracker
tracking_profile5(
664 FROM_HERE_WITH_EXPLICIT_FUNCTION(
665 "423948 ResourceLoader::CompleteResponseStarted5"));
667 delegate_
->DidReceiveResponse(this);
669 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
670 tracked_objects::ScopedTracker
tracking_profile(
671 FROM_HERE_WITH_EXPLICIT_FUNCTION(
672 "423948 ResourceLoader::CompleteResponseStarted"));
675 if (!handler_
->OnResponseStarted(response
.get(), &defer
)) {
678 read_deferral_start_time_
= base::TimeTicks::Now();
679 deferred_stage_
= DEFERRED_READ
; // Read first chunk when resumed.
683 void ResourceLoader::StartReading(bool is_continuation
) {
684 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
685 tracked_objects::ScopedTracker
tracking_profile(
686 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::StartReading"));
689 ReadMore(&bytes_read
);
691 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
692 if (request_
->status().is_io_pending())
695 if (!is_continuation
|| bytes_read
<= 0) {
696 OnReadCompleted(request_
.get(), bytes_read
);
698 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
699 // thread in case the URLRequest can provide data synchronously.
700 base::MessageLoop::current()->PostTask(
702 base::Bind(&ResourceLoader::OnReadCompleted
,
703 weak_ptr_factory_
.GetWeakPtr(),
709 void ResourceLoader::ResumeReading() {
710 DCHECK(!is_deferred());
712 if (!read_deferral_start_time_
.is_null()) {
713 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
714 base::TimeTicks::Now() - read_deferral_start_time_
);
715 read_deferral_start_time_
= base::TimeTicks();
717 if (request_
->status().is_success()) {
718 StartReading(false); // Read the next chunk (OK to complete synchronously).
724 void ResourceLoader::ReadMore(int* bytes_read
) {
725 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
726 tracked_objects::ScopedTracker
tracking_profile1(
727 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore1"));
729 DCHECK(!is_deferred());
731 // Make sure we track the buffer in at least one place. This ensures it gets
732 // deleted even in the case the request has already finished its job and
733 // doesn't use the buffer.
734 scoped_refptr
<net::IOBuffer
> buf
;
737 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
738 tracked_objects::ScopedTracker
tracking_profile2(
739 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore2"));
741 if (!handler_
->OnWillRead(&buf
, &buf_size
, -1)) {
748 DCHECK(buf_size
> 0);
750 request_
->Read(buf
.get(), buf_size
, bytes_read
);
752 // No need to check the return value here as we'll detect errors by
753 // inspecting the URLRequest's status.
756 void ResourceLoader::CompleteRead(int bytes_read
) {
757 DCHECK(bytes_read
>= 0);
758 DCHECK(request_
->status().is_success());
760 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
761 tracked_objects::ScopedTracker
tracking_profile(
762 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::CompleteRead"));
765 if (!handler_
->OnReadCompleted(bytes_read
, &defer
)) {
769 bytes_read
> 0 ? DEFERRED_READ
: DEFERRED_RESPONSE_COMPLETE
;
772 // Note: the request may still have been cancelled while OnReadCompleted
773 // returns true if OnReadCompleted caused request to get cancelled
774 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
778 void ResourceLoader::ResponseCompleted() {
779 VLOG(1) << "ResponseCompleted: " << request_
->url().spec();
781 ResourceRequestInfoImpl
* info
= GetRequestInfo();
783 std::string security_info
;
784 const net::SSLInfo
& ssl_info
= request_
->ssl_info();
785 if (ssl_info
.cert
.get() != NULL
) {
786 int cert_id
= CertStore::GetInstance()->StoreCert(ssl_info
.cert
.get(),
788 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids
;
789 StoreSignedCertificateTimestamps(ssl_info
.signed_certificate_timestamps
,
791 &signed_certificate_timestamp_ids
);
793 security_info
= SerializeSecurityInfo(
794 cert_id
, ssl_info
.cert_status
, ssl_info
.security_bits
,
795 ssl_info
.connection_status
, signed_certificate_timestamp_ids
);
800 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
801 tracked_objects::ScopedTracker
tracking_profile(
802 FROM_HERE_WITH_EXPLICIT_FUNCTION(
803 "423948 ResourceLoader::ResponseCompleted"));
805 handler_
->OnResponseCompleted(request_
->status(), security_info
, &defer
);
808 // The handler is not ready to die yet. We will call DidFinishLoading when
810 deferred_stage_
= DEFERRED_FINISH
;
812 // This will result in our destruction.
813 CallDidFinishLoading();
817 void ResourceLoader::CallDidFinishLoading() {
818 delegate_
->DidFinishLoading(this);
821 void ResourceLoader::RecordHistograms() {
822 ResourceRequestInfoImpl
* info
= GetRequestInfo();
824 if (info
->GetResourceType() == RESOURCE_TYPE_PREFETCH
) {
825 PrefetchStatus status
= STATUS_UNDEFINED
;
826 TimeDelta total_time
= base::TimeTicks::Now() - request_
->creation_time();
828 switch (request_
->status().status()) {
829 case net::URLRequestStatus::SUCCESS
:
830 if (request_
->was_cached()) {
831 status
= STATUS_SUCCESS_FROM_CACHE
;
832 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
835 status
= STATUS_SUCCESS_FROM_NETWORK
;
836 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
840 case net::URLRequestStatus::CANCELED
:
841 status
= STATUS_CANCELED
;
842 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time
);
844 case net::URLRequestStatus::IO_PENDING
:
845 case net::URLRequestStatus::FAILED
:
846 status
= STATUS_UNDEFINED
;
850 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status
, STATUS_MAX
);
854 void ResourceLoader::ContinueWithCertificate(net::X509Certificate
* cert
) {
855 ssl_client_auth_handler_
.reset();
856 request_
->ContinueWithCertificate(cert
);
859 } // namespace content