summaryrefslogtreecommitdiffstats
path: root/chrome/browser/renderer_host/resource_dispatcher_host.h
blob: 840d2db42ba46610cfd220438726e2d712beb4d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This is the browser side of the resource dispatcher, it receives requests
// from the child process (i.e. [Renderer, Plugin, Worker]ProcessHost), and
// dispatches them to URLRequests. It then forwards the messages from the
// URLRequests back to the correct process for handling.
//
// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading

#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_H_
#pragma once

#include <map>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/observer_list.h"
#include "base/scoped_ptr.h"
#include "base/timer.h"
#include "chrome/common/child_process_info.h"
#include "chrome/browser/renderer_host/resource_queue.h"
#include "ipc/ipc_message.h"
#include "net/url_request/url_request.h"
#include "webkit/glue/resource_type.h"

class CrossSiteResourceHandler;
class DownloadFileManager;
class DownloadRequestLimiter;
class LoginHandler;
class PluginService;
class ResourceDispatcherHostRequestInfo;
class ResourceHandler;
class SafeBrowsingService;
class SaveFileManager;
class SocketStreamDispatcherHost;
class SSLClientAuthHandler;
class UserScriptListener;
class URLRequestContext;
class WebKitThread;
struct DownloadSaveInfo;
struct GlobalRequestID;
struct ViewHostMsg_Resource_Request;
struct ViewMsg_ClosePage_Params;

namespace webkit_blob {
class DeletableFileReference;
}

class ResourceDispatcherHost : public net::URLRequest::Delegate {
 public:
  // Implemented by the client of ResourceDispatcherHost to receive messages in
  // response to a resource load.  The messages are intended to be forwarded to
  // the ResourceDispatcher in the child process via an IPC channel that the
  // client manages.
  //
  // NOTE: This class unfortunately cannot be named 'Delegate' because that
  // conflicts with the name of ResourceDispatcherHost's base class.
  //
  // If the receiver is unable to send a given message (i.e., if Send returns
  // false), then the ResourceDispatcherHost assumes the receiver has failed,
  // and the given request will be dropped. (This happens, for example, when a
  // renderer crashes and the channel dies).
  class Receiver : public IPC::Message::Sender,
                   public ChildProcessInfo {
   public:
    // Returns the URLRequestContext for the given request.
    // If NULL is returned, the default context for the profile is used.
    virtual URLRequestContext* GetRequestContext(
        uint32 request_id,
        const ViewHostMsg_Resource_Request& request_data) = 0;

   protected:
    explicit Receiver(ChildProcessInfo::ProcessType type, int child_id);
    virtual ~Receiver();
  };

  class Observer {
   public:
    virtual ~Observer() {}
    virtual void OnRequestStarted(ResourceDispatcherHost* resource_dispatcher,
                                  net::URLRequest* request) = 0;
    virtual void OnResponseCompleted(
        ResourceDispatcherHost* resource_dispatcher,
        net::URLRequest* request) = 0;
    virtual void OnReceivedRedirect(ResourceDispatcherHost* resource_dispatcher,
                                    net::URLRequest* request,
                                    const GURL& new_url) = 0;
  };

  ResourceDispatcherHost();
  ~ResourceDispatcherHost();

  void Initialize();

  // Puts the resource dispatcher host in an inactive state (unable to begin
  // new requests).  Cancels all pending requests.
  void Shutdown();

  // Returns true if the message was a resource message that was processed.
  // If it was, message_was_ok will be false iff the message was corrupt.
  bool OnMessageReceived(const IPC::Message& message,
                         Receiver* receiver,
                         bool* message_was_ok);

  // Initiates a download from the browser process (as opposed to a resource
  // request from the renderer or another child process).
  void BeginDownload(const GURL& url,
                     const GURL& referrer,
                     const DownloadSaveInfo& save_info,
                     bool prompt_for_save_location,
                     int process_unique_id,
                     int route_id,
                     URLRequestContext* request_context);

  // Initiates a save file from the browser process (as opposed to a resource
  // request from the renderer or another child process).
  void BeginSaveFile(const GURL& url,
                     const GURL& referrer,
                     int process_unique_id,
                     int route_id,
                     URLRequestContext* request_context);

