Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: content/browser/renderer_host/resource_loader.cc

Issue 11414299: Add content/browser/loader/ for resource loading related classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/renderer_host/resource_loader.h"
6
7 #include "base/message_loop.h"
8 #include "base/time.h"
9 #include "content/browser/child_process_security_policy_impl.h"
10 #include "content/browser/renderer_host/doomed_resource_handler.h"
11 #include "content/browser/renderer_host/resource_loader_delegate.h"
12 #include "content/browser/renderer_host/resource_request_info_impl.h"
13 #include "content/browser/ssl/ssl_client_auth_handler.h"
14 #include "content/browser/ssl/ssl_manager.h"
15 #include "content/common/ssl_status_serialization.h"
16 #include "content/public/browser/cert_store.h"
17 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
18 #include "content/public/common/resource_response.h"
19 #include "net/base/load_flags.h"
20 #include "net/http/http_response_headers.h"
21 #include "webkit/appcache/appcache_interceptor.h"
22
23 using base::TimeDelta;
24 using base::TimeTicks;
25
26 namespace content {
27 namespace {
28
29 void PopulateResourceResponse(net::URLRequest* request,
30 ResourceResponse* response) {
31 response->head.error_code = request->status().error();
32 response->head.request_time = request->request_time();
33 response->head.response_time = request->response_time();
34 response->head.headers = request->response_headers();
35 request->GetCharset(&response->head.charset);
36 response->head.content_length = request->GetExpectedContentSize();
37 request->GetMimeType(&response->head.mime_type);
38 net::HttpResponseInfo response_info = request->response_info();
39 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
40 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
41 response->head.npn_negotiated_protocol =
42 response_info.npn_negotiated_protocol;
43 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
44 response->head.socket_address = request->GetSocketAddress();
45 appcache::AppCacheInterceptor::GetExtraResponseInfo(
46 request,
47 &response->head.appcache_id,
48 &response->head.appcache_manifest_url);
49 }
50
51 } // namespace
52
53 ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
54 scoped_ptr<ResourceHandler> handler,
55 ResourceLoaderDelegate* delegate)
56 : deferred_stage_(DEFERRED_NONE),
57 request_(request.Pass()),
58 handler_(handler.Pass()),
59 delegate_(delegate),
60 last_upload_position_(0),
61 waiting_for_upload_progress_ack_(false),
62 is_transferring_(false),
63 weak_ptr_factory_(this) {
64 request_->set_delegate(this);
65 handler_->SetController(this);
66 }
67
68 ResourceLoader::~ResourceLoader() {
69 if (login_delegate_)
70 login_delegate_->OnRequestCancelled();
71 if (ssl_client_auth_handler_)
72 ssl_client_auth_handler_->OnRequestCancelled();
73
74 // Run ResourceHandler destructor before we tear-down the rest of our state
75 // as the ResourceHandler may want to inspect the URLRequest and other state.
76 handler_.reset();
77 }
78
79 void ResourceLoader::StartRequest() {
80 if (delegate_->HandleExternalProtocol(this, request_->url())) {
81 CancelAndIgnore();
82 return;
83 }
84
85 // Give the handler a chance to delay the URLRequest from being started.
86 bool defer_start = false;
87 if (!handler_->OnWillStart(GetRequestInfo()->GetRequestID(), request_->url(),
88 &defer_start)) {
89 Cancel();
90 return;
91 }
92
93 if (defer_start) {
94 deferred_stage_ = DEFERRED_START;
95 } else {
96 StartRequestInternal();
97 }
98 }
99
100 void ResourceLoader::CancelRequest(bool from_renderer) {
101 CancelRequestInternal(net::ERR_ABORTED, from_renderer);
102 }
103
104 void ResourceLoader::CancelAndIgnore() {
105 ResourceRequestInfoImpl* info = GetRequestInfo();
106 info->set_was_ignored_by_handler(true);
107 CancelRequest(false);
108 }
109
110 void ResourceLoader::CancelWithError(int error_code) {
111 CancelRequestInternal(error_code, false);
112 }
113
114 void ResourceLoader::ReportUploadProgress() {
115 ResourceRequestInfoImpl* info = GetRequestInfo();
116
117 if (waiting_for_upload_progress_ack_)
118 return; // Send one progress event at a time.
119
120 net::UploadProgress progress = request_->GetUploadProgress();
121 if (!progress.size())
122 return; // Nothing to upload.
123
124 if (progress.position() == last_upload_position_)
125 return; // No progress made since last time.
126
127 const uint64 kHalfPercentIncrements = 200;
128 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
129
130 uint64 amt_since_last = progress.position() - last_upload_position_;
131 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_;
132
133 bool is_finished = (progress.size() == progress.position());
134 bool enough_new_progress =
135 (amt_since_last > (progress.size() / kHalfPercentIncrements));
136 bool too_much_time_passed = time_since_last > kOneSecond;
137
138 if (is_finished || enough_new_progress || too_much_time_passed) {
139 if (request_->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
140 handler_->OnUploadProgress(
141 info->GetRequestID(), progress.position(), progress.size());
142 waiting_for_upload_progress_ack_ = true;
143 }
144 last_upload_ticks_ = TimeTicks::Now();
145 last_upload_position_ = progress.position();
146 }
147 }
148
149 void ResourceLoader::MarkAsTransferring() {
150 is_transferring_ = true;
151
152 // When an URLRequest is transferred to a new RenderViewHost, its
153 // ResourceHandler should not receive any notifications because it may depend
154 // on the state of the old RVH. We set a ResourceHandler that only allows
155 // canceling requests, because on shutdown of the RDH all pending requests
156 // are canceled. The RVH of requests that are being transferred may be gone
157 // by that time. In CompleteTransfer, the ResoureHandlers are substituted
158 // again.
159 handler_.reset(new DoomedResourceHandler(handler_.Pass()));
160 }
161
162 void ResourceLoader::WillCompleteTransfer() {
163 handler_.reset();
164 }
165
166 void ResourceLoader::CompleteTransfer(scoped_ptr<ResourceHandler> new_handler) {
167 DCHECK_EQ(DEFERRED_REDIRECT, deferred_stage_);
168 DCHECK(!handler_.get());
169
170 handler_ = new_handler.Pass();
171 handler_->SetController(this);
172 is_transferring_ = false;
173
174 Resume();
175 }
176
177 ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
178 return ResourceRequestInfoImpl::ForRequest(request_.get());
179 }
180
181 void ResourceLoader::ClearLoginDelegate() {
182 login_delegate_ = NULL;
183 }
184
185 void ResourceLoader::ClearSSLClientAuthHandler() {
186 ssl_client_auth_handler_ = NULL;
187 }
188
189 void ResourceLoader::OnUploadProgressACK() {
190 waiting_for_upload_progress_ack_ = false;
191 }
192
193 void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
194 const GURL& new_url,
195 bool* defer) {
196 DCHECK_EQ(request_.get(), unused);
197
198 VLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
199 DCHECK(request_->status().is_success());
200
201 ResourceRequestInfoImpl* info = GetRequestInfo();
202
203 if (info->process_type() != PROCESS_TYPE_PLUGIN &&
204 !ChildProcessSecurityPolicyImpl::GetInstance()->
205 CanRequestURL(info->GetChildID(), new_url)) {
206 VLOG(1) << "Denied unauthorized request for "
207 << new_url.possibly_invalid_spec();
208
209 // Tell the renderer that this request was disallowed.
210 Cancel();
211 return;
212 }
213
214 delegate_->DidReceiveRedirect(this, new_url);
215
216 if (delegate_->HandleExternalProtocol(this, new_url)) {
217 // The request is complete so we can remove it.
218 CancelAndIgnore();
219 return;
220 }
221
222 scoped_refptr<ResourceResponse> response(new ResourceResponse());
223 PopulateResourceResponse(request_.get(), response);
224
225 if (!handler_->OnRequestRedirected(info->GetRequestID(), new_url, response,
226 defer)) {
227 Cancel();
228 } else if (*defer) {
229 deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
230 }
231 }
232
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 if (!delegate_->AcceptAuthRequest(this, auth_info)) {
243 request_->CancelAuth();
244 return;
245 }
246
247 // Create a login dialog on the UI thread to get authentication data, or pull
248 // from cache and continue on the IO thread.
249
250 DCHECK(!login_delegate_) <<
251 "OnAuthRequired called with login_delegate pending";
252 login_delegate_ = delegate_->CreateLoginDelegate(this, auth_info);
253 if (!login_delegate_)
254 request_->CancelAuth();
255 }
256
257 void ResourceLoader::OnCertificateRequested(
258 net::URLRequest* unused,
259 net::SSLCertRequestInfo* cert_info) {
260 DCHECK_EQ(request_.get(), unused);
261
262 if (!delegate_->AcceptSSLClientCertificateRequest(this, cert_info)) {
263 request_->Cancel();
264 return;
265 }
266
267 if (cert_info->client_certs.empty()) {
268 // No need to query the user if there are no certs to choose from.
269 request_->ContinueWithCertificate(NULL);
270 return;
271 }
272
273 DCHECK(!ssl_client_auth_handler_) <<
274 "OnCertificateRequested called with ssl_client_auth_handler pending";
275 ssl_client_auth_handler_ = new SSLClientAuthHandler(request_.get(),
276 cert_info);
277 ssl_client_auth_handler_->SelectCertificate();
278 }
279
280 void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
281 const net::SSLInfo& ssl_info,
282 bool fatal) {
283 ResourceRequestInfoImpl* info = GetRequestInfo();
284
285 int render_process_id;
286 int render_view_id;
287 if (!info->GetAssociatedRenderView(&render_process_id, &render_view_id))
288 NOTREACHED();
289
290 SSLManager::OnSSLCertificateError(
291 weak_ptr_factory_.GetWeakPtr(),
292 info->GetGlobalRequestID(),
293 info->GetResourceType(),
294 request_->url(),
295 render_process_id,
296 render_view_id,
297 ssl_info,
298 fatal);
299 }
300
301 void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
302 DCHECK_EQ(request_.get(), unused);
303
304 VLOG(1) << "OnResponseStarted: " << request_->url().spec();
305
306 if (!request_->status().is_success()) {
307 ResponseCompleted();
308 return;
309 }
310
311 // We want to send a final upload progress message prior to sending the
312 // response complete message even if we're waiting for an ack to to a
313 // previous upload progress message.
314 waiting_for_upload_progress_ack_ = false;
315 ReportUploadProgress();
316
317 CompleteResponseStarted();
318
319 if (is_deferred())
320 return;
321
322 if (request_->status().is_success()) {
323 StartReading(false); // Read the first chunk.
324 } else {
325 ResponseCompleted();
326 }
327 }
328
329 void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
330 DCHECK_EQ(request_.get(), unused);
331 VLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
332 << " bytes_read = " << bytes_read;
333
334 // bytes_read == -1 always implies an error.
335 if (bytes_read == -1 || !request_->status().is_success()) {
336 ResponseCompleted();
337 return;
338 }
339
340 CompleteRead(bytes_read);
341
342 if (is_deferred())
343 return;
344
345 if (request_->status().is_success() && bytes_read > 0) {
346 StartReading(true); // Read the next chunk.
347 } else {
348 ResponseCompleted();
349 }
350 }
351
352 void ResourceLoader::CancelSSLRequest(const GlobalRequestID& id,
353 int error,
354 const net::SSLInfo* ssl_info) {
355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
356
357 // The request can be NULL if it was cancelled by the renderer (as the
358 // request of the user navigating to a new page from the location bar).
359 if (!request_->is_pending())
360 return;
361 DVLOG(1) << "CancelSSLRequest() url: " << request_->url().spec();
362
363 if (ssl_info) {
364 request_->CancelWithSSLError(error, *ssl_info);
365 } else {
366 request_->CancelWithError(error);
367 }
368 }
369
370 void ResourceLoader::ContinueSSLRequest(const GlobalRequestID& id) {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
372
373 DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
374
375 request_->ContinueDespiteLastError();
376 }
377
378 void ResourceLoader::Resume() {
379 DCHECK(!is_transferring_);
380
381 DeferredStage stage = deferred_stage_;
382 deferred_stage_ = DEFERRED_NONE;
383 switch (stage) {
384 case DEFERRED_NONE:
385 NOTREACHED();
386 break;
387 case DEFERRED_START:
388 StartRequestInternal();
389 break;
390 case DEFERRED_REDIRECT:
391 request_->FollowDeferredRedirect();
392 break;
393 case DEFERRED_READ:
394 MessageLoop::current()->PostTask(
395 FROM_HERE,
396 base::Bind(&ResourceLoader::ResumeReading,
397 weak_ptr_factory_.GetWeakPtr()));
398 break;
399 case DEFERRED_FINISH:
400 // Delay self-destruction since we don't know how we were reached.
401 MessageLoop::current()->PostTask(
402 FROM_HERE,
403 base::Bind(&ResourceLoader::CallDidFinishLoading,
404 weak_ptr_factory_.GetWeakPtr()));
405 break;
406 }
407 }
408
409 void ResourceLoader::Cancel() {
410 CancelRequest(false);
411 }
412
413 void ResourceLoader::StartRequestInternal() {
414 DCHECK(!request_->is_pending());
415 request_->Start();
416
417 delegate_->DidStartRequest(this);
418 }
419
420 void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
421 VLOG(1) << "CancelRequestInternal: " << request_->url().spec();
422
423 ResourceRequestInfoImpl* info = GetRequestInfo();
424
425 // WebKit will send us a cancel for downloads since it no longer handles
426 // them. In this case, ignore the cancel since we handle downloads in the
427 // browser.
428 if (from_renderer && info->is_download())
429 return;
430
431 // TODO(darin): Perhaps we should really be looking to see if the status is
432 // IO_PENDING?
433 bool was_pending = request_->is_pending();
434
435 if (login_delegate_) {
436 login_delegate_->OnRequestCancelled();
437 login_delegate_ = NULL;
438 }
439 if (ssl_client_auth_handler_) {
440 ssl_client_auth_handler_->OnRequestCancelled();
441 ssl_client_auth_handler_ = NULL;
442 }
443
444 request_->CancelWithError(error);
445
446 if (!was_pending) {
447 // If the request isn't in flight, then we won't get an asynchronous
448 // notification from the request, so we have to signal ourselves to finish
449 // this request.
450 MessageLoop::current()->PostTask(
451 FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
452 weak_ptr_factory_.GetWeakPtr()));
453 }
454 }
455
456 void ResourceLoader::CompleteResponseStarted() {
457 ResourceRequestInfoImpl* info = GetRequestInfo();
458
459 scoped_refptr<ResourceResponse> response(new ResourceResponse());
460 PopulateResourceResponse(request_.get(), response);
461
462 if (request_->ssl_info().cert) {
463 int cert_id =
464 CertStore::GetInstance()->StoreCert(request_->ssl_info().cert,
465 info->GetChildID());
466 response->head.security_info = SerializeSecurityInfo(
467 cert_id,
468 request_->ssl_info().cert_status,
469 request_->ssl_info().security_bits,
470 request_->ssl_info().connection_status);
471 } else {
472 // We should not have any SSL state.
473 DCHECK(!request_->ssl_info().cert_status &&
474 request_->ssl_info().security_bits == -1 &&
475 !request_->ssl_info().connection_status);
476 }
477
478 delegate_->DidReceiveResponse(this);
479
480 bool defer = false;
481 if (!handler_->OnResponseStarted(info->GetRequestID(), response, &defer)) {
482 Cancel();
483 } else if (defer) {
484 deferred_stage_ = DEFERRED_READ; // Read first chunk when resumed.
485 }
486 }
487
488 void ResourceLoader::StartReading(bool is_continuation) {
489 int bytes_read = 0;
490 ReadMore(&bytes_read);
491
492 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
493 if (request_->status().is_io_pending())
494 return;
495
496 if (!is_continuation || bytes_read <= 0) {
497 OnReadCompleted(request_.get(), bytes_read);
498 } else {
499 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
500 // thread in case the URLRequest can provide data synchronously.
501 MessageLoop::current()->PostTask(
502 FROM_HERE,
503 base::Bind(&ResourceLoader::OnReadCompleted,
504 weak_ptr_factory_.GetWeakPtr(),
505 request_.get(), bytes_read));
506 }
507 }
508
509 void ResourceLoader::ResumeReading() {
510 DCHECK(!is_deferred());
511
512 if (request_->status().is_success()) {
513 StartReading(false); // Read the next chunk (OK to complete synchronously).
514 } else {
515 ResponseCompleted();
516 }
517 }
518
519 void ResourceLoader::ReadMore(int* bytes_read) {
520 ResourceRequestInfoImpl* info = GetRequestInfo();
521 DCHECK(!is_deferred());
522
523 net::IOBuffer* buf;
524 int buf_size;
525 if (!handler_->OnWillRead(info->GetRequestID(), &buf, &buf_size, -1)) {
526 Cancel();
527 return;
528 }
529
530 DCHECK(buf);
531 DCHECK(buf_size > 0);
532
533 request_->Read(buf, buf_size, bytes_read);
534
535 // No need to check the return value here as we'll detect errors by
536 // inspecting the URLRequest's status.
537 }
538
539 void ResourceLoader::CompleteRead(int bytes_read) {
540 DCHECK(bytes_read >= 0);
541 DCHECK(request_->status().is_success());
542
543 ResourceRequestInfoImpl* info = GetRequestInfo();
544
545 bool defer = false;
546 if (!handler_->OnReadCompleted(info->GetRequestID(), bytes_read, &defer)) {
547 Cancel();
548 } else if (defer) {
549 deferred_stage_ = DEFERRED_READ; // Read next chunk when resumed.
550 }
551 }
552
553 void ResourceLoader::ResponseCompleted() {
554 VLOG(1) << "ResponseCompleted: " << request_->url().spec();
555 ResourceRequestInfoImpl* info = GetRequestInfo();
556
557 std::string security_info;
558 const net::SSLInfo& ssl_info = request_->ssl_info();
559 if (ssl_info.cert != NULL) {
560 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert,
561 info->GetChildID());
562 security_info = SerializeSecurityInfo(
563 cert_id, ssl_info.cert_status, ssl_info.security_bits,
564 ssl_info.connection_status);
565 }
566
567 if (handler_->OnResponseCompleted(info->GetRequestID(), request_->status(),
568 security_info)) {
569 // This will result in our destruction.
570 CallDidFinishLoading();
571 } else {
572 // The handler is not ready to die yet. We will call DidFinishLoading when
573 // we resume.
574 deferred_stage_ = DEFERRED_FINISH;
575 }
576 }
577
578 void ResourceLoader::CallDidFinishLoading() {
579 delegate_->DidFinishLoading(this);
580 }
581
582 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/resource_loader.h ('k') | content/browser/renderer_host/resource_loader_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698