Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blobf8dcc0a7c3306ac806259cc44ad32d38e473d8a4
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 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.
104 handler_.reset();
107 void ResourceLoader::StartRequest() {
108 if (delegate_->HandleExternalProtocol(this, request_->url())) {
109 CancelAndIgnore();
110 return;
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)) {
122 Cancel();
123 return;
127 if (defer_start) {
128 deferred_stage_ = DEFERRED_START;
129 } else {
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
174 // fixed.
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());
196 if (handler)
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());
217 if (handler)
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,
238 bool* defer) {
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.
253 Cancel();
254 return;
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.
261 CancelAndIgnore();
262 return;
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)) {
274 Cancel();
275 } else if (*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();
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_)
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, this));
315 ssl_client_auth_handler_->SelectCertificate();
318 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
319 const net::SSLInfo& ssl_info,
320 bool fatal) {
321 ResourceRequestInfoImpl* info = GetRequestInfo();
323 int render_process_id;
324 int render_frame_id;
325 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
326 NOTREACHED();
328 SSLManager::OnSSLCertificateError(
329 weak_ptr_factory_.GetWeakPtr(),
330 info->GetResourceType(),
331 request_->url(),
332 render_process_id,
333 render_frame_id,
334 ssl_info,
335 fatal);
338 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
339 bool* defer) {
340 DCHECK_EQ(request_.get(), unused);
342 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
343 tracked_objects::ScopedTracker tracking_profile(
344 FROM_HERE_WITH_EXPLICIT_FUNCTION(
345 "423948 ResourceLoader::OnBeforeNetworkStart"));
347 // Give the handler a chance to delay the URLRequest from using the network.
348 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
349 Cancel();
350 return;
351 } else if (*defer) {
352 deferred_stage_ = DEFERRED_NETWORK_START;
356 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
357 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
358 tracked_objects::ScopedTracker tracking_profile(
359 FROM_HERE_WITH_EXPLICIT_FUNCTION(
360 "423948 ResourceLoader::OnResponseStarted"));
362 DCHECK_EQ(request_.get(), unused);
364 VLOG(1) << "OnResponseStarted: " << request_->url().spec();
366 // The CanLoadPage check should take place after any server redirects have
367 // finished, at the point in time that we know a page will commit in the
368 // renderer process.
369 ResourceRequestInfoImpl* info = GetRequestInfo();
370 ChildProcessSecurityPolicyImpl* policy =
371 ChildProcessSecurityPolicyImpl::GetInstance();
372 if (!policy->CanLoadPage(info->GetChildID(),
373 request_->url(),
374 info->GetResourceType())) {
375 Cancel();
376 return;
379 if (!request_->status().is_success()) {
380 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
381 tracked_objects::ScopedTracker tracking_profile1(
382 FROM_HERE_WITH_EXPLICIT_FUNCTION(
383 "423948 ResourceLoader::OnResponseStarted1"));
385 ResponseCompleted();
386 return;
389 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
390 tracked_objects::ScopedTracker tracking_profile2(
391 FROM_HERE_WITH_EXPLICIT_FUNCTION(
392 "423948 ResourceLoader::OnResponseStarted2"));
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 waiting_for_upload_progress_ack_ = false;
398 ReportUploadProgress();
400 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
401 tracked_objects::ScopedTracker tracking_profile3(
402 FROM_HERE_WITH_EXPLICIT_FUNCTION(
403 "423948 ResourceLoader::OnResponseStarted3"));
405 CompleteResponseStarted();
407 if (is_deferred())
408 return;
410 if (request_->status().is_success()) {
411 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
412 tracked_objects::ScopedTracker tracking_profile4(
413 FROM_HERE_WITH_EXPLICIT_FUNCTION(
414 "423948 ResourceLoader::OnResponseStarted4"));
416 StartReading(false); // Read the first chunk.
417 } else {
418 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
419 tracked_objects::ScopedTracker tracking_profile5(
420 FROM_HERE_WITH_EXPLICIT_FUNCTION(
421 "423948 ResourceLoader::OnResponseStarted5"));
423 ResponseCompleted();
427 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
428 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
429 tracked_objects::ScopedTracker tracking_profile(
430 FROM_HERE_WITH_EXPLICIT_FUNCTION(
431 "423948 ResourceLoader::OnReadCompleted"));
433 DCHECK_EQ(request_.get(), unused);
434 VLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
435 << " bytes_read = " << bytes_read;
437 // bytes_read == -1 always implies an error.
438 if (bytes_read == -1 || !request_->status().is_success()) {
439 tracked_objects::ScopedTracker tracking_profile1(
440 FROM_HERE_WITH_EXPLICIT_FUNCTION(
441 "423948 ResourceLoader::OnReadCompleted1"));
443 ResponseCompleted();
444 return;
447 tracked_objects::ScopedTracker tracking_profile2(
448 FROM_HERE_WITH_EXPLICIT_FUNCTION(
449 "423948 ResourceLoader::OnReadCompleted2"));
451 CompleteRead(bytes_read);
453 // If the handler cancelled or deferred the request, do not continue
454 // processing the read. If cancelled, the URLRequest has already been
455 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
456 // do nothing until resumed.
458 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
459 // ResponseCompleted().
460 if (is_deferred() || !request_->status().is_success())
461 return;
463 if (bytes_read > 0) {
464 tracked_objects::ScopedTracker tracking_profile3(
465 FROM_HERE_WITH_EXPLICIT_FUNCTION(
466 "423948 ResourceLoader::OnReadCompleted3"));
468 StartReading(true); // Read the next chunk.
469 } else {
470 tracked_objects::ScopedTracker tracking_profile4(
471 FROM_HERE_WITH_EXPLICIT_FUNCTION(
472 "423948 ResourceLoader::OnReadCompleted4"));
474 // URLRequest reported an EOF. Call ResponseCompleted.
475 DCHECK_EQ(0, bytes_read);
476 ResponseCompleted();
480 void ResourceLoader::CancelSSLRequest(int error,
481 const net::SSLInfo* ssl_info) {
482 DCHECK_CURRENTLY_ON(BrowserThread::IO);
484 // The request can be NULL if it was cancelled by the renderer (as the
485 // request of the user navigating to a new page from the location bar).
486 if (!request_->is_pending())
487 return;
488 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
490 if (ssl_info) {
491 request_->CancelWithSSLError(error, *ssl_info);
492 } else {
493 request_->CancelWithError(error);
497 void ResourceLoader::ContinueSSLRequest() {
498 DCHECK_CURRENTLY_ON(BrowserThread::IO);
500 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
502 request_->ContinueDespiteLastError();
505 void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
506 DCHECK(ssl_client_auth_handler_);
507 ssl_client_auth_handler_.reset();
508 request_->ContinueWithCertificate(cert);
511 void ResourceLoader::CancelCertificateSelection() {
512 DCHECK(ssl_client_auth_handler_);
513 ssl_client_auth_handler_.reset();
514 request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
517 void ResourceLoader::Resume() {
518 DCHECK(!is_transferring_);
520 DeferredStage stage = deferred_stage_;
521 deferred_stage_ = DEFERRED_NONE;
522 switch (stage) {
523 case DEFERRED_NONE:
524 NOTREACHED();
525 break;
526 case DEFERRED_START:
527 StartRequestInternal();
528 break;
529 case DEFERRED_NETWORK_START:
530 request_->ResumeNetworkStart();
531 break;
532 case DEFERRED_REDIRECT:
533 request_->FollowDeferredRedirect();
534 break;
535 case DEFERRED_READ:
536 base::MessageLoop::current()->PostTask(
537 FROM_HERE,
538 base::Bind(&ResourceLoader::ResumeReading,
539 weak_ptr_factory_.GetWeakPtr()));
540 break;
541 case DEFERRED_RESPONSE_COMPLETE:
542 base::MessageLoop::current()->PostTask(
543 FROM_HERE,
544 base::Bind(&ResourceLoader::ResponseCompleted,
545 weak_ptr_factory_.GetWeakPtr()));
546 break;
547 case DEFERRED_FINISH:
548 // Delay self-destruction since we don't know how we were reached.
549 base::MessageLoop::current()->PostTask(
550 FROM_HERE,
551 base::Bind(&ResourceLoader::CallDidFinishLoading,
552 weak_ptr_factory_.GetWeakPtr()));
553 break;
557 void ResourceLoader::Cancel() {
558 CancelRequest(false);
561 void ResourceLoader::StartRequestInternal() {
562 DCHECK(!request_->is_pending());
564 if (!request_->status().is_success()) {
565 return;
568 request_->Start();
570 delegate_->DidStartRequest(this);
573 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
574 VLOG(1) << "CancelRequestInternal: " << request_->url().spec();
576 ResourceRequestInfoImpl* info = GetRequestInfo();
578 // WebKit will send us a cancel for downloads since it no longer handles
579 // them. In this case, ignore the cancel since we handle downloads in the
580 // browser.
581 if (from_renderer && (info->IsDownload() || info->is_stream()))
582 return;
584 if (from_renderer && info->detachable_handler()) {
585 // TODO(davidben): Fix Blink handling of prefetches so they are not
586 // cancelled on navigate away and end up in the local cache.
587 info->detachable_handler()->Detach();
588 return;
591 // TODO(darin): Perhaps we should really be looking to see if the status is
592 // IO_PENDING?
593 bool was_pending = request_->is_pending();
595 if (login_delegate_.get()) {
596 login_delegate_->OnRequestCancelled();
597 login_delegate_ = NULL;
599 ssl_client_auth_handler_.reset();
601 request_->CancelWithError(error);
603 if (!was_pending) {
604 // If the request isn't in flight, then we won't get an asynchronous
605 // notification from the request, so we have to signal ourselves to finish
606 // this request.
607 base::MessageLoop::current()->PostTask(
608 FROM_HERE,
609 base::Bind(&ResourceLoader::ResponseCompleted,
610 weak_ptr_factory_.GetWeakPtr()));
614 void ResourceLoader::StoreSignedCertificateTimestamps(
615 const net::SignedCertificateTimestampAndStatusList& sct_list,
616 int process_id,
617 SignedCertificateTimestampIDStatusList* sct_ids) {
618 SignedCertificateTimestampStore* sct_store(
619 SignedCertificateTimestampStore::GetInstance());
621 for (net::SignedCertificateTimestampAndStatusList::const_iterator iter =
622 sct_list.begin(); iter != sct_list.end(); ++iter) {
623 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
624 sct_ids->push_back(
625 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
629 void ResourceLoader::CompleteResponseStarted() {
630 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
631 tracked_objects::ScopedTracker tracking_profile1(
632 FROM_HERE_WITH_EXPLICIT_FUNCTION(
633 "423948 ResourceLoader::CompleteResponseStarted1"));
635 ResourceRequestInfoImpl* info = GetRequestInfo();
637 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
638 tracked_objects::ScopedTracker tracking_profile2(
639 FROM_HERE_WITH_EXPLICIT_FUNCTION(
640 "423948 ResourceLoader::CompleteResponseStarted2"));
642 scoped_refptr<ResourceResponse> response(new ResourceResponse());
643 PopulateResourceResponse(info, request_.get(), response.get());
645 if (request_->ssl_info().cert.get()) {
646 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
647 tracked_objects::ScopedTracker tracking_profile3(
648 FROM_HERE_WITH_EXPLICIT_FUNCTION(
649 "423948 ResourceLoader::CompleteResponseStarted3"));
651 int cert_id = CertStore::GetInstance()->StoreCert(
652 request_->ssl_info().cert.get(), info->GetChildID());
654 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
655 StoreSignedCertificateTimestamps(
656 request_->ssl_info().signed_certificate_timestamps,
657 info->GetChildID(),
658 &signed_certificate_timestamp_ids);
660 response->head.security_info = SerializeSecurityInfo(
661 cert_id,
662 request_->ssl_info().cert_status,
663 request_->ssl_info().security_bits,
664 request_->ssl_info().connection_status,
665 signed_certificate_timestamp_ids);
666 } else {
667 // We should not have any SSL state.
668 DCHECK(!request_->ssl_info().cert_status &&
669 request_->ssl_info().security_bits == -1 &&
670 !request_->ssl_info().connection_status);
673 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
674 tracked_objects::ScopedTracker tracking_profile5(
675 FROM_HERE_WITH_EXPLICIT_FUNCTION(
676 "423948 ResourceLoader::CompleteResponseStarted5"));
678 delegate_->DidReceiveResponse(this);
680 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
681 tracked_objects::ScopedTracker tracking_profile(
682 FROM_HERE_WITH_EXPLICIT_FUNCTION(
683 "423948 ResourceLoader::CompleteResponseStarted"));
685 bool defer = false;
686 if (!handler_->OnResponseStarted(response.get(), &defer)) {
687 Cancel();
688 } else if (defer) {
689 read_deferral_start_time_ = base::TimeTicks::Now();
690 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
694 void ResourceLoader::StartReading(bool is_continuation) {
695 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
696 tracked_objects::ScopedTracker tracking_profile(
697 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::StartReading"));
699 int bytes_read = 0;
700 ReadMore(&bytes_read);
702 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
703 if (request_->status().is_io_pending())
704 return;
706 if (!is_continuation || bytes_read <= 0) {
707 OnReadCompleted(request_.get(), bytes_read);
708 } else {
709 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
710 // thread in case the URLRequest can provide data synchronously.
711 base::MessageLoop::current()->PostTask(
712 FROM_HERE,
713 base::Bind(&ResourceLoader::OnReadCompleted,
714 weak_ptr_factory_.GetWeakPtr(),
715 request_.get(),
716 bytes_read));
720 void ResourceLoader::ResumeReading() {
721 DCHECK(!is_deferred());
723 if (!read_deferral_start_time_.is_null()) {
724 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
725 base::TimeTicks::Now() - read_deferral_start_time_);
726 read_deferral_start_time_ = base::TimeTicks();
728 if (request_->status().is_success()) {
729 StartReading(false); // Read the next chunk (OK to complete synchronously).
730 } else {
731 ResponseCompleted();
735 void ResourceLoader::ReadMore(int* bytes_read) {
736 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
737 tracked_objects::ScopedTracker tracking_profile1(
738 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore1"));
740 DCHECK(!is_deferred());
742 // Make sure we track the buffer in at least one place. This ensures it gets
743 // deleted even in the case the request has already finished its job and
744 // doesn't use the buffer.
745 scoped_refptr<net::IOBuffer> buf;
746 int buf_size;
748 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
749 tracked_objects::ScopedTracker tracking_profile2(
750 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore2"));
752 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
753 Cancel();
754 return;
758 DCHECK(buf.get());
759 DCHECK(buf_size > 0);
761 request_->Read(buf.get(), buf_size, bytes_read);
763 // No need to check the return value here as we'll detect errors by
764 // inspecting the URLRequest's status.
767 void ResourceLoader::CompleteRead(int bytes_read) {
768 DCHECK(bytes_read >= 0);
769 DCHECK(request_->status().is_success());
771 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
772 tracked_objects::ScopedTracker tracking_profile(
773 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::CompleteRead"));
775 bool defer = false;
776 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
777 Cancel();
778 } else if (defer) {
779 deferred_stage_ =
780 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
783 // Note: the request may still have been cancelled while OnReadCompleted
784 // returns true if OnReadCompleted caused request to get cancelled
785 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
786 // instance.)
789 void ResourceLoader::ResponseCompleted() {
790 VLOG(1) << "ResponseCompleted: " << request_->url().spec();
791 RecordHistograms();
792 ResourceRequestInfoImpl* info = GetRequestInfo();
794 std::string security_info;
795 const net::SSLInfo& ssl_info = request_->ssl_info();
796 if (ssl_info.cert.get() != NULL) {
797 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert.get(),
798 info->GetChildID());
799 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
800 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
801 info->GetChildID(),
802 &signed_certificate_timestamp_ids);
804 security_info = SerializeSecurityInfo(
805 cert_id, ssl_info.cert_status, ssl_info.security_bits,
806 ssl_info.connection_status, signed_certificate_timestamp_ids);
809 bool defer = false;
811 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
812 tracked_objects::ScopedTracker tracking_profile(
813 FROM_HERE_WITH_EXPLICIT_FUNCTION(
814 "423948 ResourceLoader::ResponseCompleted"));
816 handler_->OnResponseCompleted(request_->status(), security_info, &defer);
818 if (defer) {
819 // The handler is not ready to die yet. We will call DidFinishLoading when
820 // we resume.
821 deferred_stage_ = DEFERRED_FINISH;
822 } else {
823 // This will result in our destruction.
824 CallDidFinishLoading();
828 void ResourceLoader::CallDidFinishLoading() {
829 delegate_->DidFinishLoading(this);
832 void ResourceLoader::RecordHistograms() {
833 ResourceRequestInfoImpl* info = GetRequestInfo();
835 if (info->GetResourceType() == RESOURCE_TYPE_PREFETCH) {
836 PrefetchStatus status = STATUS_UNDEFINED;
837 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
839 switch (request_->status().status()) {
840 case net::URLRequestStatus::SUCCESS:
841 if (request_->was_cached()) {
842 status = STATUS_SUCCESS_FROM_CACHE;
843 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
844 total_time);
845 } else {
846 status = STATUS_SUCCESS_FROM_NETWORK;
847 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
848 total_time);
850 break;
851 case net::URLRequestStatus::CANCELED:
852 status = STATUS_CANCELED;
853 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
854 break;
855 case net::URLRequestStatus::IO_PENDING:
856 case net::URLRequestStatus::FAILED:
857 status = STATUS_UNDEFINED;
858 break;
861 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
865 } // namespace content