  // Cancels the given request if it still exists. We ignore cancels from the
  // renderer in the event of a download.
  void CancelRequest(int process_unique_id,
                     int request_id,
                     bool from_renderer);

  // Follows a deferred redirect for the given request.
  // new_first_party_for_cookies, if non-empty, is the new cookie policy URL
  // for the redirected URL.  If the cookie policy URL needs changing, pass
  // true as has_new_first_party_for_cookies and the new cookie policy URL as
  // new_first_party_for_cookies.  Otherwise, pass false as
  // has_new_first_party_for_cookies, and new_first_party_for_cookies will not
  // be used.
  void FollowDeferredRedirect(int process_unique_id,
                              int request_id,
                              bool has_new_first_party_for_cookies,
                              const GURL& new_first_party_for_cookies);

  // Starts a request that was deferred during ResourceHandler::OnWillStart().
  void StartDeferredRequest(int process_unique_id, int request_id);

  // Returns true if it's ok to send the data. If there are already too many
  // data messages pending, it pauses the request and returns false. In this
  // case the caller should not send the data.
  bool WillSendData(int process_unique_id, int request_id);

  // Pauses or resumes network activity for a particular request.
  void PauseRequest(int process_unique_id, int request_id, bool pause);

  // Returns the number of pending requests. This is designed for the unittests
  int pending_requests() const {
    return static_cast<int>(pending_requests_.size());
  }

  // Intended for unit-tests only. Returns the memory cost of all the
  // outstanding requests (pending and blocked) for |process_unique_id|.
  int GetOutstandingRequestsMemoryCost(int process_unique_id) const;

  // Intended for unit-tests only. Overrides the outstanding requests bound.
  void set_max_outstanding_requests_cost_per_process(int limit) {
    max_outstanding_requests_cost_per_process_ = limit;
  }

  // The average private bytes increase of the browser for each new pending
  // request. Experimentally obtained.
  static const int kAvgBytesPerOutstandingRequest = 4400;

  DownloadFileManager* download_file_manager() const {
    return download_file_manager_;
  }

  DownloadRequestLimiter* download_request_limiter() const {
    return download_request_limiter_.get();
  }

  SaveFileManager* save_file_manager() const {
    return save_file_manager_;
  }

  SafeBrowsingService* safe_browsing_service() const {
    return safe_browsing_;
  }

  WebKitThread* webkit_thread() const {
    return webkit_thread_.get();
  }

  // Called when the onunload handler for a cross-site request has finished.
  void OnClosePageACK(const ViewMsg_ClosePage_Params& params);

  // Force cancels any pending requests for the given process.
  void CancelRequestsForProcess(int process_unique_id);

  // Force cancels any pending requests for the given route id.  This method
  // acts like CancelRequestsForProcess when route_id is -1.
  void CancelRequestsForRoute(int process_unique_id, int route_id);

  // net::URLRequest::Delegate
  virtual void OnReceivedRedirect(net::URLRequest* request,
                                  const GURL& new_url,
                                  bool* defer_redirect);
  virtual void OnAuthRequired(net::URLRequest* request,
                              net::AuthChallengeInfo* auth_info);
  virtual void OnCertificateRequested(
      net::URLRequest* request,
      net::SSLCertRequestInfo* cert_request_info);
  virtual void OnSSLCertificateError(net::URLRequest* request,
                                     int cert_error,
                                     net::X509Certificate* cert);
  virtual void OnSetCookie(net::URLRequest* request,
                           const std::string& cookie_line,
                           const net::CookieOptions& options,
                           bool blocked_by_policy);
  virtual void OnResponseStarted(net::URLRequest* request);
  virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
  void OnResponseCompleted(net::URLRequest* request);

  // Helper functions to get our extra data out of a request. The given request
  // must have been one we created so that it has the proper extra data pointer.
  static ResourceDispatcherHostRequestInfo* InfoForRequest(
      net::URLRequest* request);
  static const ResourceDispatcherHostRequestInfo* InfoForRequest(
      const net::URLRequest* request);

