1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_
6 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_
12 #include "base/callback.h"
13 #include "base/gtest_prod_util.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/weak_ptr.h"
16 #include "chrome/common/content_settings.h"
17 #include "content/public/browser/notification_observer.h"
18 #include "content/public/browser/notification_registrar.h"
19 #include "content/public/browser/web_contents_observer.h"
21 class HostContentSettingsMap
;
22 class DownloadRequestInfoBarDelegate
;
25 class NavigationController
;
29 // DownloadRequestLimiter is responsible for determining whether a download
30 // should be allowed or not. It is designed to keep pages from downloading
31 // multiple files without user interaction. DownloadRequestLimiter is invoked
32 // from ResourceDispatcherHost any time a download begins
33 // (CanDownloadOnIOThread). The request is processed on the UI thread, and the
34 // request is notified (back on the IO thread) as to whether the download should
35 // be allowed or denied.
37 // Invoking CanDownloadOnIOThread notifies the callback and may update the
38 // download status. The following details the various states:
39 // . Each NavigationController initially starts out allowing a download
40 // (ALLOW_ONE_DOWNLOAD).
41 // . The first time CanDownloadOnIOThread is invoked the download is allowed and
42 // the state changes to PROMPT_BEFORE_DOWNLOAD.
43 // . If the state is PROMPT_BEFORE_DOWNLOAD and the user clicks the mouse,
44 // presses enter, the space bar or navigates to another page the state is
45 // reset to ALLOW_ONE_DOWNLOAD.
46 // . If a download is attempted and the state is PROMPT_BEFORE_DOWNLOAD the user
47 // is prompted as to whether the download is allowed or disallowed. The users
48 // choice stays until the user navigates to a different host. For example, if
49 // the user allowed the download, multiple downloads are allowed without any
50 // user intervention until the user navigates to a different host.
51 class DownloadRequestLimiter
52 : public base::RefCountedThreadSafe
<DownloadRequestLimiter
> {
54 // Download status for a particular page. See class description for details.
57 PROMPT_BEFORE_DOWNLOAD
,
62 // Max number of downloads before a "Prompt Before Download" Dialog is shown.
63 static const size_t kMaxDownloadsAtOnce
= 50;
65 // The callback from CanDownloadOnIOThread. This is invoked on the io thread.
66 // The boolean parameter indicates whether or not the download is allowed.
67 typedef base::Callback
<void(bool /*allow*/)> Callback
;
69 // TabDownloadState maintains the download state for a particular tab.
70 // TabDownloadState prompts the user with an infobar as necessary.
71 // TabDownloadState deletes itself (by invoking
72 // DownloadRequestLimiter::Remove) as necessary.
73 class TabDownloadState
: public content::NotificationObserver
,
74 public content::WebContentsObserver
{
76 // Creates a new TabDownloadState. |controller| is the controller the
77 // TabDownloadState tracks the state of and is the host for any dialogs that
78 // are displayed. |originating_controller| is used to determine the host of
79 // the initial download. If |originating_controller| is null, |controller|
80 // is used. |originating_controller| is typically null, but differs from
81 // |controller| in the case of a constrained popup requesting the download.
82 TabDownloadState(DownloadRequestLimiter
* host
,
83 content::WebContents
* web_contents
,
84 content::WebContents
* originating_web_contents
);
85 virtual ~TabDownloadState();
87 // Status of the download.
88 void set_download_status(DownloadRequestLimiter::DownloadStatus status
) {
91 DownloadRequestLimiter::DownloadStatus
download_status() const {
95 // Number of "ALLOWED" downloads.
96 void increment_download_count() {
99 size_t download_count() const {
100 return download_count_
;
103 // Promote protected accessor to public.
104 content::WebContents
* web_contents() {
105 return content::WebContentsObserver::web_contents();
108 // content::WebContentsObserver overrides.
109 virtual void AboutToNavigateRenderView(
110 content::RenderViewHost
* render_view_host
) OVERRIDE
;
111 // Invoked when a user gesture occurs (mouse click, enter or space). This
112 // may result in invoking Remove on DownloadRequestLimiter.
113 virtual void DidGetUserGesture() OVERRIDE
;
114 virtual void WebContentsDestroyed(
115 content::WebContents
* web_contents
) OVERRIDE
;
117 // Asks the user if they really want to allow the download.
118 // See description above CanDownloadOnIOThread for details on lifetime of
120 void PromptUserForDownload(
121 const DownloadRequestLimiter::Callback
& callback
);
123 // Invoked from DownloadRequestDialogDelegate. Notifies the delegates and
124 // changes the status appropriately. Virtual for testing.
125 virtual void Cancel();
126 virtual void CancelOnce();
127 virtual void Accept();
134 // Are we showing a prompt to the user? Determined by whether
135 // we have an outstanding weak pointer--weak pointers are only
136 // given to the info bar delegate.
137 bool is_showing_prompt() const { return factory_
.HasWeakPtrs(); }
139 // content::NotificationObserver method.
140 virtual void Observe(int type
,
141 const content::NotificationSource
& source
,
142 const content::NotificationDetails
& details
) OVERRIDE
;
144 // Remember to either block or allow automatic downloads from this origin.
145 void SetContentSetting(ContentSetting setting
);
147 // Notifies the callbacks as to whether the download is allowed or not.
148 // Updates status_ appropriately.
149 void NotifyCallbacks(bool allow
);
151 content::WebContents
* web_contents_
;
153 DownloadRequestLimiter
* host_
;
155 // Host of the first page the download started on. This may be empty.
156 std::string initial_page_host_
;
158 DownloadRequestLimiter::DownloadStatus status_
;
160 size_t download_count_
;
162 // Callbacks we need to notify. This is only non-empty if we're showing a
164 // See description above CanDownloadOnIOThread for details on lifetime of
166 std::vector
<DownloadRequestLimiter::Callback
> callbacks_
;
168 // Used to remove observers installed on NavigationController.
169 content::NotificationRegistrar registrar_
;
171 // Weak pointer factory for generating a weak pointer to pass to the
172 // infobar. User responses to the throttling prompt will be returned
173 // through this channel, and it can be revoked if the user prompt result
175 base::WeakPtrFactory
<DownloadRequestLimiter::TabDownloadState
> factory_
;
177 DISALLOW_COPY_AND_ASSIGN(TabDownloadState
);
180 static void SetContentSettingsForTesting(HostContentSettingsMap
* settings
);
182 DownloadRequestLimiter();
184 // Returns the download status for a page. This does not change the state in
186 DownloadStatus
GetDownloadStatus(content::WebContents
* tab
);
188 // Updates the state of the page as necessary and notifies the callback.
189 // WARNING: both this call and the callback are invoked on the io thread.
190 void CanDownloadOnIOThread(int render_process_host_id
,
193 const std::string
& request_method
,
194 const Callback
& callback
);
197 FRIEND_TEST_ALL_PREFIXES(DownloadTest
, DownloadResourceThrottleCancels
);
198 friend class base::RefCountedThreadSafe
<DownloadRequestLimiter
>;
199 friend class DownloadRequestLimiterTest
;
200 friend class TabDownloadState
;
202 ~DownloadRequestLimiter();
204 // Gets the download state for the specified controller. If the
205 // TabDownloadState does not exist and |create| is true, one is created.
206 // See TabDownloadState's constructor description for details on the two
209 // The returned TabDownloadState is owned by the DownloadRequestLimiter and
210 // deleted when no longer needed (the Remove method is invoked).
211 TabDownloadState
* GetDownloadState(
212 content::WebContents
* web_contents
,
213 content::WebContents
* originating_web_contents
,
216 // CanDownloadOnIOThread invokes this on the UI thread. This determines the
217 // tab and invokes CanDownloadImpl.
218 void CanDownload(int render_process_host_id
,
221 const std::string
& request_method
,
222 const Callback
& callback
);
224 // Does the work of updating the download status on the UI thread and
225 // potentially prompting the user.
226 void CanDownloadImpl(content::WebContents
* originating_contents
,
228 const std::string
& request_method
,
229 const Callback
& callback
);
231 // Invoked when decision to download has been made.
232 void OnCanDownloadDecided(int render_process_host_id
,
235 const std::string
& request_method
,
236 const Callback
& orig_callback
,
239 // Invoked on the UI thread. Schedules a call to NotifyCallback on the io
241 void ScheduleNotification(const Callback
& callback
, bool allow
);
243 // Removes the specified TabDownloadState from the internal map and deletes
244 // it. This has the effect of resetting the status for the tab to
245 // ALLOW_ONE_DOWNLOAD.
246 void Remove(TabDownloadState
* state
, content::WebContents
* contents
);
248 static HostContentSettingsMap
* content_settings_
;
249 static HostContentSettingsMap
* GetContentSettings(
250 content::WebContents
* contents
);
252 // Maps from tab to download state. The download state for a tab only exists
253 // if the state is other than ALLOW_ONE_DOWNLOAD. Similarly once the state
254 // transitions from anything but ALLOW_ONE_DOWNLOAD back to ALLOW_ONE_DOWNLOAD
255 // the TabDownloadState is removed and deleted (by way of Remove).
256 typedef std::map
<content::WebContents
*, TabDownloadState
*> StateMap
;
259 // Weak ptr factory used when |CanDownload| asks the delegate asynchronously
260 // about the download.
261 base::WeakPtrFactory
<DownloadRequestLimiter
> factory_
;
263 DISALLOW_COPY_AND_ASSIGN(DownloadRequestLimiter
);
266 #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_