[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / content / browser / loader / resource_loader.cc
blob4c4959005a73a21b8bc4518ffc1723bb77b19040
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.h"
9 #include "base/time.h"
10 #include "content/browser/child_process_security_policy_impl.h"
11 #include "content/browser/loader/doomed_resource_handler.h"
12 #include "content/browser/loader/resource_loader_delegate.h"
13 #include "content/browser/loader/resource_request_info_impl.h"
14 #include "content/browser/ssl/ssl_client_auth_handler.h"
15 #include "content/browser/ssl/ssl_manager.h"
16 #include "content/common/ssl_status_serialization.h"
17 #include "content/public/browser/cert_store.h"
18 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
19 #include "content/public/common/content_client.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/common/resource_response.h"
22 #include "net/base/load_flags.h"
23 #include "net/http/http_response_headers.h"
24 #include "webkit/appcache/appcache_interceptor.h"
26 using base::TimeDelta;
27 using base::TimeTicks;
29 namespace content {
30 namespace {
32 void PopulateResourceResponse(net::URLRequest* request,
33 ResourceResponse* response) {
34 response->head.error_code = request->status().error();
35 response->head.request_time = request->request_time();
36 response->head.response_time = request->response_time();
37 response->head.headers = request->response_headers();
38 request->GetCharset(&response->head.charset);
39 response->head.content_length = request->GetExpectedContentSize();
40 request->GetMimeType(&response->head.mime_type);
41 net::HttpResponseInfo response_info = request->response_info();
42 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
43 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
44 response->head.npn_negotiated_protocol =
45 response_info.npn_negotiated_protocol;
46 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
47 response->head.socket_address = request->GetSocketAddress();
48 appcache::AppCacheInterceptor::GetExtraResponseInfo(
49 request,
50 &response->head.appcache_id,
51 &response->head.appcache_manifest_url);
54 } // namespace
56 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
57 scoped_ptr<ResourceHandler> handler,
58 ResourceLoaderDelegate* delegate)
59 : deferred_stage_(DEFERRED_NONE),
60 request_(request.Pass()),
61 handler_(handler.Pass()),
62 delegate_(delegate),
63 last_upload_position_(0),
64 waiting_for_upload_progress_ack_(false),
65 is_transferring_(false),
66 weak_ptr_factory_(this) {
67 request_->set_delegate(this);
68 handler_->SetController(this);
71 ResourceLoader::~ResourceLoader() {
72 if (login_delegate_)
73 login_delegate_->OnRequestCancelled();
74 if (ssl_client_auth_handler_)
75 ssl_client_auth_handler_->OnRequestCancelled();
77 // Run ResourceHandler destructor before we tear-down the rest of our state
78 // as the ResourceHandler may want to inspect the URLRequest and other state.
79 handler_.reset();
82 void ResourceLoader::StartRequest() {
83 if (delegate_->HandleExternalProtocol(this, request_->url())) {
84 CancelAndIgnore();
85 return;
88 // Give the handler a chance to delay the URLRequest from being started.
89 bool defer_start = false;
90 if (!handler_->OnWillStart(GetRequestInfo()->GetRequestID(), request_->url(),
91 &defer_start)) {
92 Cancel();
93 return;
96 if (defer_start) {
97 deferred_stage_ = DEFERRED_START;
98 } else {
99 StartRequestInternal();
103 void ResourceLoader::CancelRequest(bool from_renderer) {
104 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
107 void ResourceLoader::CancelAndIgnore() {
108 ResourceRequestInfoImpl* info = GetRequestInfo();
109 info->set_was_ignored_by_handler(true);
110 CancelRequest(false);
113 void ResourceLoader::CancelWithError(int error_code) {
114 CancelRequestInternal(error_code, false);
117 void ResourceLoader::ReportUploadProgress() {
118 ResourceRequestInfoImpl* info = GetRequestInfo();
120 if (waiting_for_upload_progress_ack_)
121 return; // Send one progress event at a time.
123 net::UploadProgress progress = request_->GetUploadProgress();
124 if (!progress.size())
125 return; // Nothing to upload.
127 if (progress.position() == last_upload_position_)
128 return; // No progress made since last time.
130 const uint64 kHalfPercentIncrements = 200;
131 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
133 uint64 amt_since_last = progress.position() - last_upload_position_;
134 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
136 bool is_finished = (progress.size() == progress.position());
137 bool enough_new_progress =
138 (amt_since_last > (progress.size() / kHalfPercentIncrements));
139 bool too_much_time_passed = time_since_last > kOneSecond;
141 if (is_finished || enough_new_progress || too_much_time_passed) {
142 if (request_->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
143 handler_->OnUploadProgress(
144 info->GetRequestID(), progress.position(), progress.size());
145 waiting_for_upload_progress_ack_ = true;
147 last_upload_ticks_ = TimeTicks::Now();
148 last_upload_position_ = progress.position();
152 void ResourceLoader::MarkAsTransferring() {
153 is_transferring_ = true;
155 // When an URLRequest is transferred to a new RenderViewHost, its
156 // ResourceHandler should not receive any notifications because it may depend
157 // on the state of the old RVH. We set a ResourceHandler that only allows
158 // canceling requests, because on shutdown of the RDH all pending requests
159 // are canceled. The RVH of requests that are being transferred may be gone
160 // by that time. In CompleteTransfer, the ResoureHandlers are substituted
161 // again.
162 handler_.reset(new DoomedResourceHandler(handler_.Pass()));
165 void ResourceLoader::WillCompleteTransfer() {
166 handler_.reset();
169 void ResourceLoader::CompleteTransfer(scoped_ptr<ResourceHandler> new_handler) {
170 DCHECK_EQ(DEFERRED_REDIRECT, deferred_stage_);
171 DCHECK(!handler_.get());
173 handler_ = new_handler.Pass();
174 handler_->SetController(this);
175 is_transferring_ = false;
177 Resume();
180 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
181 return ResourceRequestInfoImpl::ForRequest(request_.get());
184 void ResourceLoader::ClearLoginDelegate() {
185 login_delegate_ = NULL;
188 void ResourceLoader::ClearSSLClientAuthHandler() {
189 ssl_client_auth_handler_ = NULL;
192 void ResourceLoader::OnUploadProgressACK() {
193 waiting_for_upload_progress_ack_ = false;
196 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
197 const GURL& new_url,
198 bool* defer) {
199 DCHECK_EQ(request_.get(), unused);
201 VLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
202 DCHECK(request_->status().is_success());
204 ResourceRequestInfoImpl* info = GetRequestInfo();
206 if (info->process_type() != PROCESS_TYPE_PLUGIN &&
207 !ChildProcessSecurityPolicyImpl::GetInstance()->
208 CanRequestURL(info->GetChildID(), new_url)) {
209 VLOG(1) << "Denied unauthorized request for "
210 << new_url.possibly_invalid_spec();
212 // Tell the renderer that this request was disallowed.
213 Cancel();
214 return;
217 delegate_->DidReceiveRedirect(this, new_url);
219 if (delegate_->HandleExternalProtocol(this, new_url)) {
220 // The request is complete so we can remove it.
221 CancelAndIgnore();
222 return;
225 scoped_refptr<ResourceResponse> response(new ResourceResponse());
226 PopulateResourceResponse(request_.get(), response);
228 if (!handler_->OnRequestRedirected(info->GetRequestID(), new_url, response,
229 defer)) {
230 Cancel();
231 } else if (*defer) {
232 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
236 void ResourceLoader::OnAuthRequired(net::URLRequest* unused,
237 net::AuthChallengeInfo* auth_info) {
238 DCHECK_EQ(request_.get(), unused);
240 if (request_->load_flags() & net::LOAD_DO_NOT_PROMPT_FOR_LOGIN) {
241 request_->CancelAuth();
242 return;
245 if (!delegate_->AcceptAuthRequest(this, auth_info)) {
246 request_->CancelAuth();
247 return;
250 // Create a login dialog on the UI thread to get authentication data, or pull
251 // from cache and continue on the IO thread.
253 DCHECK(!login_delegate_) <<
254 "OnAuthRequired called with login_delegate pending";
255 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
256 if (!login_delegate_)
257 request_->CancelAuth();
260 void ResourceLoader::OnCertificateRequested(
261 net::URLRequest* unused,
262 net::SSLCertRequestInfo* cert_info) {
263 DCHECK_EQ(request_.get(), unused);
265 if (!delegate_->AcceptSSLClientCertificateRequest(this, cert_info)) {
266 request_->Cancel();
267 return;
270 if (cert_info->client_certs.empty()) {
271 // No need to query the user if there are no certs to choose from.
272 request_->ContinueWithCertificate(NULL);
273 return;
276 DCHECK(!ssl_client_auth_handler_) <<
277 "OnCertificateRequested called with ssl_client_auth_handler pending";
278 ssl_client_auth_handler_ = new SSLClientAuthHandler(request_.get(),
279 cert_info);
280 ssl_client_auth_handler_->SelectCertificate();
283 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
284 const net::SSLInfo& ssl_info,
285 bool fatal) {
286 ResourceRequestInfoImpl* info = GetRequestInfo();
288 int render_process_id;
289 int render_view_id;
290 if (!info->GetAssociatedRenderView(&render_process_id, &render_view_id))
291 NOTREACHED();
293 SSLManager::OnSSLCertificateError(
294 weak_ptr_factory_.GetWeakPtr(),
295 info->GetGlobalRequestID(),
296 info->GetResourceType(),
297 request_->url(),
298 render_process_id,
299 render_view_id,
300 ssl_info,
301 fatal);
304 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
305 DCHECK_EQ(request_.get(), unused);
307 VLOG(1) << "OnResponseStarted: " << request_->url().spec();
309 // The CanLoadPage check should take place after any server redirects have
310 // finished, at the point in time that we know a page will commit in the
311 // renderer process.
312 ResourceRequestInfoImpl* info = GetRequestInfo();
313 ChildProcessSecurityPolicyImpl* policy =
314 ChildProcessSecurityPolicyImpl::GetInstance();
315 if (!policy->CanLoadPage(info->GetChildID(),
316 request_->url(),
317 info->GetResourceType())) {
318 Cancel();
319 return;
322 if (!request_->status().is_success()) {
323 ResponseCompleted();
324 return;
327 // We want to send a final upload progress message prior to sending the
328 // response complete message even if we're waiting for an ack to to a
329 // previous upload progress message.
330 waiting_for_upload_progress_ack_ = false;
331 ReportUploadProgress();
333 CompleteResponseStarted();
335 if (is_deferred())
336 return;
338 if (request_->status().is_success()) {
339 StartReading(false); // Read the first chunk.
340 } else {
341 ResponseCompleted();
345 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
346 DCHECK_EQ(request_.get(), unused);
347 VLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
348 << " bytes_read = " << bytes_read;
350 // bytes_read == -1 always implies an error.
351 if (bytes_read == -1 || !request_->status().is_success()) {
352 ResponseCompleted();
353 return;
356 CompleteRead(bytes_read);
358 if (is_deferred())
359 return;
361 if (request_->status().is_success() && bytes_read > 0) {
362 StartReading(true); // Read the next chunk.
363 } else {
364 ResponseCompleted();
368 void ResourceLoader::CancelSSLRequest(const GlobalRequestID& id,
369 int error,
370 const net::SSLInfo* ssl_info) {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
373 // The request can be NULL if it was cancelled by the renderer (as the
374 // request of the user navigating to a new page from the location bar).
375 if (!request_->is_pending())
376 return;
377 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
379 if (ssl_info) {
380 request_->CancelWithSSLError(error, *ssl_info);
381 } else {
382 request_->CancelWithError(error);
386 void ResourceLoader::ContinueSSLRequest(const GlobalRequestID& id) {
387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
389 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
391 request_->ContinueDespiteLastError();
394 void ResourceLoader::Resume() {
395 DCHECK(!is_transferring_);
397 DeferredStage stage = deferred_stage_;
398 deferred_stage_ = DEFERRED_NONE;
399 switch (stage) {
400 case DEFERRED_NONE:
401 NOTREACHED();
402 break;
403 case DEFERRED_START:
404 StartRequestInternal();
405 break;
406 case DEFERRED_REDIRECT:
407 request_->FollowDeferredRedirect();
408 break;
409 case DEFERRED_READ:
410 MessageLoop::current()->PostTask(
411 FROM_HERE,
412 base::Bind(&ResourceLoader::ResumeReading,
413 weak_ptr_factory_.GetWeakPtr()));
414 break;
415 case DEFERRED_FINISH:
416 // Delay self-destruction since we don't know how we were reached.
417 MessageLoop::current()->PostTask(
418 FROM_HERE,
419 base::Bind(&ResourceLoader::CallDidFinishLoading,
420 weak_ptr_factory_.GetWeakPtr()));
421 break;
425 void ResourceLoader::Cancel() {
426 CancelRequest(false);
429 void ResourceLoader::StartRequestInternal() {
430 DCHECK(!request_->is_pending());
431 request_->Start();
433 delegate_->DidStartRequest(this);
436 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
437 VLOG(1) << "CancelRequestInternal: " << request_->url().spec();
439 ResourceRequestInfoImpl* info = GetRequestInfo();
441 // WebKit will send us a cancel for downloads since it no longer handles
442 // them. In this case, ignore the cancel since we handle downloads in the
443 // browser.
444 if (from_renderer && info->is_download())
445 return;
447 // TODO(darin): Perhaps we should really be looking to see if the status is
448 // IO_PENDING?
449 bool was_pending = request_->is_pending();
451 if (login_delegate_) {
452 login_delegate_->OnRequestCancelled();
453 login_delegate_ = NULL;
455 if (ssl_client_auth_handler_) {
456 ssl_client_auth_handler_->OnRequestCancelled();
457 ssl_client_auth_handler_ = NULL;
460 request_->CancelWithError(error);
462 if (!was_pending) {
463 // If the request isn't in flight, then we won't get an asynchronous
464 // notification from the request, so we have to signal ourselves to finish
465 // this request.
466 MessageLoop::current()->PostTask(
467 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
468 weak_ptr_factory_.GetWeakPtr()));
472 void ResourceLoader::CompleteResponseStarted() {
473 ResourceRequestInfoImpl* info = GetRequestInfo();
475 scoped_refptr<ResourceResponse> response(new ResourceResponse());
476 PopulateResourceResponse(request_.get(), response);
478 if (request_->ssl_info().cert) {
479 int cert_id =
480 CertStore::GetInstance()->StoreCert(request_->ssl_info().cert,
481 info->GetChildID());
482 response->head.security_info = SerializeSecurityInfo(
483 cert_id,
484 request_->ssl_info().cert_status,
485 request_->ssl_info().security_bits,
486 request_->ssl_info().connection_status);
487 } else {
488 // We should not have any SSL state.
489 DCHECK(!request_->ssl_info().cert_status &&
490 request_->ssl_info().security_bits == -1 &&
491 !request_->ssl_info().connection_status);
494 delegate_->DidReceiveResponse(this);
496 bool defer = false;
497 if (!handler_->OnResponseStarted(info->GetRequestID(), response, &defer)) {
498 Cancel();
499 } else if (defer) {
500 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
504 void ResourceLoader::StartReading(bool is_continuation) {
505 int bytes_read = 0;
506 ReadMore(&bytes_read);
508 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
509 if (request_->status().is_io_pending())
510 return;
512 if (!is_continuation || bytes_read <= 0) {
513 OnReadCompleted(request_.get(), bytes_read);
514 } else {
515 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
516 // thread in case the URLRequest can provide data synchronously.
517 MessageLoop::current()->PostTask(
518 FROM_HERE,
519 base::Bind(&ResourceLoader::OnReadCompleted,
520 weak_ptr_factory_.GetWeakPtr(),
521 request_.get(), bytes_read));
525 void ResourceLoader::ResumeReading() {
526 DCHECK(!is_deferred());
528 if (request_->status().is_success()) {
529 StartReading(false); // Read the next chunk (OK to complete synchronously).
530 } else {
531 ResponseCompleted();
535 void ResourceLoader::ReadMore(int* bytes_read) {
536 ResourceRequestInfoImpl* info = GetRequestInfo();
537 DCHECK(!is_deferred());
539 net::IOBuffer* buf;
540 int buf_size;
541 if (!handler_->OnWillRead(info->GetRequestID(), &buf, &buf_size, -1)) {
542 Cancel();
543 return;
546 DCHECK(buf);
547 DCHECK(buf_size > 0);
549 request_->Read(buf, buf_size, bytes_read);
551 // No need to check the return value here as we'll detect errors by
552 // inspecting the URLRequest's status.
555 void ResourceLoader::CompleteRead(int bytes_read) {
556 DCHECK(bytes_read >= 0);
557 DCHECK(request_->status().is_success());
559 ResourceRequestInfoImpl* info = GetRequestInfo();
561 bool defer = false;
562 if (!handler_->OnReadCompleted(info->GetRequestID(), bytes_read, &defer)) {
563 Cancel();
564 } else if (defer) {
565 deferred_stage_ = DEFERRED_READ; // Read next chunk when resumed.
569 void ResourceLoader::ResponseCompleted() {
570 VLOG(1) << "ResponseCompleted: " << request_->url().spec();
571 ResourceRequestInfoImpl* info = GetRequestInfo();
573 std::string security_info;
574 const net::SSLInfo& ssl_info = request_->ssl_info();
575 if (ssl_info.cert != NULL) {
576 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert,
577 info->GetChildID());
578 security_info = SerializeSecurityInfo(
579 cert_id, ssl_info.cert_status, ssl_info.security_bits,
580 ssl_info.connection_status);
583 if (handler_->OnResponseCompleted(info->GetRequestID(), request_->status(),
584 security_info)) {
585 // This will result in our destruction.
586 CallDidFinishLoading();
587 } else {
588 // The handler is not ready to die yet. We will call DidFinishLoading when
589 // we resume.
590 deferred_stage_ = DEFERRED_FINISH;
594 void ResourceLoader::CallDidFinishLoading() {
595 delegate_->DidFinishLoading(this);
598 } // namespace content