  // Extracts the render view/process host's identifiers from the given request
  // and places them in the given out params (both required). If there are no
  // such IDs associated with the request (such as non-page-related requests),
  // this function will return false and both out params will be -1.
  static bool RenderViewForRequest(const net::URLRequest* request,
                                   int* render_process_host_id,
                                   int* render_view_host_id);

  // Adds an observer.  The observer will be called on the IO thread.  To
  // observe resource events on the UI thread, subscribe to the
  // NOTIFY_RESOURCE_* notifications of the notification service.
  void AddObserver(Observer* obs);

  // Removes an observer.
  void RemoveObserver(Observer* obs);

  // Retrieves a net::URLRequest.  Must be called from the IO thread.
  net::URLRequest* GetURLRequest(const GlobalRequestID& request_id) const;

  // Notifies our observers that a request has been cancelled.
  void NotifyResponseCompleted(net::URLRequest* request, int process_unique_id);

  void RemovePendingRequest(int process_unique_id, int request_id);

  // Causes all new requests for the route identified by
  // |process_unique_id| and |route_id| to be blocked (not being
  // started) until ResumeBlockedRequestsForRoute or
  // CancelBlockedRequestsForRoute is called.
  void BlockRequestsForRoute(int process_unique_id, int route_id);

  // Resumes any blocked request for the specified route id.
  void ResumeBlockedRequestsForRoute(int process_unique_id, int route_id);

  // Cancels any blocked request for the specified route id.
  void CancelBlockedRequestsForRoute(int process_unique_id, int route_id);

  // Decrements the pending_data_count for the request and resumes
  // the request if it was paused due to too many pending data
  // messages sent.
  void DataReceivedACK(int process_unique_id, int request_id);

  // Maintains a collection of temp files created in support of
  // the download_to_file capability. Used to grant access to the
  // child process and to defer deletion of the file until it's
  // no longer needed.
  void RegisterDownloadedTempFile(
      int receiver_id, int request_id,
      webkit_blob::DeletableFileReference* reference);
  void UnregisterDownloadedTempFile(int receiver_id, int request_id);

  // Needed for the sync IPC message dispatcher macros.
  bool Send(IPC::Message* message);

  // Controls if we launch or squash prefetch requests as they arrive
  // from renderers.
  static bool is_prefetch_enabled();
  static void set_is_prefetch_enabled(bool value);

