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.
4
5 #include "content/browser/loader/resource_loader.h"
6
7 #include "base/command_line.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/time/time.h"
11 #include "content/browser/appcache/appcache_interceptor.h"
12 #include "content/browser/child_process_security_policy_impl.h"
13 #include "content/browser/loader/cross_site_resource_handler.h"
14 #include "content/browser/loader/detachable_resource_handler.h"
15 #include "content/browser/loader/resource_loader_delegate.h"
16 #include "content/browser/loader/resource_request_info_impl.h"
17 #include "content/browser/ssl/ssl_client_auth_handler.h"
18 #include "content/browser/ssl/ssl_manager.h"
19 #include "content/common/ssl_status_serialization.h"
20 #include "content/public/browser/cert_store.h"
21 #include "content/public/browser/resource_context.h"
22 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
23 #include "content/public/browser/signed_certificate_timestamp_store.h"
24 #include "content/public/common/content_client.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/process_type.h"
27 #include "content/public/common/resource_response.h"
28 #include "net/base/io_buffer.h"
29 #include "net/base/load_flags.h"
30 #include "net/http/http_response_headers.h"
31 #include "net/ssl/client_cert_store.h"
32 #include "net/url_request/url_request_status.h"
33
34 using base::TimeDelta;
35 using base::TimeTicks;
36
37 namespace content {
38 namespace {
39
PopulateResourceResponse(net::URLRequest * request,ResourceResponse * response)40 void PopulateResourceResponse(net::URLRequest* request,
41 ResourceResponse* response) {
42 response->head.error_code = request->status().error();
43 response->head.request_time = request->request_time();
44 response->head.response_time = request->response_time();
45 response->head.headers = request->response_headers();
46 request->GetCharset(&response->head.charset);
47 response->head.content_length = request->GetExpectedContentSize();
48 request->GetMimeType(&response->head.mime_type);
49 net::HttpResponseInfo response_info = request->response_info();
50 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
51 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
52 response->head.npn_negotiated_protocol =
53 response_info.npn_negotiated_protocol;
54 response->head.connection_info = response_info.connection_info;
55 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
56 response->head.socket_address = request->GetSocketAddress();
57 AppCacheInterceptor::GetExtraResponseInfo(
58 request,
59 &response->head.appcache_id,
60 &response->head.appcache_manifest_url);
61 // TODO(mmenke): Figure out if LOAD_ENABLE_LOAD_TIMING is safe to remove.
62 if (request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)
63 request->GetLoadTimingInfo(&response->head.load_timing);
64 }
65
66 } // namespace
67
ResourceLoader(scoped_ptr<net::URLRequest> request,scoped_ptr<ResourceHandler> handler,ResourceLoaderDelegate * delegate)68 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
69 scoped_ptr<ResourceHandler> handler,
70 ResourceLoaderDelegate* delegate)
71 : deferred_stage_(DEFERRED_NONE),
72 request_(request.Pass()),
73 handler_(handler.Pass()),
74 delegate_(delegate),
75 last_upload_position_(0),
76 waiting_for_upload_progress_ack_(false),
77 is_transferring_(false),
78 weak_ptr_factory_(this) {
79 request_->set_delegate(this);
80 handler_->SetController(this);
81 }
82
~ResourceLoader()83 ResourceLoader::~ResourceLoader() {
84 if (login_delegate_.get())
85 login_delegate_->OnRequestCancelled();
86 if (ssl_client_auth_handler_.get())
87 ssl_client_auth_handler_->OnRequestCancelled();
88
89 // Run ResourceHandler destructor before we tear-down the rest of our state
90 // as the ResourceHandler may want to inspect the URLRequest and other state.
91 handler_.reset();
92 }
93
StartRequest()94 void ResourceLoader::StartRequest() {
95 if (delegate_->HandleExternalProtocol(this, request_->url())) {
96 CancelAndIgnore();
97 return;
98 }
99
100 // Give the handler a chance to delay the URLRequest from being started.
101 bool defer_start = false;
102 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
103 Cancel();
104 return;
105 }
106
107 if (defer_start) {
108 deferred_stage_ = DEFERRED_START;
109 } else {
110 StartRequestInternal();
111 }
112 }
113
CancelRequest(bool from_renderer)114 void ResourceLoader::CancelRequest(bool from_renderer) {
115 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
116 }
117
CancelAndIgnore()118 void ResourceLoader::CancelAndIgnore() {
119 ResourceRequestInfoImpl* info = GetRequestInfo();
120 info->set_was_ignored_by_handler(true);
121 CancelRequest(false);
122 }
123
CancelWithError(int error_code)124 void ResourceLoader::CancelWithError(int error_code) {
125 CancelRequestInternal(error_code, false);
126 }
127
ReportUploadProgress()128 void ResourceLoader::ReportUploadProgress() {
129 if (waiting_for_upload_progress_ack_)
130 return; // Send one progress event at a time.
131
132 net::UploadProgress progress = request_->GetUploadProgress();
133 if (!progress.size())
134 return; // Nothing to upload.
135
136 if (progress.position() == last_upload_position_)
137 return; // No progress made since last time.
138
139 const uint64 kHalfPercentIncrements = 200;
140 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
141
142 uint64 amt_since_last = progress.position() - last_upload_position_;
143 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
144
145 bool is_finished = (progress.size() == progress.position());
146 bool enough_new_progress =
147 (amt_since_last > (progress.size() / kHalfPercentIncrements));
148 bool too_much_time_passed = time_since_last > kOneSecond;
149
150 if (is_finished || enough_new_progress || too_much_time_passed) {
151 if (request_->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
152 handler_->OnUploadProgress(progress.position(), progress.size());
153 waiting_for_upload_progress_ack_ = true;
154 }
155 last_upload_ticks_ = TimeTicks::Now();
156 last_upload_position_ = progress.position();
157 }
158 }
159
MarkAsTransferring()160 void ResourceLoader::MarkAsTransferring() {
161 CHECK(ResourceType::IsFrame(GetRequestInfo()->GetResourceType()))
162 << "Can only transfer for navigations";
163 is_transferring_ = true;
164 }
165
CompleteTransfer()166 void ResourceLoader::CompleteTransfer() {
167 // Although CrossSiteResourceHandler defers at OnResponseStarted
168 // (DEFERRED_READ), it may be seeing a replay of events via
169 // BufferedResourceHandler, and so the request itself is actually deferred at
170 // a later read stage.
171 DCHECK(DEFERRED_READ == deferred_stage_ ||
172 DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
173
174 is_transferring_ = false;
175 GetRequestInfo()->cross_site_handler()->ResumeResponse();
176 }
177
GetRequestInfo()178 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
179 return ResourceRequestInfoImpl::ForRequest(request_.get());
180 }
181
ClearLoginDelegate()182 void ResourceLoader::ClearLoginDelegate() {
183 login_delegate_ = NULL;
184 }
185
ClearSSLClientAuthHandler()186 void ResourceLoader::ClearSSLClientAuthHandler() {
187 ssl_client_auth_handler_ = NULL;
188 }
189
OnUploadProgressACK()190 void ResourceLoader::OnUploadProgressACK() {
191 waiting_for_upload_progress_ack_ = false;
192 }
193
OnReceivedRedirect(net::URLRequest * unused,const GURL & new_url,bool * defer)194 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
195 const GURL& new_url,
196 bool* defer) {
197 DCHECK_EQ(request_.get(), unused);
198
199 VLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
200 DCHECK(request_->status().is_success());
201
202 ResourceRequestInfoImpl* info = GetRequestInfo();
203
204 if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
205 !ChildProcessSecurityPolicyImpl::GetInstance()->
206 CanRequestURL(info->GetChildID(), new_url)) {
207 VLOG(1) << "Denied unauthorized request for "
208 << new_url.possibly_invalid_spec();
209
210 // Tell the renderer that this request was disallowed.
211 Cancel();
212 return;
213 }
214
215 delegate_->DidReceiveRedirect(this, new_url);
216
217 if (delegate_->HandleExternalProtocol(this, new_url)) {
218 // The request is complete so we can remove it.
219 CancelAndIgnore();
220 return;
221 }
222
223 scoped_refptr<ResourceResponse> response(new ResourceResponse());
224 PopulateResourceResponse(request_.get(), response.get());
225
226 if (!handler_->OnRequestRedirected(new_url, response.get(), defer)) {
227 Cancel();
228 } else if (*defer) {
229 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
230 }
231 }
232
OnAuthRequired(net::URLRequest * unused,net::AuthChallengeInfo * auth_info)233 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
234 net::AuthChallengeInfo* auth_info) {
235 DCHECK_EQ(request_.get(), unused);
236
237 if (request_->load_flags() & net::LOAD_DO_NOT_PROMPT_FOR_LOGIN) {
238 request_->CancelAuth();
239 return;
240 }
241
242 // Create a login dialog on the UI thread to get authentication data, or pull
243 // from cache and continue on the IO thread.
244
245 DCHECK(!login_delegate_.get())
246 << "OnAuthRequired called with login_delegate pending";
247 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
248 if (!login_delegate_.get())
249 request_->CancelAuth();
250 }
251
OnCertificateRequested(net::URLRequest * unused,net::SSLCertRequestInfo * cert_info)252 void ResourceLoader::OnCertificateRequested(
253 net::URLRequest* unused,
254 net::SSLCertRequestInfo* cert_info) {
255 DCHECK_EQ(request_.get(), unused);
256
257 if (request_->load_flags() & net::LOAD_PREFETCH) {
258 request_->Cancel();
259 return;
260 }
261
262 DCHECK(!ssl_client_auth_handler_.get())
263 << "OnCertificateRequested called with ssl_client_auth_handler pending";
264 ssl_client_auth_handler_ = new SSLClientAuthHandler(
265 GetRequestInfo()->GetContext()->CreateClientCertStore(),
266 request_.get(),
267 cert_info);
268 ssl_client_auth_handler_->SelectCertificate();
269 }
270
OnSSLCertificateError(net::URLRequest * request,const net::SSLInfo & ssl_info,bool fatal)271 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
272 const net::SSLInfo& ssl_info,
273 bool fatal) {
274 ResourceRequestInfoImpl* info = GetRequestInfo();
275
276 int render_process_id;
277 int render_frame_id;
278 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
279 NOTREACHED();
280
281 SSLManager::OnSSLCertificateError(
282 weak_ptr_factory_.GetWeakPtr(),
283 info->GetGlobalRequestID(),
284 info->GetResourceType(),
285 request_->url(),
286 render_process_id,
287 render_frame_id,
288 ssl_info,
289 fatal);
290 }
291
OnBeforeNetworkStart(net::URLRequest * unused,bool * defer)292 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
293 bool* defer) {
294 DCHECK_EQ(request_.get(), unused);
295
296 // Give the handler a chance to delay the URLRequest from using the network.
297 if (!handler_->OnBeforeNetworkStart(request_->url(), defer)) {
298 Cancel();
299 return;
300 } else if (*defer) {
301 deferred_stage_ = DEFERRED_NETWORK_START;
302 }
303 }
304
OnResponseStarted(net::URLRequest * unused)305 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
306 DCHECK_EQ(request_.get(), unused);
307
308 VLOG(1) << "OnResponseStarted: " << request_->url().spec();
309
310 // The CanLoadPage check should take place after any server redirects have
311 // finished, at the point in time that we know a page will commit in the
312 // renderer process.
313 ResourceRequestInfoImpl* info = GetRequestInfo();
314 ChildProcessSecurityPolicyImpl* policy =
315 ChildProcessSecurityPolicyImpl::GetInstance();
316 if (!policy->CanLoadPage(info->GetChildID(),
317 request_->url(),
318 info->GetResourceType())) {
319 Cancel();
320 return;
321 }
322
323 if (!request_->status().is_success()) {
324 ResponseCompleted();
325 return;
326 }
327
328 // We want to send a final upload progress message prior to sending the
329 // response complete message even if we're waiting for an ack to to a
330 // previous upload progress message.
331 waiting_for_upload_progress_ack_ = false;
332 ReportUploadProgress();
333
334 CompleteResponseStarted();
335
336 if (is_deferred())
337 return;
338
339 if (request_->status().is_success()) {
340 StartReading(false); // Read the first chunk.
341 } else {
342 ResponseCompleted();
343 }
344 }
345
OnReadCompleted(net::URLRequest * unused,int bytes_read)346 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
347 DCHECK_EQ(request_.get(), unused);
348 VLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
349 << " bytes_read = " << bytes_read;
350
351 // bytes_read == -1 always implies an error.
352 if (bytes_read == -1 || !request_->status().is_success()) {
353 ResponseCompleted();
354 return;
355 }
356
357 CompleteRead(bytes_read);
358
359 // If the handler cancelled or deferred the request, do not continue
360 // processing the read. If cancelled, the URLRequest has already been
361 // cancelled and will schedule an erroring OnReadCompleted later. If deferred,
362 // do nothing until resumed.
363 //
364 // Note: if bytes_read is 0 (EOF) and the handler defers, resumption will call
365 // ResponseCompleted().
366 if (is_deferred() || !request_->status().is_success())
367 return;
368
369 if (bytes_read > 0) {
370 StartReading(true); // Read the next chunk.
371 } else {
372 // URLRequest reported an EOF. Call ResponseCompleted.
373 DCHECK_EQ(0, bytes_read);
374 ResponseCompleted();
375 }
376 }
377
CancelSSLRequest(const GlobalRequestID & id,int error,const net::SSLInfo * ssl_info)378 void ResourceLoader::CancelSSLRequest(const GlobalRequestID& id,
379 int error,
380 const net::SSLInfo* ssl_info) {
381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
382
383 // The request can be NULL if it was cancelled by the renderer (as the
384 // request of the user navigating to a new page from the location bar).
385 if (!request_->is_pending())
386 return;
387 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
388
389 if (ssl_info) {
390 request_->CancelWithSSLError(error, *ssl_info);
391 } else {
392 request_->CancelWithError(error);
393 }
394 }
395
ContinueSSLRequest(const GlobalRequestID & id)396 void ResourceLoader::ContinueSSLRequest(const GlobalRequestID& id) {
397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
398
399 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
400
401 request_->ContinueDespiteLastError();
402 }
403
Resume()404 void ResourceLoader::Resume() {
405 DCHECK(!is_transferring_);
406
407 DeferredStage stage = deferred_stage_;
408 deferred_stage_ = DEFERRED_NONE;
409 switch (stage) {
410 case DEFERRED_NONE:
411 NOTREACHED();
412 break;
413 case DEFERRED_START:
414 StartRequestInternal();
415 break;
416 case DEFERRED_NETWORK_START:
417 request_->ResumeNetworkStart();
418 break;
419 case DEFERRED_REDIRECT:
420 request_->FollowDeferredRedirect();
421 break;
422 case DEFERRED_READ:
423 base::MessageLoop::current()->PostTask(
424 FROM_HERE,
425 base::Bind(&ResourceLoader::ResumeReading,
426 weak_ptr_factory_.GetWeakPtr()));
427 break;
428 case DEFERRED_RESPONSE_COMPLETE:
429 base::MessageLoop::current()->PostTask(
430 FROM_HERE,
431 base::Bind(&ResourceLoader::ResponseCompleted,
432 weak_ptr_factory_.GetWeakPtr()));
433 break;
434 case DEFERRED_FINISH:
435 // Delay self-destruction since we don't know how we were reached.
436 base::MessageLoop::current()->PostTask(
437 FROM_HERE,
438 base::Bind(&ResourceLoader::CallDidFinishLoading,
439 weak_ptr_factory_.GetWeakPtr()));
440 break;
441 }
442 }
443
Cancel()444 void ResourceLoader::Cancel() {
445 CancelRequest(false);
446 }
447
StartRequestInternal()448 void ResourceLoader::StartRequestInternal() {
449 DCHECK(!request_->is_pending());
450
451 if (!request_->status().is_success()) {
452 return;
453 }
454
455 request_->Start();
456
457 delegate_->DidStartRequest(this);
458 }
459
CancelRequestInternal(int error,bool from_renderer)460 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
461 VLOG(1) << "CancelRequestInternal: " << request_->url().spec();
462
463 ResourceRequestInfoImpl* info = GetRequestInfo();
464
465 // WebKit will send us a cancel for downloads since it no longer handles
466 // them. In this case, ignore the cancel since we handle downloads in the
467 // browser.
468 if (from_renderer && (info->IsDownload() || info->is_stream()))
469 return;
470
471 if (from_renderer && info->detachable_handler()) {
472 // TODO(davidben): Fix Blink handling of prefetches so they are not
473 // cancelled on navigate away and end up in the local cache.
474 info->detachable_handler()->Detach();
475 return;
476 }
477
478 // TODO(darin): Perhaps we should really be looking to see if the status is
479 // IO_PENDING?
480 bool was_pending = request_->is_pending();
481
482 if (login_delegate_.get()) {
483 login_delegate_->OnRequestCancelled();
484 login_delegate_ = NULL;
485 }
486 if (ssl_client_auth_handler_.get()) {
487 ssl_client_auth_handler_->OnRequestCancelled();
488 ssl_client_auth_handler_ = NULL;
489 }
490
491 request_->CancelWithError(error);
492
493 if (!was_pending) {
494 // If the request isn't in flight, then we won't get an asynchronous
495 // notification from the request, so we have to signal ourselves to finish
496 // this request.
497 base::MessageLoop::current()->PostTask(
498 FROM_HERE,
499 base::Bind(&ResourceLoader::ResponseCompleted,
500 weak_ptr_factory_.GetWeakPtr()));
501 }
502 }
503
StoreSignedCertificateTimestamps(const net::SignedCertificateTimestampAndStatusList & sct_list,int process_id,SignedCertificateTimestampIDStatusList * sct_ids)504 void ResourceLoader::StoreSignedCertificateTimestamps(
505 const net::SignedCertificateTimestampAndStatusList& sct_list,
506 int process_id,
507 SignedCertificateTimestampIDStatusList* sct_ids) {
508 SignedCertificateTimestampStore* sct_store(
509 SignedCertificateTimestampStore::GetInstance());
510
511 for (net::SignedCertificateTimestampAndStatusList::const_iterator iter =
512 sct_list.begin(); iter != sct_list.end(); ++iter) {
513 const int sct_id(sct_store->Store(iter->sct, process_id));
514 sct_ids->push_back(
515 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
516 }
517 }
518
CompleteResponseStarted()519 void ResourceLoader::CompleteResponseStarted() {
520 ResourceRequestInfoImpl* info = GetRequestInfo();
521
522 scoped_refptr<ResourceResponse> response(new ResourceResponse());
523 PopulateResourceResponse(request_.get(), response.get());
524
525 if (request_->ssl_info().cert.get()) {
526 int cert_id = CertStore::GetInstance()->StoreCert(
527 request_->ssl_info().cert.get(), info->GetChildID());
528
529 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
530 StoreSignedCertificateTimestamps(
531 request_->ssl_info().signed_certificate_timestamps,
532 info->GetChildID(),
533 &signed_certificate_timestamp_ids);
534
535 response->head.security_info = SerializeSecurityInfo(
536 cert_id,
537 request_->ssl_info().cert_status,
538 request_->ssl_info().security_bits,
539 request_->ssl_info().connection_status,
540 signed_certificate_timestamp_ids);
541 } else {
542 // We should not have any SSL state.
543 DCHECK(!request_->ssl_info().cert_status &&
544 request_->ssl_info().security_bits == -1 &&
545 !request_->ssl_info().connection_status);
546 }
547
548 delegate_->DidReceiveResponse(this);
549
550 bool defer = false;
551 if (!handler_->OnResponseStarted(response.get(), &defer)) {
552 Cancel();
553 } else if (defer) {
554 read_deferral_start_time_ = base::TimeTicks::Now();
555 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
556 }
557 }
558
StartReading(bool is_continuation)559 void ResourceLoader::StartReading(bool is_continuation) {
560 int bytes_read = 0;
561 ReadMore(&bytes_read);
562
563 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
564 if (request_->status().is_io_pending())
565 return;
566
567 if (!is_continuation || bytes_read <= 0) {
568 OnReadCompleted(request_.get(), bytes_read);
569 } else {
570 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
571 // thread in case the URLRequest can provide data synchronously.
572 base::MessageLoop::current()->PostTask(
573 FROM_HERE,
574 base::Bind(&ResourceLoader::OnReadCompleted,
575 weak_ptr_factory_.GetWeakPtr(),
576 request_.get(),
577 bytes_read));
578 }
579 }
580
ResumeReading()581 void ResourceLoader::ResumeReading() {
582 DCHECK(!is_deferred());
583
584 if (!read_deferral_start_time_.is_null()) {
585 UMA_HISTOGRAM_TIMES("Net.ResourceLoader.ReadDeferral",
586 base::TimeTicks::Now() - read_deferral_start_time_);
587 read_deferral_start_time_ = base::TimeTicks();
588 }
589 if (request_->status().is_success()) {
590 StartReading(false); // Read the next chunk (OK to complete synchronously).
591 } else {
592 ResponseCompleted();
593 }
594 }
595
ReadMore(int * bytes_read)596 void ResourceLoader::ReadMore(int* bytes_read) {
597 DCHECK(!is_deferred());
598
599 // Make sure we track the buffer in at least one place. This ensures it gets
600 // deleted even in the case the request has already finished its job and
601 // doesn't use the buffer.
602 scoped_refptr<net::IOBuffer> buf;
603 int buf_size;
604 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
605 Cancel();
606 return;
607 }
608
609 DCHECK(buf);
610 DCHECK(buf_size > 0);
611
612 request_->Read(buf.get(), buf_size, bytes_read);
613
614 // No need to check the return value here as we'll detect errors by
615 // inspecting the URLRequest's status.
616 }
617
CompleteRead(int bytes_read)618 void ResourceLoader::CompleteRead(int bytes_read) {
619 DCHECK(bytes_read >= 0);
620 DCHECK(request_->status().is_success());
621
622 bool defer = false;
623 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
624 Cancel();
625 } else if (defer) {
626 deferred_stage_ =
627 bytes_read > 0 ? DEFERRED_READ : DEFERRED_RESPONSE_COMPLETE;
628 }
629
630 // Note: the request may still have been cancelled while OnReadCompleted
631 // returns true if OnReadCompleted caused request to get cancelled
632 // out-of-band. (In AwResourceDispatcherHostDelegate::DownloadStarting, for
633 // instance.)
634 }
635
ResponseCompleted()636 void ResourceLoader::ResponseCompleted() {
637 VLOG(1) << "ResponseCompleted: " << request_->url().spec();
638 RecordHistograms();
639 ResourceRequestInfoImpl* info = GetRequestInfo();
640
641 std::string security_info;
642 const net::SSLInfo& ssl_info = request_->ssl_info();
643 if (ssl_info.cert.get() != NULL) {
644 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert.get(),
645 info->GetChildID());
646 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
647 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
648 info->GetChildID(),
649 &signed_certificate_timestamp_ids);
650
651 security_info = SerializeSecurityInfo(
652 cert_id, ssl_info.cert_status, ssl_info.security_bits,
653 ssl_info.connection_status, signed_certificate_timestamp_ids);
654 }
655
656 bool defer = false;
657 handler_->OnResponseCompleted(request_->status(), security_info, &defer);
658 if (defer) {
659 // The handler is not ready to die yet. We will call DidFinishLoading when
660 // we resume.
661 deferred_stage_ = DEFERRED_FINISH;
662 } else {
663 // This will result in our destruction.
664 CallDidFinishLoading();
665 }
666 }
667
CallDidFinishLoading()668 void ResourceLoader::CallDidFinishLoading() {
669 delegate_->DidFinishLoading(this);
670 }
671
RecordHistograms()672 void ResourceLoader::RecordHistograms() {
673 ResourceRequestInfoImpl* info = GetRequestInfo();
674
675 if (info->GetResourceType() == ResourceType::PREFETCH) {
676 PrefetchStatus status = STATUS_UNDEFINED;
677 TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
678
679 switch (request_->status().status()) {
680 case net::URLRequestStatus::SUCCESS:
681 if (request_->was_cached()) {
682 status = STATUS_SUCCESS_FROM_CACHE;
683 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromCache",
684 total_time);
685 } else {
686 status = STATUS_SUCCESS_FROM_NETWORK;
687 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeSpentPrefetchingFromNetwork",
688 total_time);
689 }
690 break;
691 case net::URLRequestStatus::CANCELED:
692 status = STATUS_CANCELED;
693 UMA_HISTOGRAM_TIMES("Net.Prefetch.TimeBeforeCancel", total_time);
694 break;
695 case net::URLRequestStatus::IO_PENDING:
696 case net::URLRequestStatus::FAILED:
697 status = STATUS_UNDEFINED;
698 break;
699 }
700
701 UMA_HISTOGRAM_ENUMERATION("Net.Prefetch.Pattern", status, STATUS_MAX);
702 }
703 }
704
705 } // namespace content
706