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

Side by Side Diff: chrome/browser/renderer_host/resource_dispatcher_host.cc

Issue 6532073: Move core pieces of browser\renderer_host to src\content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months 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) 2011 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 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading
6
7 #include "chrome/browser/renderer_host/resource_dispatcher_host.h"
8
9 #include <set>
10 #include <vector>
11
12 #include "base/logging.h"
13 #include "base/command_line.h"
14 #include "base/message_loop.h"
15 #include "base/metrics/histogram.h"
16 #include "base/scoped_ptr.h"
17 #include "base/shared_memory.h"
18 #include "base/stl_util-inl.h"
19 #include "base/time.h"
20 #include "chrome/browser/cert_store.h"
21 #include "chrome/browser/child_process_security_policy.h"
22 #include "chrome/browser/chrome_blob_storage_context.h"
23 #include "chrome/browser/cross_site_request_manager.h"
24 #include "chrome/browser/download/download_file_manager.h"
25 #include "chrome/browser/download/download_manager.h"
26 #include "chrome/browser/download/download_request_limiter.h"
27 #include "chrome/browser/download/download_util.h"
28 #include "chrome/browser/download/save_file_manager.h"
29 #include "chrome/browser/extensions/user_script_listener.h"
30 #include "chrome/browser/external_protocol_handler.h"
31 #include "chrome/browser/in_process_webkit/webkit_thread.h"
32 #include "chrome/browser/net/chrome_url_request_context.h"
33 #include "chrome/browser/net/url_request_tracking.h"
34 #include "chrome/browser/plugin_service.h"
35 #include "chrome/browser/prerender/prerender_manager.h"
36 #include "chrome/browser/prerender/prerender_resource_handler.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/renderer_host/async_resource_handler.h"
39 #include "chrome/browser/renderer_host/buffered_resource_handler.h"
40 #include "chrome/browser/renderer_host/cross_site_resource_handler.h"
41 #include "chrome/browser/renderer_host/download_resource_handler.h"
42 #include "chrome/browser/renderer_host/global_request_id.h"
43 #include "chrome/browser/renderer_host/redirect_to_file_resource_handler.h"
44 #include "chrome/browser/renderer_host/render_view_host.h"
45 #include "chrome/browser/renderer_host/render_view_host_delegate.h"
46 #include "chrome/browser/renderer_host/render_view_host_notification_task.h"
47 #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
48 #include "chrome/browser/renderer_host/resource_message_filter.h"
49 #include "chrome/browser/renderer_host/resource_queue.h"
50 #include "chrome/browser/renderer_host/resource_request_details.h"
51 #include "chrome/browser/renderer_host/safe_browsing_resource_handler.h"
52 #include "chrome/browser/renderer_host/save_file_resource_handler.h"
53 #include "chrome/browser/renderer_host/sync_resource_handler.h"
54 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
55 #include "chrome/browser/ssl/ssl_client_auth_handler.h"
56 #include "chrome/browser/ssl/ssl_manager.h"
57 #include "chrome/browser/ui/login/login_prompt.h"
58 #include "chrome/browser/worker_host/worker_service.h"
59 #include "chrome/common/chrome_switches.h"
60 #include "chrome/common/notification_service.h"
61 #include "chrome/common/render_messages.h"
62 #include "chrome/common/render_messages_params.h"
63 #include "chrome/common/url_constants.h"
64 #include "net/base/auth.h"
65 #include "net/base/cert_status_flags.h"
66 #include "net/base/cookie_monster.h"
67 #include "net/base/load_flags.h"
68 #include "net/base/mime_util.h"
69 #include "net/base/net_errors.h"
70 #include "net/base/request_priority.h"
71 #include "net/base/ssl_cert_request_info.h"
72 #include "net/base/upload_data.h"
73 #include "net/http/http_response_headers.h"
74 #include "net/url_request/url_request.h"
75 #include "net/url_request/url_request_context.h"
76 #include "webkit/appcache/appcache_interceptor.h"
77 #include "webkit/appcache/appcache_interfaces.h"
78 #include "webkit/blob/blob_storage_controller.h"
79 #include "webkit/blob/deletable_file_reference.h"
80
81 // TODO(oshima): Enable this for other platforms.
82 #if defined(OS_CHROMEOS)
83 #include "chrome/browser/renderer_host/offline_resource_handler.h"
84 #endif
85
86 using base::Time;
87 using base::TimeDelta;
88 using base::TimeTicks;
89 using webkit_blob::DeletableFileReference;
90
91 // ----------------------------------------------------------------------------
92
93 // A ShutdownTask proxies a shutdown task from the UI thread to the IO thread.
94 // It should be constructed on the UI thread and run in the IO thread.
95 class ResourceDispatcherHost::ShutdownTask : public Task {
96 public:
97 explicit ShutdownTask(ResourceDispatcherHost* resource_dispatcher_host)
98 : rdh_(resource_dispatcher_host) {
99 }
100
101 void Run() {
102 rdh_->OnShutdown();
103 }
104
105 private:
106 ResourceDispatcherHost* rdh_;
107 };
108
109 namespace {
110
111 // The interval for calls to ResourceDispatcherHost::UpdateLoadStates
112 const int kUpdateLoadStatesIntervalMsec = 100;
113
114 // Maximum number of pending data messages sent to the renderer at any
115 // given time for a given request.
116 const int kMaxPendingDataMessages = 20;
117
118 // Maximum byte "cost" of all the outstanding requests for a renderer.
119 // See delcaration of |max_outstanding_requests_cost_per_process_| for details.
120 // This bound is 25MB, which allows for around 6000 outstanding requests.
121 const int kMaxOutstandingRequestsCostPerProcess = 26214400;
122
123 // Consults the RendererSecurity policy to determine whether the
124 // ResourceDispatcherHost should service this request. A request might be
125 // disallowed if the renderer is not authorized to retrieve the request URL or
126 // if the renderer is attempting to upload an unauthorized file.
127 bool ShouldServiceRequest(ChildProcessInfo::ProcessType process_type,
128 int child_id,
129 const ViewHostMsg_Resource_Request& request_data) {
130 if (process_type == ChildProcessInfo::PLUGIN_PROCESS)
131 return true;
132
133 if (request_data.resource_type == ResourceType::PREFETCH) {
134 prerender::PrerenderManager::RecordPrefetchTagObserved();
135 if (!ResourceDispatcherHost::is_prefetch_enabled())
136 return false;
137 }
138
139 ChildProcessSecurityPolicy* policy =
140 ChildProcessSecurityPolicy::GetInstance();
141
142 // Check if the renderer is permitted to request the requested URL.
143 if (!policy->CanRequestURL(child_id, request_data.url)) {
144 VLOG(1) << "Denied unauthorized request for "
145 << request_data.url.possibly_invalid_spec();
146 return false;
147 }
148
149 // Check if the renderer is permitted to upload the requested files.
150 if (request_data.upload_data) {
151 const std::vector<net::UploadData::Element>* uploads =
152 request_data.upload_data->elements();
153 std::vector<net::UploadData::Element>::const_iterator iter;
154 for (iter = uploads->begin(); iter != uploads->end(); ++iter) {
155 if (iter->type() == net::UploadData::TYPE_FILE &&
156 !policy->CanReadFile(child_id, iter->file_path())) {
157 NOTREACHED() << "Denied unauthorized upload of "
158 << iter->file_path().value();
159 return false;
160 }
161 }
162 }
163
164 return true;
165 }
166
167 void PopulateResourceResponse(net::URLRequest* request,
168 bool replace_extension_localization_templates,
169 ResourceResponse* response) {
170 response->response_head.status = request->status();
171 response->response_head.request_time = request->request_time();
172 response->response_head.response_time = request->response_time();
173 response->response_head.headers = request->response_headers();
174 request->GetCharset(&response->response_head.charset);
175 response->response_head.replace_extension_localization_templates =
176 replace_extension_localization_templates;
177 response->response_head.content_length = request->GetExpectedContentSize();
178 request->GetMimeType(&response->response_head.mime_type);
179 response->response_head.was_fetched_via_spdy =
180 request->was_fetched_via_spdy();
181 response->response_head.was_npn_negotiated = request->was_npn_negotiated();
182 response->response_head.was_alternate_protocol_available =
183 request->was_alternate_protocol_available();
184 response->response_head.was_fetched_via_proxy =
185 request->was_fetched_via_proxy();
186 appcache::AppCacheInterceptor::GetExtraResponseInfo(
187 request,
188 &response->response_head.appcache_id,
189 &response->response_head.appcache_manifest_url);
190 }
191
192 // Returns a list of all the possible error codes from the network module.
193 // Note that the error codes are all positive (since histograms expect positive
194 // sample values).
195 std::vector<int> GetAllNetErrorCodes() {
196 std::vector<int> all_error_codes;
197 #define NET_ERROR(label, value) all_error_codes.push_back(-(value));
198 #include "net/base/net_error_list.h"
199 #undef NET_ERROR
200 return all_error_codes;
201 }
202
203 #if defined(OS_WIN)
204 #pragma warning(disable: 4748)
205 #pragma optimize("", off)
206 #endif
207
208 #if defined(OS_WIN)
209 #pragma optimize("", on)
210 #pragma warning(default: 4748)
211 #endif
212
213 } // namespace
214
215 ResourceDispatcherHost::ResourceDispatcherHost()
216 : ALLOW_THIS_IN_INITIALIZER_LIST(
217 download_file_manager_(new DownloadFileManager(this))),
218 download_request_limiter_(new DownloadRequestLimiter()),
219 ALLOW_THIS_IN_INITIALIZER_LIST(
220 save_file_manager_(new SaveFileManager(this))),
221 user_script_listener_(new UserScriptListener(&resource_queue_)),
222 safe_browsing_(SafeBrowsingService::CreateSafeBrowsingService()),
223 webkit_thread_(new WebKitThread),
224 request_id_(-1),
225 ALLOW_THIS_IN_INITIALIZER_LIST(method_runner_(this)),
226 is_shutdown_(false),
227 max_outstanding_requests_cost_per_process_(
228 kMaxOutstandingRequestsCostPerProcess),
229 filter_(NULL) {
230 ResourceQueue::DelegateSet resource_queue_delegates;
231 resource_queue_delegates.insert(user_script_listener_.get());
232 resource_queue_.Initialize(resource_queue_delegates);
233 }
234
235 ResourceDispatcherHost::~ResourceDispatcherHost() {
236 AsyncResourceHandler::GlobalCleanup();
237 STLDeleteValues(&pending_requests_);
238
239 user_script_listener_->ShutdownMainThread();
240 }
241
242 void ResourceDispatcherHost::Initialize() {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
244 webkit_thread_->Initialize();
245 safe_browsing_->Initialize();
246 BrowserThread::PostTask(
247 BrowserThread::IO, FROM_HERE,
248 NewRunnableFunction(&appcache::AppCacheInterceptor::EnsureRegistered));
249 }
250
251 void ResourceDispatcherHost::Shutdown() {
252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
253 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, new ShutdownTask(this));
254 }
255
256 void ResourceDispatcherHost::SetRequestInfo(
257 net::URLRequest* request,
258 ResourceDispatcherHostRequestInfo* info) {
259 request->SetUserData(NULL, info);
260 }
261
262 void ResourceDispatcherHost::OnShutdown() {
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
264 is_shutdown_ = true;
265 resource_queue_.Shutdown();
266 STLDeleteValues(&pending_requests_);
267 // Make sure we shutdown the timer now, otherwise by the time our destructor
268 // runs if the timer is still running the Task is deleted twice (once by
269 // the MessageLoop and the second time by RepeatingTimer).
270 update_load_states_timer_.Stop();
271
272 // Clear blocked requests if any left.
273 // Note that we have to do this in 2 passes as we cannot call
274 // CancelBlockedRequestsForRoute while iterating over
275 // blocked_requests_map_, as it modifies it.
276 std::set<ProcessRouteIDs> ids;
277 for (BlockedRequestMap::const_iterator iter = blocked_requests_map_.begin();
278 iter != blocked_requests_map_.end(); ++iter) {
279 std::pair<std::set<ProcessRouteIDs>::iterator, bool> result =
280 ids.insert(iter->first);
281 // We should not have duplicates.
282 DCHECK(result.second);
283 }
284 for (std::set<ProcessRouteIDs>::const_iterator iter = ids.begin();
285 iter != ids.end(); ++iter) {
286 CancelBlockedRequestsForRoute(iter->first, iter->second);
287 }
288 }
289
290 bool ResourceDispatcherHost::HandleExternalProtocol(int request_id,
291 int child_id,
292 int route_id,
293 const GURL& url,
294 ResourceType::Type type,
295 ResourceHandler* handler) {
296 if (!ResourceType::IsFrame(type) || net::URLRequest::IsHandledURL(url))
297 return false;
298
299 BrowserThread::PostTask(
300 BrowserThread::UI, FROM_HERE,
301 NewRunnableFunction(
302 &ExternalProtocolHandler::LaunchUrl, url, child_id, route_id));
303
304 handler->OnResponseCompleted(
305 request_id,
306 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_ABORTED),
307 std::string()); // No security info necessary.
308 return true;
309 }
310
311 bool ResourceDispatcherHost::OnMessageReceived(const IPC::Message& message,
312 ResourceMessageFilter* filter,
313 bool* message_was_ok) {
314 filter_ = filter;
315 bool handled = true;
316 IPC_BEGIN_MESSAGE_MAP_EX(ResourceDispatcherHost, message, *message_was_ok)
317 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestResource, OnRequestResource)
318 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncLoad, OnSyncLoad)
319 IPC_MESSAGE_HANDLER(ViewHostMsg_ReleaseDownloadedFile,
320 OnReleaseDownloadedFile)
321 IPC_MESSAGE_HANDLER(ViewHostMsg_DataReceived_ACK, OnDataReceivedACK)
322 IPC_MESSAGE_HANDLER(ViewHostMsg_DataDownloaded_ACK, OnDataDownloadedACK)
323 IPC_MESSAGE_HANDLER(ViewHostMsg_UploadProgress_ACK, OnUploadProgressACK)
324 IPC_MESSAGE_HANDLER(ViewHostMsg_CancelRequest, OnCancelRequest)
325 IPC_MESSAGE_HANDLER(ViewHostMsg_FollowRedirect, OnFollowRedirect)
326 IPC_MESSAGE_HANDLER(ViewHostMsg_ClosePage_ACK, OnClosePageACK)
327 IPC_MESSAGE_UNHANDLED(handled = false)
328 IPC_END_MESSAGE_MAP_EX()
329
330 filter_ = NULL;
331 return handled;
332 }
333
334 void ResourceDispatcherHost::OnRequestResource(
335 const IPC::Message& message,
336 int request_id,
337 const ViewHostMsg_Resource_Request& request_data) {
338 BeginRequest(request_id, request_data, NULL, message.routing_id());
339 }
340
341 // Begins a resource request with the given params on behalf of the specified
342 // child process. Responses will be dispatched through the given receiver. The
343 // process ID is used to lookup TabContents from routing_id's in the case of a
344 // request from a renderer. request_context is the cookie/cache context to be
345 // used for this request.
346 //
347 // If sync_result is non-null, then a SyncLoad reply will be generated, else
348 // a normal asynchronous set of response messages will be generated.
349 void ResourceDispatcherHost::OnSyncLoad(
350 int request_id,
351 const ViewHostMsg_Resource_Request& request_data,
352 IPC::Message* sync_result) {
353 BeginRequest(request_id, request_data, sync_result,
354 sync_result->routing_id());
355 }
356
357 void ResourceDispatcherHost::BeginRequest(
358 int request_id,
359 const ViewHostMsg_Resource_Request& request_data,
360 IPC::Message* sync_result, // only valid for sync
361 int route_id) {
362 ChildProcessInfo::ProcessType process_type = filter_->process_type();
363 int child_id = filter_->child_id();
364
365 ChromeURLRequestContext* context = filter_->GetURLRequestContext(
366 request_data);
367
368 // Might need to resolve the blob references in the upload data.
369 if (request_data.upload_data && context) {
370 context->blob_storage_context()->controller()->
371 ResolveBlobReferencesInUploadData(request_data.upload_data.get());
372 }
373
374 if (is_shutdown_ ||
375 !ShouldServiceRequest(process_type, child_id, request_data)) {
376 net::URLRequestStatus status(net::URLRequestStatus::FAILED,
377 net::ERR_ABORTED);
378 if (sync_result) {
379 SyncLoadResult result;
380 result.status = status;
381 ViewHostMsg_SyncLoad::WriteReplyParams(sync_result, result);
382 filter_->Send(sync_result);
383 } else {
384 // Tell the renderer that this request was disallowed.
385 filter_->Send(new ViewMsg_Resource_RequestComplete(
386 route_id,
387 request_id,
388 status,
389 std::string(), // No security info needed, connection was not
390 base::Time())); // established.
391 }
392 return;
393 }
394
395 // Ensure the Chrome plugins are loaded, as they may intercept network
396 // requests. Does nothing if they are already loaded.
397 // TODO(mpcomplete): This takes 200 ms! Investigate parallelizing this by
398 // starting the load earlier in a BG thread.
399 PluginService::GetInstance()->LoadChromePlugins(this);
400
401 // Construct the event handler.
402 scoped_refptr<ResourceHandler> handler;
403 if (sync_result) {
404 handler = new SyncResourceHandler(
405 filter_, request_data.url, sync_result, this);
406 } else {
407 handler = new AsyncResourceHandler(
408 filter_, route_id, request_data.url, this);
409 }
410
411 // The RedirectToFileResourceHandler depends on being next in the chain.
412 if (request_data.download_to_file)
413 handler = new RedirectToFileResourceHandler(handler, child_id, this);
414
415 if (HandleExternalProtocol(request_id, child_id, route_id,
416 request_data.url, request_data.resource_type,
417 handler)) {
418 return;
419 }
420
421 // Construct the request.
422 net::URLRequest* request = new net::URLRequest(request_data.url, this);
423 request->set_method(request_data.method);
424 request->set_first_party_for_cookies(request_data.first_party_for_cookies);
425 request->set_referrer(CommandLine::ForCurrentProcess()->HasSwitch(
426 switches::kNoReferrers) ? std::string() : request_data.referrer.spec());
427 net::HttpRequestHeaders headers;
428 headers.AddHeadersFromString(request_data.headers);
429 request->SetExtraRequestHeaders(headers);
430
431 int load_flags = request_data.load_flags;
432 // Although EV status is irrelevant to sub-frames and sub-resources, we have
433 // to perform EV certificate verification on all resources because an HTTP
434 // keep-alive connection created to load a sub-frame or a sub-resource could
435 // be reused to load a main frame.
436 load_flags |= net::LOAD_VERIFY_EV_CERT;
437 if (request_data.resource_type == ResourceType::MAIN_FRAME) {
438 load_flags |= net::LOAD_MAIN_FRAME;
439 } else if (request_data.resource_type == ResourceType::SUB_FRAME) {
440 load_flags |= net::LOAD_SUB_FRAME;
441 } else if (request_data.resource_type == ResourceType::PREFETCH) {
442 load_flags |= net::LOAD_PREFETCH;
443 }
444 // Raw headers are sensitive, as they inclide Cookie/Set-Cookie, so only
445 // allow requesting them if requestor has ReadRawCookies permission.
446 if ((load_flags & net::LOAD_REPORT_RAW_HEADERS)
447 && !ChildProcessSecurityPolicy::GetInstance()->
448 CanReadRawCookies(child_id)) {
449 VLOG(1) << "Denied unathorized request for raw headers";
450 load_flags &= ~net::LOAD_REPORT_RAW_HEADERS;
451 }
452
453 request->set_load_flags(load_flags);
454 request->set_context(context);
455 request->set_priority(DetermineRequestPriority(request_data.resource_type));
456
457 // Set upload data.
458 uint64 upload_size = 0;
459 if (request_data.upload_data) {
460 request->set_upload(request_data.upload_data);
461 upload_size = request_data.upload_data->GetContentLength();
462 }
463
464 // Install a PrerenderResourceHandler if the requested URL could
465 // be prerendered. This should be in front of the [a]syncResourceHandler,
466 // but after the BufferedResourceHandler since it depends on the MIME
467 // sniffing capabilities in the BufferedResourceHandler.
468 prerender::PrerenderResourceHandler* pre_handler =
469 prerender::PrerenderResourceHandler::MaybeCreate(*request,
470 context,
471 handler);
472 if (pre_handler)
473 handler = pre_handler;
474
475 // Install a CrossSiteResourceHandler if this request is coming from a
476 // RenderViewHost with a pending cross-site request. We only check this for
477 // MAIN_FRAME requests. Unblock requests only come from a blocked page, do
478 // not count as cross-site, otherwise it gets blocked indefinitely.
479 if (request_data.resource_type == ResourceType::MAIN_FRAME &&
480 process_type == ChildProcessInfo::RENDER_PROCESS &&
481 CrossSiteRequestManager::GetInstance()->
482 HasPendingCrossSiteRequest(child_id, route_id)) {
483 // Wrap the event handler to be sure the current page's onunload handler
484 // has a chance to run before we render the new page.
485 handler = new CrossSiteResourceHandler(handler,
486 child_id,
487 route_id,
488 this);
489 }
490
491 // Insert a buffered event handler before the actual one.
492 handler = new BufferedResourceHandler(handler, this, request);
493
494 // Insert safe browsing at the front of the chain, so it gets to decide
495 // on policies first.
496 if (safe_browsing_->enabled()) {
497 handler = CreateSafeBrowsingResourceHandler(handler, child_id, route_id,
498 request_data.resource_type);
499 }
500
501 #if defined(OS_CHROMEOS)
502 // We check offline first, then check safe browsing so that we still can block
503 // unsafe site after we remove offline page.
504 handler =
505 new OfflineResourceHandler(handler, child_id, route_id, this, request);
506 #endif
507
508 // Make extra info and read footer (contains request ID).
509 ResourceDispatcherHostRequestInfo* extra_info =
510 new ResourceDispatcherHostRequestInfo(
511 handler,
512 process_type,
513 child_id,
514 route_id,
515 request_id,
516 request_data.resource_type,
517 upload_size,
518 false, // is download
519 ResourceType::IsFrame(request_data.resource_type), // allow_download
520 request_data.has_user_gesture,
521 request_data.host_renderer_id,
522 request_data.host_render_view_id);
523 ApplyExtensionLocalizationFilter(request_data.url, request_data.resource_type,
524 extra_info);
525 SetRequestInfo(request, extra_info); // Request takes ownership.
526 chrome_browser_net::SetOriginPIDForRequest(
527 request_data.origin_pid, request);
528
529 if (request->url().SchemeIs(chrome::kBlobScheme) && context) {
530 // Hang on to a reference to ensure the blob is not released prior
531 // to the job being started.
532 webkit_blob::BlobStorageController* controller =
533 context->blob_storage_context()->controller();
534 extra_info->set_requested_blob_data(
535 controller->GetBlobDataFromUrl(request->url()));
536 }
537
538 // Have the appcache associate its extra info with the request.
539 appcache::AppCacheInterceptor::SetExtraRequestInfo(
540 request, context ? context->appcache_service() : NULL, child_id,
541 request_data.appcache_host_id, request_data.resource_type);
542
543 BeginRequestInternal(request);
544 }
545
546 void ResourceDispatcherHost::OnReleaseDownloadedFile(int request_id) {
547 DCHECK(pending_requests_.end() ==
548 pending_requests_.find(
549 GlobalRequestID(filter_->child_id(), request_id)));
550 UnregisterDownloadedTempFile(filter_->child_id(), request_id);
551 }
552
553 void ResourceDispatcherHost::OnDataReceivedACK(int request_id) {
554 DataReceivedACK(filter_->child_id(), request_id);
555 }
556
557 void ResourceDispatcherHost::DataReceivedACK(int child_id,
558 int request_id) {
559 PendingRequestList::iterator i = pending_requests_.find(
560 GlobalRequestID(child_id, request_id));
561 if (i == pending_requests_.end())
562 return;
563
564 ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second);
565
566 // Decrement the number of pending data messages.
567 info->DecrementPendingDataCount();
568
569 // If the pending data count was higher than the max, resume the request.
570 if (info->pending_data_count() == kMaxPendingDataMessages) {
571 // Decrement the pending data count one more time because we also
572 // incremented it before pausing the request.
573 info->DecrementPendingDataCount();
574
575 // Resume the request.
576 PauseRequest(child_id, request_id, false);
577 }
578 }
579
580 void ResourceDispatcherHost::OnDataDownloadedACK(int request_id) {
581 // TODO(michaeln): maybe throttle DataDownloaded messages
582 }
583
584 void ResourceDispatcherHost::RegisterDownloadedTempFile(
585 int child_id, int request_id, DeletableFileReference* reference) {
586 registered_temp_files_[child_id][request_id] = reference;
587 ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
588 child_id, reference->path());
589 }
590
591 void ResourceDispatcherHost::UnregisterDownloadedTempFile(
592 int child_id, int request_id) {
593 DeletableFilesMap& map = registered_temp_files_[child_id];
594 DeletableFilesMap::iterator found = map.find(request_id);
595 if (found == map.end())
596 return;
597
598 ChildProcessSecurityPolicy::GetInstance()->RevokeAllPermissionsForFile(
599 child_id, found->second->path());
600 map.erase(found);
601 }
602
603 bool ResourceDispatcherHost::Send(IPC::Message* message) {
604 delete message;
605 return false;
606 }
607
608 void ResourceDispatcherHost::OnUploadProgressACK(int request_id) {
609 int child_id = filter_->child_id();
610 PendingRequestList::iterator i = pending_requests_.find(
611 GlobalRequestID(child_id, request_id));
612 if (i == pending_requests_.end())
613 return;
614
615 ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second);
616 info->set_waiting_for_upload_progress_ack(false);
617 }
618
619 void ResourceDispatcherHost::OnCancelRequest(int request_id) {
620 CancelRequest(filter_->child_id(), request_id, true);
621 }
622
623 void ResourceDispatcherHost::OnFollowRedirect(
624 int request_id,
625 bool has_new_first_party_for_cookies,
626 const GURL& new_first_party_for_cookies) {
627 FollowDeferredRedirect(filter_->child_id(), request_id,
628 has_new_first_party_for_cookies,
629 new_first_party_for_cookies);
630 }
631
632 ResourceHandler* ResourceDispatcherHost::CreateSafeBrowsingResourceHandler(
633 ResourceHandler* handler, int child_id, int route_id,
634 ResourceType::Type resource_type) {
635 return new SafeBrowsingResourceHandler(
636 handler, child_id, route_id, resource_type, safe_browsing_, this);
637 }
638
639 ResourceDispatcherHostRequestInfo*
640 ResourceDispatcherHost::CreateRequestInfoForBrowserRequest(
641 ResourceHandler* handler, int child_id, int route_id, bool download) {
642 return new ResourceDispatcherHostRequestInfo(handler,
643 ChildProcessInfo::RENDER_PROCESS,
644 child_id,
645 route_id,
646 request_id_,
647 ResourceType::SUB_RESOURCE,
648 0, // upload_size
649 download, // is_download
650 download, // allow_download
651 false, // has_user_gesture
652 -1, // host renderer id
653 -1); // host render view id
654 }
655
656 void ResourceDispatcherHost::OnClosePageACK(
657 const ViewMsg_ClosePage_Params& params) {
658 if (params.for_cross_site_transition) {
659 // Closes for cross-site transitions are handled such that the cross-site
660 // transition continues.
661 GlobalRequestID global_id(params.new_render_process_host_id,
662 params.new_request_id);
663 PendingRequestList::iterator i = pending_requests_.find(global_id);
664 if (i != pending_requests_.end()) {
665 // The response we were meant to resume could have already been canceled.
666 ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second);
667 if (info->cross_site_handler())
668 info->cross_site_handler()->ResumeResponse();
669 }
670 } else {
671 // This is a tab close, so just forward the message to close it.
672 DCHECK(params.new_render_process_host_id == -1);
673 DCHECK(params.new_request_id == -1);
674 CallRenderViewHost(params.closing_process_id,
675 params.closing_route_id,
676 &RenderViewHost::ClosePageIgnoringUnloadEvents);
677 }
678 }
679
680 // We are explicitly forcing the download of 'url'.
681 void ResourceDispatcherHost::BeginDownload(
682 const GURL& url,
683 const GURL& referrer,
684 const DownloadSaveInfo& save_info,
685 bool prompt_for_save_location,
686 int child_id,
687 int route_id,
688 net::URLRequestContext* request_context) {
689 if (is_shutdown_)
690 return;
691
692 // Check if the renderer is permitted to request the requested URL.
693 if (!ChildProcessSecurityPolicy::GetInstance()->
694 CanRequestURL(child_id, url)) {
695 VLOG(1) << "Denied unauthorized download request for "
696 << url.possibly_invalid_spec();
697 return;
698 }
699
700 BrowserThread::PostTask(
701 BrowserThread::UI, FROM_HERE,
702 NewRunnableFunction(&download_util::NotifyDownloadInitiated,
703 child_id, route_id));
704
705 // Ensure the Chrome plugins are loaded, as they may intercept network
706 // requests. Does nothing if they are already loaded.
707 PluginService::GetInstance()->LoadChromePlugins(this);
708 net::URLRequest* request = new net::URLRequest(url, this);
709
710 request_id_--;
711
712 scoped_refptr<ResourceHandler> handler(
713 new DownloadResourceHandler(this,
714 child_id,
715 route_id,
716 request_id_,
717 url,
718 download_file_manager_.get(),
719 request,
720 prompt_for_save_location,
721 save_info));
722
723 if (safe_browsing_->enabled()) {
724 handler = CreateSafeBrowsingResourceHandler(handler, child_id, route_id,
725 ResourceType::MAIN_FRAME);
726 }
727
728 if (!net::URLRequest::IsHandledURL(url)) {
729 VLOG(1) << "Download request for unsupported protocol: "
730 << url.possibly_invalid_spec();
731 return;
732 }
733
734 request->set_method("GET");
735 request->set_referrer(CommandLine::ForCurrentProcess()->HasSwitch(
736 switches::kNoReferrers) ? std::string() : referrer.spec());
737 request->set_context(request_context);
738 request->set_load_flags(request->load_flags() |
739 net::LOAD_IS_DOWNLOAD);
740
741 ResourceDispatcherHostRequestInfo* extra_info =
742 CreateRequestInfoForBrowserRequest(handler, child_id, route_id, true);
743 SetRequestInfo(request, extra_info); // Request takes ownership.
744
745 BeginRequestInternal(request);
746 }
747
748 // This function is only used for saving feature.
749 void ResourceDispatcherHost::BeginSaveFile(
750 const GURL& url,
751 const GURL& referrer,
752 int child_id,
753 int route_id,
754 net::URLRequestContext* request_context) {
755 if (is_shutdown_)
756 return;
757
758 // Ensure the Chrome plugins are loaded, as they may intercept network
759 // requests. Does nothing if they are already loaded.
760 PluginService::GetInstance()->LoadChromePlugins(this);
761
762 scoped_refptr<ResourceHandler> handler(
763 new SaveFileResourceHandler(child_id,
764 route_id,
765 url,
766 save_file_manager_.get()));
767 request_id_--;
768
769 bool known_proto = net::URLRequest::IsHandledURL(url);
770 if (!known_proto) {
771 // Since any URLs which have non-standard scheme have been filtered
772 // by save manager(see GURL::SchemeIsStandard). This situation
773 // should not happen.
774 NOTREACHED();
775 return;
776 }
777
778 net::URLRequest* request = new net::URLRequest(url, this);
779 request->set_method("GET");
780 request->set_referrer(CommandLine::ForCurrentProcess()->HasSwitch(
781 switches::kNoReferrers) ? std::string() : referrer.spec());
782 // So far, for saving page, we need fetch content from cache, in the
783 // future, maybe we can use a configuration to configure this behavior.
784 request->set_load_flags(net::LOAD_PREFERRING_CACHE);
785 request->set_context(request_context);
786
787 // Since we're just saving some resources we need, disallow downloading.
788 ResourceDispatcherHostRequestInfo* extra_info =
789 CreateRequestInfoForBrowserRequest(handler, child_id, route_id, false);
790 SetRequestInfo(request, extra_info); // Request takes ownership.
791
792 BeginRequestInternal(request);
793 }
794
795 void ResourceDispatcherHost::FollowDeferredRedirect(
796 int child_id,
797 int request_id,
798 bool has_new_first_party_for_cookies,
799 const GURL& new_first_party_for_cookies) {
800 PendingRequestList::iterator i = pending_requests_.find(
801 GlobalRequestID(child_id, request_id));
802 if (i == pending_requests_.end() || !i->second->status().is_success()) {
803 DLOG(WARNING) << "FollowDeferredRedirect for invalid request";
804 return;
805 }
806
807 if (has_new_first_party_for_cookies)
808 i->second->set_first_party_for_cookies(new_first_party_for_cookies);
809 i->second->FollowDeferredRedirect();
810 }
811
812 void ResourceDispatcherHost::StartDeferredRequest(int process_unique_id,
813 int request_id) {
814 GlobalRequestID global_id(process_unique_id, request_id);
815 PendingRequestList::iterator i = pending_requests_.find(global_id);
816 if (i == pending_requests_.end()) {
817 // The request may have been destroyed
818 LOG(WARNING) << "Trying to resume a non-existent request ("
819 << process_unique_id << ", " << request_id << ")";
820 return;
821 }
822
823 // TODO(eroman): are there other considerations for paused or blocked
824 // requests?
825
826 net::URLRequest* request = i->second;
827 InsertIntoResourceQueue(request, *InfoForRequest(request));
828 }
829
830 bool ResourceDispatcherHost::WillSendData(int child_id,
831 int request_id) {
832 PendingRequestList::iterator i = pending_requests_.find(
833 GlobalRequestID(child_id, request_id));
834 if (i == pending_requests_.end()) {
835 NOTREACHED() << "WillSendData for invalid request";
836 return false;
837 }
838
839 ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second);
840
841 info->IncrementPendingDataCount();
842 if (info->pending_data_count() > kMaxPendingDataMessages) {
843 // We reached the max number of data messages that can be sent to
844 // the renderer for a given request. Pause the request and wait for
845 // the renderer to start processing them before resuming it.
846 PauseRequest(child_id, request_id, true);
847 return false;
848 }
849
850 return true;
851 }
852
853 void ResourceDispatcherHost::PauseRequest(int child_id,
854 int request_id,
855 bool pause) {
856 GlobalRequestID global_id(child_id, request_id);
857 PendingRequestList::iterator i = pending_requests_.find(global_id);
858 if (i == pending_requests_.end()) {
859 DLOG(WARNING) << "Pausing a request that wasn't found";
860 return;
861 }
862
863 ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second);
864 int pause_count = info->pause_count() + (pause ? 1 : -1);
865 if (pause_count < 0) {
866 NOTREACHED(); // Unbalanced call to pause.
867 return;
868 }
869 info->set_pause_count(pause_count);
870
871 VLOG(1) << "To pause (" << pause << "): " << i->second->url().spec();
872
873 // If we're resuming, kick the request to start reading again. Run the read
874 // asynchronously to avoid recursion problems.
875 if (info->pause_count() == 0) {
876 MessageLoop::current()->PostTask(FROM_HERE,
877 method_runner_.NewRunnableMethod(
878 &ResourceDispatcherHost::ResumeRequest, global_id));
879 }
880 }
881
882 int ResourceDispatcherHost::GetOutstandingRequestsMemoryCost(
883 int child_id) const {
884 OutstandingRequestsMemoryCostMap::const_iterator entry =
885 outstanding_requests_memory_cost_map_.find(child_id);
886 return (entry == outstanding_requests_memory_cost_map_.end()) ?
887 0 : entry->second;
888 }
889
890 // The object died, so cancel and detach all requests associated with it except
891 // for downloads, which belong to the browser process even if initiated via a
892 // renderer.
893 void ResourceDispatcherHost::CancelRequestsForProcess(int child_id) {
894 CancelRequestsForRoute(child_id, -1 /* cancel all */);
895 registered_temp_files_.erase(child_id);
896 }
897
898 void ResourceDispatcherHost::CancelRequestsForRoute(int child_id,
899 int route_id) {
900 // Since pending_requests_ is a map, we first build up a list of all of the
901 // matching requests to be cancelled, and then we cancel them. Since there
902 // may be more than one request to cancel, we cannot simply hold onto the map
903 // iterators found in the first loop.
904
905 // Find the global ID of all matching elements.
906 std::vector<GlobalRequestID> matching_requests;
907 for (PendingRequestList::const_iterator i = pending_requests_.begin();
908 i != pending_requests_.end(); ++i) {
909 if (i->first.child_id == child_id) {
910 ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second);
911 if (!info->is_download() &&
912 (route_id == -1 || route_id == info->route_id())) {
913 matching_requests.push_back(
914 GlobalRequestID(child_id, i->first.request_id));
915 }
916 }
917 }
918
919 // Remove matches.
920 for (size_t i = 0; i < matching_requests.size(); ++i) {
921 PendingRequestList::iterator iter =
922 pending_requests_.find(matching_requests[i]);
923 // Although every matching request was in pending_requests_ when we built
924 // matching_requests, it is normal for a matching request to be not found
925 // in pending_requests_ after we have removed some matching requests from
926 // pending_requests_. For example, deleting a net::URLRequest that has
927 // exclusive (write) access to an HTTP cache entry may unblock another
928 // net::URLRequest that needs exclusive access to the same cache entry, and
929 // that net::URLRequest may complete and remove itself from
930 // pending_requests_. So we need to check that iter is not equal to
931 // pending_requests_.end().
932 if (iter != pending_requests_.end())
933 RemovePendingRequest(iter);
934 }
935
936 // Now deal with blocked requests if any.
937 if (route_id != -1) {
938 if (blocked_requests_map_.find(std::pair<int, int>(child_id, route_id)) !=
939 blocked_requests_map_.end()) {
940 CancelBlockedRequestsForRoute(child_id, route_id);
941 }
942 } else {
943 // We have to do all render views for the process |child_id|.
944 // Note that we have to do this in 2 passes as we cannot call
945 // CancelBlockedRequestsForRoute while iterating over
946 // blocked_requests_map_, as it modifies it.
947 std::set<int> route_ids;
948 for (BlockedRequestMap::const_iterator iter = blocked_requests_map_.begin();
949 iter != blocked_requests_map_.end(); ++iter) {
950 if (iter->first.first == child_id)
951 route_ids.insert(iter->first.second);
952 }
953 for (std::set<int>::const_iterator iter = route_ids.begin();
954 iter != route_ids.end(); ++iter) {
955 CancelBlockedRequestsForRoute(child_id, *iter);
956 }
957 }
958 }
959
960 // Cancels the request and removes it from the list.
961 void ResourceDispatcherHost::RemovePendingRequest(int child_id,
962 int request_id) {
963 PendingRequestList::iterator i = pending_requests_.find(
964 GlobalRequestID(child_id, request_id));
965 if (i == pending_requests_.end()) {
966 NOTREACHED() << "Trying to remove a request that's not here";
967 return;
968 }
969 RemovePendingRequest(i);
970 }
971
972 void ResourceDispatcherHost::RemovePendingRequest(
973 const PendingRequestList::iterator& iter) {
974 ResourceDispatcherHostRequestInfo* info = InfoForRequest(iter->second);
975
976 // Remove the memory credit that we added when pushing the request onto
977 // the pending list.
978 IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(),
979 info->child_id());
980
981 // Notify interested parties that the request object is going away.
982 if (info->login_handler())
983 info->login_handler()->OnRequestCancelled();
984 if (info->ssl_client_auth_handler())
985 info->ssl_client_auth_handler()->OnRequestCancelled();
986 resource_queue_.RemoveRequest(iter->first);
987
988 delete iter->second;
989 pending_requests_.erase(iter);
990
991 // If we have no more pending requests, then stop the load state monitor
992 if (pending_requests_.empty())
993 update_load_states_timer_.Stop();
994 }
995
996 // net::URLRequest::Delegate ---------------------------------------------------
997
998 void ResourceDispatcherHost::OnReceivedRedirect(net::URLRequest* request,
999 const GURL& new_url,
1000 bool* defer_redirect) {
1001 VLOG(1) << "OnReceivedRedirect: " << request->url().spec();
1002 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1003
1004 DCHECK(request->status().is_success());
1005
1006 if (info->process_type() != ChildProcessInfo::PLUGIN_PROCESS &&
1007 !ChildProcessSecurityPolicy::GetInstance()->
1008 CanRequestURL(info->child_id(), new_url)) {
1009 VLOG(1) << "Denied unauthorized request for "
1010 << new_url.possibly_invalid_spec();
1011
1012 // Tell the renderer that this request was disallowed.
1013 CancelRequestInternal(request, false);
1014 return;
1015 }
1016
1017 NotifyReceivedRedirect(request, info->child_id(), new_url);
1018
1019 if (HandleExternalProtocol(info->request_id(), info->child_id(),
1020 info->route_id(), new_url,
1021 info->resource_type(), info->resource_handler())) {
1022 // The request is complete so we can remove it.
1023 RemovePendingRequest(info->child_id(), info->request_id());
1024 return;
1025 }
1026
1027 scoped_refptr<ResourceResponse> response(new ResourceResponse);
1028 PopulateResourceResponse(request,
1029 info->replace_extension_localization_templates(), response);
1030 if (!info->resource_handler()->OnRequestRedirected(info->request_id(),
1031 new_url,
1032 response, defer_redirect))
1033 CancelRequestInternal(request, false);
1034 }
1035
1036 void ResourceDispatcherHost::OnAuthRequired(
1037 net::URLRequest* request,
1038 net::AuthChallengeInfo* auth_info) {
1039 if (request->load_flags() & net::LOAD_PREFETCH) {
1040 request->CancelAuth();
1041 return;
1042 }
1043 // Create a login dialog on the UI thread to get authentication data,
1044 // or pull from cache and continue on the IO thread.
1045 // TODO(mpcomplete): We should block the parent tab while waiting for
1046 // authentication.
1047 // That would also solve the problem of the net::URLRequest being cancelled
1048 // before we receive authentication.
1049 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1050 DCHECK(!info->login_handler()) <<
1051 "OnAuthRequired called with login_handler pending";
1052 info->set_login_handler(CreateLoginPrompt(auth_info, request));
1053 }
1054
1055 void ResourceDispatcherHost::OnCertificateRequested(
1056 net::URLRequest* request,
1057 net::SSLCertRequestInfo* cert_request_info) {
1058 DCHECK(request);
1059
1060 if (cert_request_info->client_certs.empty()) {
1061 // No need to query the user if there are no certs to choose from.
1062 request->ContinueWithCertificate(NULL);
1063 return;
1064 }
1065
1066 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1067 DCHECK(!info->ssl_client_auth_handler()) <<
1068 "OnCertificateRequested called with ssl_client_auth_handler pending";
1069 info->set_ssl_client_auth_handler(
1070 new SSLClientAuthHandler(request, cert_request_info));
1071 info->ssl_client_auth_handler()->SelectCertificate();
1072 }
1073
1074 void ResourceDispatcherHost::OnSSLCertificateError(
1075 net::URLRequest* request,
1076 int cert_error,
1077 net::X509Certificate* cert) {
1078 DCHECK(request);
1079 SSLManager::OnSSLCertificateError(this, request, cert_error, cert);
1080 }
1081
1082 void ResourceDispatcherHost::OnGetCookies(
1083 net::URLRequest* request,
1084 bool blocked_by_policy) {
1085 VLOG(1) << "OnGetCookies: " << request->url().spec();
1086
1087 int render_process_id, render_view_id;
1088 if (!RenderViewForRequest(request, &render_process_id, &render_view_id))
1089 return;
1090
1091 net::URLRequestContext* context = request->context();
1092
1093 net::CookieMonster* cookie_monster =
1094 context->cookie_store()->GetCookieMonster();
1095 net::CookieList cookie_list =
1096 cookie_monster->GetAllCookiesForURL(request->url());
1097 CallRenderViewHostContentSettingsDelegate(
1098 render_process_id, render_view_id,
1099 &RenderViewHostDelegate::ContentSettings::OnCookiesRead,
1100 request->url(), cookie_list, blocked_by_policy);
1101 }
1102
1103 void ResourceDispatcherHost::OnSetCookie(net::URLRequest* request,
1104 const std::string& cookie_line,
1105 const net::CookieOptions& options,
1106 bool blocked_by_policy) {
1107 VLOG(1) << "OnSetCookie: " << request->url().spec();
1108
1109 int render_process_id, render_view_id;
1110 if (!RenderViewForRequest(request, &render_process_id, &render_view_id))
1111 return;
1112
1113 CallRenderViewHostContentSettingsDelegate(
1114 render_process_id, render_view_id,
1115 &RenderViewHostDelegate::ContentSettings::OnCookieChanged,
1116 request->url(), cookie_line, options, blocked_by_policy);
1117 }
1118
1119 void ResourceDispatcherHost::OnResponseStarted(net::URLRequest* request) {
1120 VLOG(1) << "OnResponseStarted: " << request->url().spec();
1121 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1122 if (PauseRequestIfNeeded(info)) {
1123 VLOG(1) << "OnResponseStarted pausing: " << request->url().spec();
1124 return;
1125 }
1126
1127 if (request->status().is_success()) {
1128 // We want to send a final upload progress message prior to sending
1129 // the response complete message even if we're waiting for an ack to
1130 // to a previous upload progress message.
1131 info->set_waiting_for_upload_progress_ack(false);
1132 MaybeUpdateUploadProgress(info, request);
1133
1134 if (!CompleteResponseStarted(request)) {
1135 CancelRequestInternal(request, false);
1136 } else {
1137 // Check if the handler paused the request in their OnResponseStarted.
1138 if (PauseRequestIfNeeded(info)) {
1139 VLOG(1) << "OnResponseStarted pausing2: " << request->url().spec();
1140 return;
1141 }
1142
1143 StartReading(request);
1144 }
1145 } else {
1146 OnResponseCompleted(request);
1147 }
1148 }
1149
1150 bool ResourceDispatcherHost::CompleteResponseStarted(net::URLRequest* request) {
1151 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1152
1153 scoped_refptr<ResourceResponse> response(new ResourceResponse);
1154 PopulateResourceResponse(request,
1155 info->replace_extension_localization_templates(), response);
1156
1157 if (request->ssl_info().cert) {
1158 int cert_id =
1159 CertStore::GetInstance()->StoreCert(request->ssl_info().cert,
1160 info->child_id());
1161 response->response_head.security_info =
1162 SSLManager::SerializeSecurityInfo(
1163 cert_id, request->ssl_info().cert_status,
1164 request->ssl_info().security_bits,
1165 request->ssl_info().connection_status);
1166 } else {
1167 // We should not have any SSL state.
1168 DCHECK(!request->ssl_info().cert_status &&
1169 request->ssl_info().security_bits == -1 &&
1170 !request->ssl_info().connection_status);
1171 }
1172
1173 NotifyResponseStarted(request, info->child_id());
1174 info->set_called_on_response_started(true);
1175 return info->resource_handler()->OnResponseStarted(info->request_id(),
1176 response.get());
1177 }
1178
1179 void ResourceDispatcherHost::CancelRequest(int child_id,
1180 int request_id,
1181 bool from_renderer) {
1182 PendingRequestList::iterator i = pending_requests_.find(
1183 GlobalRequestID(child_id, request_id));
1184 if (i == pending_requests_.end()) {
1185 // We probably want to remove this warning eventually, but I wanted to be
1186 // able to notice when this happens during initial development since it
1187 // should be rare and may indicate a bug.
1188 DLOG(WARNING) << "Canceling a request that wasn't found";
1189 return;
1190 }
1191 CancelRequestInternal(i->second, from_renderer);
1192 }
1193
1194 void ResourceDispatcherHost::CancelRequestInternal(net::URLRequest* request,
1195 bool from_renderer) {
1196 VLOG(1) << "CancelRequest: " << request->url().spec();
1197
1198 // WebKit will send us a cancel for downloads since it no longer handles them.
1199 // In this case, ignore the cancel since we handle downloads in the browser.
1200 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1201 if (!from_renderer || !info->is_download()) {
1202 if (info->login_handler()) {
1203 info->login_handler()->OnRequestCancelled();
1204 info->set_login_handler(NULL);
1205 }
1206 if (info->ssl_client_auth_handler()) {
1207 info->ssl_client_auth_handler()->OnRequestCancelled();
1208 info->set_ssl_client_auth_handler(NULL);
1209 }
1210 request->Cancel();
1211 // Our callers assume |request| is valid after we return.
1212 DCHECK(IsValidRequest(request));
1213 }
1214
1215 // Do not remove from the pending requests, as the request will still
1216 // call AllDataReceived, and may even have more data before it does
1217 // that.
1218 }
1219
1220 int ResourceDispatcherHost::IncrementOutstandingRequestsMemoryCost(
1221 int cost,
1222 int child_id) {
1223 // Retrieve the previous value (defaulting to 0 if not found).
1224 OutstandingRequestsMemoryCostMap::iterator prev_entry =
1225 outstanding_requests_memory_cost_map_.find(child_id);
1226 int new_cost = 0;
1227 if (prev_entry != outstanding_requests_memory_cost_map_.end())
1228 new_cost = prev_entry->second;
1229
1230 // Insert/update the total; delete entries when their value reaches 0.
1231 new_cost += cost;
1232 CHECK(new_cost >= 0);
1233 if (new_cost == 0)
1234 outstanding_requests_memory_cost_map_.erase(prev_entry);
1235 else
1236 outstanding_requests_memory_cost_map_[child_id] = new_cost;
1237
1238 return new_cost;
1239 }
1240
1241 // static
1242 int ResourceDispatcherHost::CalculateApproximateMemoryCost(
1243 net::URLRequest* request) {
1244 // The following fields should be a minor size contribution (experimentally
1245 // on the order of 100). However since they are variable length, it could
1246 // in theory be a sizeable contribution.
1247 int strings_cost = request->extra_request_headers().ToString().size() +
1248 request->original_url().spec().size() +
1249 request->referrer().size() +
1250 request->method().size();
1251
1252 int upload_cost = 0;
1253
1254 // TODO(eroman): don't enable the upload throttling until we have data
1255 // showing what a reasonable limit is (limiting to 25MB of uploads may
1256 // be too restrictive).
1257 #if 0
1258 // Sum all the (non-file) upload data attached to the request, if any.
1259 if (request->has_upload()) {
1260 const std::vector<net::UploadData::Element>& uploads =
1261 request->get_upload()->elements();
1262 std::vector<net::UploadData::Element>::const_iterator iter;
1263 for (iter = uploads.begin(); iter != uploads.end(); ++iter) {
1264 if (iter->type() == net::UploadData::TYPE_BYTES) {
1265 int64 element_size = iter->GetContentLength();
1266 // This cast should not result in truncation.
1267 upload_cost += static_cast<int>(element_size);
1268 }
1269 }
1270 }
1271 #endif
1272
1273 // Note that this expression will typically be dominated by:
1274 // |kAvgBytesPerOutstandingRequest|.
1275 return kAvgBytesPerOutstandingRequest + strings_cost + upload_cost;
1276 }
1277
1278 void ResourceDispatcherHost::BeginRequestInternal(net::URLRequest* request) {
1279 DCHECK(!request->is_pending());
1280 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1281
1282 // Add the memory estimate that starting this request will consume.
1283 info->set_memory_cost(CalculateApproximateMemoryCost(request));
1284 int memory_cost = IncrementOutstandingRequestsMemoryCost(info->memory_cost(),
1285 info->child_id());
1286
1287 // If enqueing/starting this request will exceed our per-process memory
1288 // bound, abort it right away.
1289 if (memory_cost > max_outstanding_requests_cost_per_process_) {
1290 // We call "SimulateError()" as a way of setting the net::URLRequest's
1291 // status -- it has no effect beyond this, since the request hasn't started.
1292 request->SimulateError(net::ERR_INSUFFICIENT_RESOURCES);
1293
1294 // TODO(eroman): this is kinda funky -- we insert the unstarted request into
1295 // |pending_requests_| simply to please OnResponseCompleted().
1296 GlobalRequestID global_id(info->child_id(), info->request_id());
1297 pending_requests_[global_id] = request;
1298 OnResponseCompleted(request);
1299 return;
1300 }
1301
1302 std::pair<int, int> pair_id(info->child_id(), info->route_id());
1303 BlockedRequestMap::const_iterator iter = blocked_requests_map_.find(pair_id);
1304 if (iter != blocked_requests_map_.end()) {
1305 // The request should be blocked.
1306 iter->second->push_back(request);
1307 return;
1308 }
1309
1310 GlobalRequestID global_id(info->child_id(), info->request_id());
1311 pending_requests_[global_id] = request;
1312
1313 // Give the resource handlers an opportunity to delay the net::URLRequest from
1314 // being started.
1315 //
1316 // There are three cases:
1317 //
1318 // (1) if OnWillStart() returns false, the request is cancelled (regardless
1319 // of whether |defer_start| was set).
1320 // (2) If |defer_start| was set to true, then the request is not added
1321 // into the resource queue, and will only be started in response to
1322 // calling StartDeferredRequest().
1323 // (3) If |defer_start| is not set, then the request is inserted into
1324 // the resource_queue_ (which may pause it further, or start it).
1325 bool defer_start = false;
1326 if (!info->resource_handler()->OnWillStart(
1327 info->request_id(), request->url(),
1328 &defer_start)) {
1329 CancelRequestInternal(request, false);
1330 return;
1331 }
1332
1333 if (!defer_start) {
1334 InsertIntoResourceQueue(request, *info);
1335 }
1336 }
1337
1338 void ResourceDispatcherHost::InsertIntoResourceQueue(
1339 net::URLRequest* request,
1340 const ResourceDispatcherHostRequestInfo& request_info) {
1341 resource_queue_.AddRequest(request, request_info);
1342
1343 // Make sure we have the load state monitor running
1344 if (!update_load_states_timer_.IsRunning()) {
1345 update_load_states_timer_.Start(
1346 TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec),
1347 this, &ResourceDispatcherHost::UpdateLoadStates);
1348 }
1349 }
1350
1351 bool ResourceDispatcherHost::PauseRequestIfNeeded(
1352 ResourceDispatcherHostRequestInfo* info) {
1353 if (info->pause_count() > 0)
1354 info->set_is_paused(true);
1355 return info->is_paused();
1356 }
1357
1358 void ResourceDispatcherHost::ResumeRequest(const GlobalRequestID& request_id) {
1359 PendingRequestList::iterator i = pending_requests_.find(request_id);
1360 if (i == pending_requests_.end()) // The request may have been destroyed
1361 return;
1362
1363 net::URLRequest* request = i->second;
1364 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1365 if (!info->is_paused())
1366 return;
1367
1368 VLOG(1) << "Resuming: " << i->second->url().spec();
1369
1370 info->set_is_paused(false);
1371
1372 if (info->called_on_response_started()) {
1373 if (info->has_started_reading()) {
1374 OnReadCompleted(i->second, info->paused_read_bytes());
1375 } else {
1376 StartReading(request);
1377 }
1378 } else {
1379 OnResponseStarted(i->second);
1380 }
1381 }
1382
1383 void ResourceDispatcherHost::StartReading(net::URLRequest* request) {
1384 // Start reading.
1385 int bytes_read = 0;
1386 if (Read(request, &bytes_read)) {
1387 OnReadCompleted(request, bytes_read);
1388 } else if (!request->status().is_io_pending()) {
1389 DCHECK(!InfoForRequest(request)->is_paused());
1390 // If the error is not an IO pending, then we're done reading.
1391 OnResponseCompleted(request);
1392 }
1393 }
1394
1395 bool ResourceDispatcherHost::Read(net::URLRequest* request, int* bytes_read) {
1396 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1397 DCHECK(!info->is_paused());
1398
1399 net::IOBuffer* buf;
1400 int buf_size;
1401 if (!info->resource_handler()->OnWillRead(info->request_id(),
1402 &buf, &buf_size, -1)) {
1403 return false;
1404 }
1405
1406 DCHECK(buf);
1407 DCHECK(buf_size > 0);
1408
1409 info->set_has_started_reading(true);
1410 return request->Read(buf, buf_size, bytes_read);
1411 }
1412
1413 void ResourceDispatcherHost::OnReadCompleted(net::URLRequest* request,
1414 int bytes_read) {
1415 DCHECK(request);
1416 VLOG(1) << "OnReadCompleted: " << request->url().spec();
1417 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1418
1419 // OnReadCompleted can be called without Read (e.g., for chrome:// URLs).
1420 // Make sure we know that a read has begun.
1421 info->set_has_started_reading(true);
1422
1423 if (PauseRequestIfNeeded(info)) {
1424 info->set_paused_read_bytes(bytes_read);
1425 VLOG(1) << "OnReadCompleted pausing: " << request->url().spec();
1426 return;
1427 }
1428
1429 if (request->status().is_success() && CompleteRead(request, &bytes_read)) {
1430 // The request can be paused if we realize that the renderer is not
1431 // servicing messages fast enough.
1432 if (info->pause_count() == 0 &&
1433 Read(request, &bytes_read) &&
1434 request->status().is_success()) {
1435 if (bytes_read == 0) {
1436 CompleteRead(request, &bytes_read);
1437 } else {
1438 // Force the next CompleteRead / Read pair to run as a separate task.
1439 // This avoids a fast, large network request from monopolizing the IO
1440 // thread and starving other IO operations from running.
1441 info->set_paused_read_bytes(bytes_read);
1442 info->set_is_paused(true);
1443 GlobalRequestID id(info->child_id(), info->request_id());
1444 MessageLoop::current()->PostTask(
1445 FROM_HERE,
1446 method_runner_.NewRunnableMethod(
1447 &ResourceDispatcherHost::ResumeRequest, id));
1448 return;
1449 }
1450 }
1451 }
1452
1453 if (PauseRequestIfNeeded(info)) {
1454 info->set_paused_read_bytes(bytes_read);
1455 VLOG(1) << "OnReadCompleted (CompleteRead) pausing: "
1456 << request->url().spec();
1457 return;
1458 }
1459
1460 // If the status is not IO pending then we've either finished (success) or we
1461 // had an error. Either way, we're done!
1462 if (!request->status().is_io_pending())
1463 OnResponseCompleted(request);
1464 }
1465
1466 bool ResourceDispatcherHost::CompleteRead(net::URLRequest* request,
1467 int* bytes_read) {
1468 if (!request || !request->status().is_success()) {
1469 NOTREACHED();
1470 return false;
1471 }
1472
1473 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1474 if (!info->resource_handler()->OnReadCompleted(info->request_id(),
1475 bytes_read)) {
1476 CancelRequestInternal(request, false);
1477 return false;
1478 }
1479
1480 return *bytes_read != 0;
1481 }
1482
1483 void ResourceDispatcherHost::OnResponseCompleted(net::URLRequest* request) {
1484 VLOG(1) << "OnResponseCompleted: " << request->url().spec();
1485 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1486
1487 // If the load for a main frame has failed, track it in a histogram,
1488 // since it will probably cause the user to see an error page.
1489 if (!request->status().is_success() &&
1490 info->resource_type() == ResourceType::MAIN_FRAME &&
1491 request->status().os_error() != net::ERR_ABORTED) {
1492 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.ErrorCodesForMainFrame",
1493 -request->status().os_error(),
1494 GetAllNetErrorCodes());
1495 }
1496
1497 std::string security_info;
1498 const net::SSLInfo& ssl_info = request->ssl_info();
1499 if (ssl_info.cert != NULL) {
1500 int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert,
1501 info->child_id());
1502 security_info = SSLManager::SerializeSecurityInfo(
1503 cert_id, ssl_info.cert_status, ssl_info.security_bits,
1504 ssl_info.connection_status);
1505 }
1506
1507 if (info->resource_handler()->OnResponseCompleted(info->request_id(),
1508 request->status(),
1509 security_info)) {
1510 NotifyResponseCompleted(request, info->child_id());
1511
1512 // The request is complete so we can remove it.
1513 RemovePendingRequest(info->child_id(), info->request_id());
1514 }
1515 // If the handler's OnResponseCompleted returns false, we are deferring the
1516 // call until later. We will notify the world and clean up when we resume.
1517 }
1518
1519 // static
1520 ResourceDispatcherHostRequestInfo* ResourceDispatcherHost::InfoForRequest(
1521 net::URLRequest* request) {
1522 // Avoid writing this function twice by casting the cosnt version.
1523 const net::URLRequest* const_request = request;
1524 return const_cast<ResourceDispatcherHostRequestInfo*>(
1525 InfoForRequest(const_request));
1526 }
1527
1528 // static
1529 const ResourceDispatcherHostRequestInfo* ResourceDispatcherHost::InfoForRequest(
1530 const net::URLRequest* request) {
1531 const ResourceDispatcherHostRequestInfo* info =
1532 static_cast<const ResourceDispatcherHostRequestInfo*>(
1533 request->GetUserData(NULL));
1534 DLOG_IF(WARNING, !info) << "Request doesn't seem to have our data";
1535 return info;
1536 }
1537
1538 // static
1539 bool ResourceDispatcherHost::RenderViewForRequest(
1540 const net::URLRequest* request,
1541 int* render_process_host_id,
1542 int* render_view_host_id) {
1543 const ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1544 if (!info) {
1545 *render_process_host_id = -1;
1546 *render_view_host_id = -1;
1547 return false;
1548 }
1549
1550 // If the request is from the worker process, find a tab that owns the worker.
1551 if (info->process_type() == ChildProcessInfo::WORKER_PROCESS) {
1552 // Need to display some related UI for this network request - pick an
1553 // arbitrary parent to do so.
1554 if (!WorkerService::GetInstance()->GetRendererForWorker(
1555 info->child_id(), render_process_host_id, render_view_host_id)) {
1556 *render_process_host_id = -1;
1557 *render_view_host_id = -1;
1558 return false;
1559 }
1560 } else {
1561 *render_process_host_id = info->child_id();
1562 *render_view_host_id = info->route_id();
1563 }
1564 return true;
1565 }
1566
1567 void ResourceDispatcherHost::AddObserver(Observer* obs) {
1568 observer_list_.AddObserver(obs);
1569 }
1570
1571 void ResourceDispatcherHost::RemoveObserver(Observer* obs) {
1572 observer_list_.RemoveObserver(obs);
1573 }
1574
1575 net::URLRequest* ResourceDispatcherHost::GetURLRequest(
1576 const GlobalRequestID& request_id) const {
1577 // This should be running in the IO loop.
1578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1579
1580 PendingRequestList::const_iterator i = pending_requests_.find(request_id);
1581 if (i == pending_requests_.end())
1582 return NULL;
1583
1584 return i->second;
1585 }
1586
1587 static int GetCertID(net::URLRequest* request, int child_id) {
1588 if (request->ssl_info().cert) {
1589 return CertStore::GetInstance()->StoreCert(request->ssl_info().cert,
1590 child_id);
1591 }
1592 return 0;
1593 }
1594
1595 void ResourceDispatcherHost::NotifyResponseStarted(net::URLRequest* request,
1596 int child_id) {
1597 // Notify the observers on the IO thread.
1598 FOR_EACH_OBSERVER(Observer, observer_list_, OnRequestStarted(this, request));
1599
1600 int render_process_id, render_view_id;
1601 if (!RenderViewForRequest(request, &render_process_id, &render_view_id))
1602 return;
1603
1604 // Notify the observers on the UI thread.
1605 ResourceRequestDetails* detail = new ResourceRequestDetails(
1606 request, GetCertID(request, child_id));
1607 BrowserThread::PostTask(
1608 BrowserThread::UI, FROM_HERE,
1609 NewRunnableFunction(
1610 &ResourceDispatcherHost::NotifyOnUI<ResourceRequestDetails>,
1611 NotificationType::RESOURCE_RESPONSE_STARTED,
1612 render_process_id, render_view_id, detail));
1613 }
1614
1615 void ResourceDispatcherHost::NotifyResponseCompleted(net::URLRequest* request,
1616 int child_id) {
1617 // Notify the observers on the IO thread.
1618 FOR_EACH_OBSERVER(Observer, observer_list_,
1619 OnResponseCompleted(this, request));
1620 }
1621
1622 void ResourceDispatcherHost::NotifyReceivedRedirect(net::URLRequest* request,
1623 int child_id,
1624 const GURL& new_url) {
1625 // Notify the observers on the IO thread.
1626 FOR_EACH_OBSERVER(Observer, observer_list_,
1627 OnReceivedRedirect(this, request, new_url));
1628
1629 int render_process_id, render_view_id;
1630 if (!RenderViewForRequest(request, &render_process_id, &render_view_id))
1631 return;
1632
1633 // Notify the observers on the UI thread.
1634 ResourceRedirectDetails* detail = new ResourceRedirectDetails(
1635 request, GetCertID(request, child_id), new_url);
1636 BrowserThread::PostTask(
1637 BrowserThread::UI, FROM_HERE,
1638 NewRunnableFunction(
1639 &ResourceDispatcherHost::NotifyOnUI<ResourceRedirectDetails>,
1640 NotificationType::RESOURCE_RECEIVED_REDIRECT,
1641 render_process_id, render_view_id, detail));
1642 }
1643
1644 template <class T>
1645 void ResourceDispatcherHost::NotifyOnUI(NotificationType type,
1646 int render_process_id,
1647 int render_view_id,
1648 T* detail) {
1649 RenderViewHost* rvh =
1650 RenderViewHost::FromID(render_process_id, render_view_id);
1651 if (rvh) {
1652 RenderViewHostDelegate* rvhd = rvh->delegate();
1653 NotificationService::current()->Notify(
1654 type, Source<RenderViewHostDelegate>(rvhd), Details<T>(detail));
1655 }
1656 delete detail;
1657 }
1658
1659 namespace {
1660
1661 // This function attempts to return the "more interesting" load state of |a|
1662 // and |b|. We don't have temporal information about these load states
1663 // (meaning we don't know when we transitioned into these states), so we just
1664 // rank them according to how "interesting" the states are.
1665 //
1666 // We take advantage of the fact that the load states are an enumeration listed
1667 // in the order in which they occur during the lifetime of a request, so we can
1668 // regard states with larger numeric values as being further along toward
1669 // completion. We regard those states as more interesting to report since they
1670 // represent progress.
1671 //
1672 // For example, by this measure "tranferring data" is a more interesting state
1673 // than "resolving host" because when we are transferring data we are actually
1674 // doing something that corresponds to changes that the user might observe,
1675 // whereas waiting for a host name to resolve implies being stuck.
1676 //
1677 net::LoadState MoreInterestingLoadState(net::LoadState a, net::LoadState b) {
1678 return (a < b) ? b : a;
1679 }
1680
1681 // Carries information about a load state change.
1682 struct LoadInfo {
1683 GURL url;
1684 net::LoadState load_state;
1685 uint64 upload_position;
1686 uint64 upload_size;
1687 };
1688
1689 // Map from ProcessID+ViewID pair to LoadState
1690 typedef std::map<std::pair<int, int>, LoadInfo> LoadInfoMap;
1691
1692 // Used to marshall calls to LoadStateChanged from the IO to UI threads. We do
1693 // them all as a single task to avoid spamming the UI thread.
1694 class LoadInfoUpdateTask : public Task {
1695 public:
1696 virtual void Run() {
1697 LoadInfoMap::const_iterator i;
1698 for (i = info_map.begin(); i != info_map.end(); ++i) {
1699 RenderViewHost* view =
1700 RenderViewHost::FromID(i->first.first, i->first.second);
1701 if (view) // The view could be gone at this point.
1702 view->LoadStateChanged(i->second.url, i->second.load_state,
1703 i->second.upload_position,
1704 i->second.upload_size);
1705 }
1706 }
1707 LoadInfoMap info_map;
1708 };
1709
1710 } // namespace
1711
1712 void ResourceDispatcherHost::UpdateLoadStates() {
1713 // Populate this map with load state changes, and then send them on to the UI
1714 // thread where they can be passed along to the respective RVHs.
1715 LoadInfoMap info_map;
1716
1717 PendingRequestList::const_iterator i;
1718
1719 // Determine the largest upload size of all requests
1720 // in each View (good chance it's zero).
1721 std::map<std::pair<int, int>, uint64> largest_upload_size;
1722 for (i = pending_requests_.begin(); i != pending_requests_.end(); ++i) {
1723 net::URLRequest* request = i->second;
1724 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1725 uint64 upload_size = info->upload_size();
1726 if (request->GetLoadState() != net::LOAD_STATE_SENDING_REQUEST)
1727 upload_size = 0;
1728 std::pair<int, int> key(info->child_id(), info->route_id());
1729 if (upload_size && largest_upload_size[key] < upload_size)
1730 largest_upload_size[key] = upload_size;
1731 }
1732
1733 for (i = pending_requests_.begin(); i != pending_requests_.end(); ++i) {
1734 net::URLRequest* request = i->second;
1735 net::LoadState load_state = request->GetLoadState();
1736 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1737
1738 // We also poll for upload progress on this timer and send upload
1739 // progress ipc messages to the plugin process.
1740 bool update_upload_progress = MaybeUpdateUploadProgress(info, request);
1741
1742 if (info->last_load_state() != load_state || update_upload_progress) {
1743 std::pair<int, int> key(info->child_id(), info->route_id());
1744
1745 // If a request is uploading data, ignore all other requests so that the
1746 // upload progress takes priority for being shown in the status bar.
1747 if (largest_upload_size.find(key) != largest_upload_size.end() &&
1748 info->upload_size() < largest_upload_size[key])
1749 continue;
1750
1751 info->set_last_load_state(load_state);
1752
1753 net::LoadState to_insert;
1754 LoadInfoMap::iterator existing = info_map.find(key);
1755 if (existing == info_map.end()) {
1756 to_insert = load_state;
1757 } else {
1758 to_insert =
1759 MoreInterestingLoadState(existing->second.load_state, load_state);
1760 if (to_insert == existing->second.load_state)
1761 continue;
1762 }
1763 LoadInfo& load_info = info_map[key];
1764 load_info.url = request->url();
1765 load_info.load_state = to_insert;
1766 load_info.upload_size = info->upload_size();
1767 load_info.upload_position = request->GetUploadProgress();
1768 }
1769 }
1770
1771 if (info_map.empty())
1772 return;
1773
1774 LoadInfoUpdateTask* task = new LoadInfoUpdateTask;
1775 task->info_map.swap(info_map);
1776 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
1777 }
1778
1779 // Calls the ResourceHandler to send upload progress messages to the renderer.
1780 // Returns true iff an upload progress message should be sent to the UI thread.
1781 bool ResourceDispatcherHost::MaybeUpdateUploadProgress(
1782 ResourceDispatcherHostRequestInfo *info,
1783 net::URLRequest *request) {
1784
1785 if (!info->upload_size() || info->waiting_for_upload_progress_ack())
1786 return false;
1787
1788 uint64 size = info->upload_size();
1789 uint64 position = request->GetUploadProgress();
1790 if (position == info->last_upload_position())
1791 return false; // no progress made since last time
1792
1793 const uint64 kHalfPercentIncrements = 200;
1794 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
1795
1796 uint64 amt_since_last = position - info->last_upload_position();
1797 TimeDelta time_since_last = TimeTicks::Now() - info->last_upload_ticks();
1798
1799 bool is_finished = (size == position);
1800 bool enough_new_progress = (amt_since_last > (size / kHalfPercentIncrements));
1801 bool too_much_time_passed = time_since_last > kOneSecond;
1802
1803 if (is_finished || enough_new_progress || too_much_time_passed) {
1804 if (request->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
1805 info->resource_handler()->OnUploadProgress(info->request_id(),
1806 position, size);
1807 info->set_waiting_for_upload_progress_ack(true);
1808 }
1809 info->set_last_upload_ticks(TimeTicks::Now());
1810 info->set_last_upload_position(position);
1811 return true;
1812 }
1813 return false;
1814 }
1815
1816 void ResourceDispatcherHost::BlockRequestsForRoute(int child_id, int route_id) {
1817 std::pair<int, int> key(child_id, route_id);
1818 DCHECK(blocked_requests_map_.find(key) == blocked_requests_map_.end()) <<
1819 "BlockRequestsForRoute called multiple time for the same RVH";
1820 blocked_requests_map_[key] = new BlockedRequestsList();
1821 }
1822
1823 void ResourceDispatcherHost::ResumeBlockedRequestsForRoute(int child_id,
1824 int route_id) {
1825 ProcessBlockedRequestsForRoute(child_id, route_id, false);
1826 }
1827
1828 void ResourceDispatcherHost::CancelBlockedRequestsForRoute(int child_id,
1829 int route_id) {
1830 ProcessBlockedRequestsForRoute(child_id, route_id, true);
1831 }
1832
1833 void ResourceDispatcherHost::ProcessBlockedRequestsForRoute(
1834 int child_id,
1835 int route_id,
1836 bool cancel_requests) {
1837 BlockedRequestMap::iterator iter = blocked_requests_map_.find(
1838 std::pair<int, int>(child_id, route_id));
1839 if (iter == blocked_requests_map_.end()) {
1840 // It's possible to reach here if the renderer crashed while an interstitial
1841 // page was showing.
1842 return;
1843 }
1844
1845 BlockedRequestsList* requests = iter->second;
1846
1847 // Removing the vector from the map unblocks any subsequent requests.
1848 blocked_requests_map_.erase(iter);
1849
1850 for (BlockedRequestsList::iterator req_iter = requests->begin();
1851 req_iter != requests->end(); ++req_iter) {
1852 // Remove the memory credit that we added when pushing the request onto
1853 // the blocked list.
1854 net::URLRequest* request = *req_iter;
1855 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1856 IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(),
1857 info->child_id());
1858 if (cancel_requests)
1859 delete request;
1860 else
1861 BeginRequestInternal(request);
1862 }
1863
1864 delete requests;
1865 }
1866
1867 bool ResourceDispatcherHost::IsValidRequest(net::URLRequest* request) {
1868 if (!request)
1869 return false;
1870 ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
1871 return pending_requests_.find(
1872 GlobalRequestID(info->child_id(), info->request_id())) !=
1873 pending_requests_.end();
1874 }
1875
1876 // static
1877 void ResourceDispatcherHost::ApplyExtensionLocalizationFilter(
1878 const GURL& url,
1879 const ResourceType::Type& resource_type,
1880 ResourceDispatcherHostRequestInfo* request_info) {
1881 // Apply filter to chrome extension CSS files.
1882 if (url.SchemeIs(chrome::kExtensionScheme) &&
1883 resource_type == ResourceType::STYLESHEET)
1884 request_info->set_replace_extension_localization_templates();
1885 }
1886
1887 // static
1888 net::RequestPriority ResourceDispatcherHost::DetermineRequestPriority(
1889 ResourceType::Type type) {
1890 // Determine request priority based on how critical this resource typically
1891 // is to user-perceived page load performance. Important considerations are:
1892 // * Can this resource block the download of other resources.
1893 // * Can this resource block the rendering of the page.
1894 // * How useful is the page to the user if this resource is not loaded yet.
1895 switch (type) {
1896 // Main frames are the highest priority because they can block nearly every
1897 // type of other resource and there is no useful display without them.
1898 // Sub frames are a close second, however it is a common pattern to wrap
1899 // ads in an iframe or even in multiple nested iframes. It is worth
1900 // investigating if there is a better priority for them.
1901 case ResourceType::MAIN_FRAME:
1902 case ResourceType::SUB_FRAME:
1903 return net::HIGHEST;
1904
1905 // Stylesheets and scripts can block rendering and loading of other
1906 // resources. Fonts can block text from rendering.
1907 case ResourceType::STYLESHEET:
1908 case ResourceType::SCRIPT:
1909 case ResourceType::FONT_RESOURCE:
1910 return net::MEDIUM;
1911
1912 // Sub resources, objects and media are lower priority than potentially
1913 // blocking stylesheets, scripts and fonts, but are higher priority than
1914 // images because if they exist they are probably more central to the page
1915 // focus than images on the page.
1916 case ResourceType::SUB_RESOURCE:
1917 case ResourceType::OBJECT:
1918 case ResourceType::MEDIA:
1919 case ResourceType::WORKER:
1920 case ResourceType::SHARED_WORKER:
1921 return net::LOW;
1922
1923 // Images are the "lowest" priority because they typically do not block
1924 // downloads or rendering and most pages have some useful content without
1925 // them.
1926 case ResourceType::IMAGE:
1927 return net::LOWEST;
1928
1929 // Prefetches are at a lower priority than even LOWEST, since they
1930 // are not even required for rendering of the current page.
1931 case ResourceType::PREFETCH:
1932 return net::IDLE;
1933
1934 default:
1935 // When new resource types are added, their priority must be considered.
1936 NOTREACHED();
1937 return net::LOW;
1938 }
1939 }
1940
1941 // static
1942 bool ResourceDispatcherHost::is_prefetch_enabled() {
1943 return is_prefetch_enabled_;
1944 }
1945
1946 // static
1947 void ResourceDispatcherHost::set_is_prefetch_enabled(bool value) {
1948 is_prefetch_enabled_ = value;
1949 }
1950
1951 // static
1952 bool ResourceDispatcherHost::is_prefetch_enabled_ = false;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698