 private:
  FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
                           TestBlockedRequestsProcessDies);
  FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
                           IncrementOutstandingRequestsMemoryCost);
  FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
                           CalculateApproximateMemoryCost);
  FRIEND_TEST_ALL_PREFIXES(ApplyExtensionLocalizationFilterTest, WrongScheme);
  FRIEND_TEST_ALL_PREFIXES(ApplyExtensionLocalizationFilterTest, GoodScheme);
  FRIEND_TEST_ALL_PREFIXES(ApplyExtensionLocalizationFilterTest,
                           GoodSchemeWrongResourceType);

  class ShutdownTask;

  friend class ShutdownTask;

  // Associates the given info with the given request. The info will then be
  // owned by the request.
  void SetRequestInfo(net::URLRequest* request,
                      ResourceDispatcherHostRequestInfo* info);

  // A shutdown helper that runs on the IO thread.
  void OnShutdown();

  // Returns true if the request is paused.
  bool PauseRequestIfNeeded(ResourceDispatcherHostRequestInfo* info);

  // Resumes the given request by calling OnResponseStarted or OnReadCompleted.
  void ResumeRequest(const GlobalRequestID& request_id);

  // Internal function to start reading for the first time.
  void StartReading(net::URLRequest* request);

  // Reads data from the response using our internal buffer as async IO.
  // Returns true if data is available immediately, false otherwise.  If the
  // return value is false, we will receive a OnReadComplete() callback later.
  bool Read(net::URLRequest* request, int* bytes_read);

  // Internal function to finish an async IO which has completed.  Returns
  // true if there is more data to read (e.g. we haven't read EOF yet and
  // no errors have occurred).
  bool CompleteRead(net::URLRequest*, int* bytes_read);

  // Internal function to finish handling the ResponseStarted message.  Returns
  // true on success.
  bool CompleteResponseStarted(net::URLRequest* request);

  // Helper function for regular and download requests.
  void BeginRequestInternal(net::URLRequest* request);

  // Helper function that cancels |request|.
  void CancelRequestInternal(net::URLRequest* request, bool from_renderer);

  // Helper function that inserts |request| into the resource queue.
  void InsertIntoResourceQueue(
      net::URLRequest* request,
      const ResourceDispatcherHostRequestInfo& request_info);

  // Updates the "cost" of outstanding requests for |process_unique_id|.
  // The "cost" approximates how many bytes are consumed by all the in-memory
  // data structures supporting this request (net::URLRequest object,
  // HttpNetworkTransaction, etc...).
  // The value of |cost| is added to the running total, and the resulting
  // sum is returned.
  int IncrementOutstandingRequestsMemoryCost(int cost,
                                             int process_unique_id);

  // Estimate how much heap space |request| will consume to run.
  static int CalculateApproximateMemoryCost(net::URLRequest* request);

  // The list of all requests that we have pending. This list is not really
  // optimized, and assumes that we have relatively few requests pending at once
  // since some operations require brute-force searching of the list.
  //
  // It may be enhanced in the future to provide some kind of prioritization
  // mechanism. We should also consider a hashtable or binary tree if it turns
  // out we have a lot of things here.
  typedef std::map<GlobalRequestID, net::URLRequest*> PendingRequestList;

  // Deletes the pending request identified by the iterator passed in.
  // This function will invalidate the iterator passed in. Callers should
  // not rely on this iterator being valid on return.
  void RemovePendingRequest(const PendingRequestList::iterator& iter);

  // Notify our observers that we started receiving a response for a request.
  void NotifyResponseStarted(net::URLRequest* request, int process_unique_id);

  // Notify our observers that a request has been redirected.
  void NotifyReceivedRedirect(net::URLRequest* request,
                              int process_unique_id,
                              const GURL& new_url);

  // Tries to handle the url with an external protocol. If the request is
  // handled, the function returns true. False otherwise.
  bool HandleExternalProtocol(int request_id,
                              int process_unique_id,
                              int route_id,
                              const GURL& url,
                              ResourceType::Type resource_type,
                              ResourceHandler* handler);

  // Checks all pending requests and updates the load states and upload
  // progress if necessary.
  void UpdateLoadStates();

  // Checks the upload state and sends an update if one is necessary.
  bool MaybeUpdateUploadProgress(ResourceDispatcherHostRequestInfo *info,
                                 net::URLRequest *request);

  // Resumes or cancels (if |cancel_requests| is true) any blocked requests.
  void ProcessBlockedRequestsForRoute(int process_unique_id,
                                      int route_id,
                                      bool cancel_requests);

  void OnRequestResource(const IPC::Message& msg,
                         int request_id,
                         const ViewHostMsg_Resource_Request& request_data);
  void OnSyncLoad(int request_id,
                  const ViewHostMsg_Resource_Request& request_data,
                  IPC::Message* sync_result);
  void BeginRequest(int request_id,
                    const ViewHostMsg_Resource_Request& request_data,
                    IPC::Message* sync_result,  // only valid for sync
                    int route_id);  // only valid for async
  void OnDataReceivedACK(int request_id);
  void OnDataDownloadedACK(int request_id);
  void OnUploadProgressACK(int request_id);
  void OnCancelRequest(int request_id);
  void OnFollowRedirect(int request_id,
                        bool has_new_first_party_for_cookies,
                        const GURL& new_first_party_for_cookies);
  void OnReleaseDownloadedFile(int request_id);

  ResourceHandler* CreateSafeBrowsingResourceHandler(
      ResourceHandler* handler, int child_id, int route_id,
      ResourceType::Type resource_type);

  // Creates ResourceDispatcherHostRequestInfo for a browser-initiated request
  // (a download or a page save). |download| should be true if the request
  // is a file download.
  ResourceDispatcherHostRequestInfo* CreateRequestInfoForBrowserRequest(
      ResourceHandler* handler, int child_id, int route_id, bool download);

  // Returns true if |request| is in |pending_requests_|.
  bool IsValidRequest(net::URLRequest* request);

  // Returns true if the message passed in is a resource related message.
  static bool IsResourceDispatcherHostMessage(const IPC::Message&);

  // Sets replace_extension_localization_templates on all text/css requests that
  // have "chrome-extension://" scheme.
  static void ApplyExtensionLocalizationFilter(
      const GURL& url,
      const ResourceType::Type& resource_type,
      ResourceDispatcherHostRequestInfo* request_info);

  // Determine request priority based on how critical this resource typically
  // is to user-perceived page load performance.
  static net::RequestPriority DetermineRequestPriority(ResourceType::Type type);

  PendingRequestList pending_requests_;

  // Collection of temp files downloaded for child processes via
  // the download_to_file mechanism. We avoid deleting them until
  // the client no longer needs them.
  typedef std::map<int, scoped_refptr<webkit_blob::DeletableFileReference> >
      DeletableFilesMap;  // key is request id
  typedef std::map<int, DeletableFilesMap>
      RegisteredTempFiles;  // key is child process id
  RegisteredTempFiles registered_temp_files_;

  // A timer that periodically calls UpdateLoadStates while pending_requests_
  // is not empty.
  base::RepeatingTimer<ResourceDispatcherHost> update_load_states_timer_;

  // Handles the resource requests from the moment we want to start them.
  ResourceQueue resource_queue_;

  // We own the download file writing thread and manager
  scoped_refptr<DownloadFileManager> download_file_manager_;

  // Determines whether a download is allowed.
  scoped_refptr<DownloadRequestLimiter> download_request_limiter_;

  // We own the save file manager.
  scoped_refptr<SaveFileManager> save_file_manager_;

  scoped_refptr<UserScriptListener> user_script_listener_;

  scoped_refptr<SafeBrowsingService> safe_browsing_;

  scoped_ptr<SocketStreamDispatcherHost> socket_stream_dispatcher_host_;

  // We own the WebKit thread and see to its destruction.
  scoped_ptr<WebKitThread> webkit_thread_;

  // Request ID for browser initiated requests. request_ids generated by
  // child processes are counted up from 0, while browser created requests
  // start at -2 and go down from there. (We need to start at -2 because -1 is
  // used as a special value all over the resource_dispatcher_host for
  // uninitialized variables.) This way, we no longer have the unlikely (but
  // observed in the real world!) event where we have two requests with the same
  // request_id_.
  int request_id_;

  // List of objects observing resource dispatching.
  ObserverList<Observer> observer_list_;

  // For running tasks.
  ScopedRunnableMethodFactory<ResourceDispatcherHost> method_runner_;

  // True if the resource dispatcher host has been shut down.
  bool is_shutdown_;

  typedef std::vector<net::URLRequest*> BlockedRequestsList;
  typedef std::pair<int, int> ProcessRouteIDs;
  typedef std::map<ProcessRouteIDs, BlockedRequestsList*> BlockedRequestMap;
  BlockedRequestMap blocked_requests_map_;

  // Maps the process_unique_ids to the approximate number of bytes
  // being used to service its resource requests. No entry implies 0 cost.
  typedef std::map<int, int> OutstandingRequestsMemoryCostMap;
  OutstandingRequestsMemoryCostMap outstanding_requests_memory_cost_map_;

  // |max_outstanding_requests_cost_per_process_| is the upper bound on how
  // many outstanding requests can be issued per child process host.
  // The constraint is expressed in terms of bytes (where the cost of
  // individual requests is given by CalculateApproximateMemoryCost).
  // The total number of outstanding requests is roughly:
  //   (max_outstanding_requests_cost_per_process_ /
  //       kAvgBytesPerOutstandingRequest)
  int max_outstanding_requests_cost_per_process_;

  // Used during IPC message dispatching so that the handlers can get a pointer
  // to the source of the message.
  Receiver* receiver_;

  static bool is_prefetch_enabled_;

  DISALLOW_COPY_AND_ASSIGN(ResourceDispatcherHost);
};

#endif  // CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_H_