1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_ 6 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_ 7 8 #include <map> 9 #include <string> 10 #include <vector> 11 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" 20 21 class HostContentSettingsMap; 22 class DownloadRequestInfoBarDelegate; 23 24 namespace content { 25 class NavigationController; 26 class WebContents; 27 } 28 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. 36 // 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> { 53 public: 54 // Download status for a particular page. See class description for details. 55 enum DownloadStatus { 56 ALLOW_ONE_DOWNLOAD, 57 PROMPT_BEFORE_DOWNLOAD, 58 ALLOW_ALL_DOWNLOADS, 59 DOWNLOADS_NOT_ALLOWED 60 }; 61 62 // Max number of downloads before a "Prompt Before Download" Dialog is shown. 63 static const size_t kMaxDownloadsAtOnce = 50; 64 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; 68 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 { 75 public: 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(); 86 87 // Status of the download. 88 void set_download_status(DownloadRequestLimiter::DownloadStatus status) { 89 status_ = status; 90 } 91 DownloadRequestLimiter::DownloadStatus download_status() const { 92 return status_; 93 } 94 95 // Number of "ALLOWED" downloads. 96 void increment_download_count() { 97 download_count_++; 98 } 99 size_t download_count() const { 100 return download_count_; 101 } 102 103 // Promote protected accessor to public. 104 content::WebContents* web_contents() { 105 return content::WebContentsObserver::web_contents(); 106 } 107 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; 116 117 // Asks the user if they really want to allow the download. 118 // See description above CanDownloadOnIOThread for details on lifetime of 119 // callback. 120 void PromptUserForDownload( 121 const DownloadRequestLimiter::Callback& callback); 122 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(); 128 129 protected: 130 // Used for testing. 131 TabDownloadState(); 132 133 private: 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(); } 138 139 // content::NotificationObserver method. 140 virtual void Observe(int type, 141 const content::NotificationSource& source, 142 const content::NotificationDetails& details) OVERRIDE; 143 144 // Remember to either block or allow automatic downloads from this origin. 145 void SetContentSetting(ContentSetting setting); 146 147 // Notifies the callbacks as to whether the download is allowed or not. 148 // Updates status_ appropriately. 149 void NotifyCallbacks(bool allow); 150 151 content::WebContents* web_contents_; 152 153 DownloadRequestLimiter* host_; 154 155 // Host of the first page the download started on. This may be empty. 156 std::string initial_page_host_; 157 158 DownloadRequestLimiter::DownloadStatus status_; 159 160 size_t download_count_; 161 162 // Callbacks we need to notify. This is only non-empty if we're showing a 163 // dialog. 164 // See description above CanDownloadOnIOThread for details on lifetime of 165 // callbacks. 166 std::vector<DownloadRequestLimiter::Callback> callbacks_; 167 168 // Used to remove observers installed on NavigationController. 169 content::NotificationRegistrar registrar_; 170 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 174 // becomes moot. 175 base::WeakPtrFactory<DownloadRequestLimiter::TabDownloadState> factory_; 176 177 DISALLOW_COPY_AND_ASSIGN(TabDownloadState); 178 }; 179 180 static void SetContentSettingsForTesting(HostContentSettingsMap* settings); 181 182 DownloadRequestLimiter(); 183 184 // Returns the download status for a page. This does not change the state in 185 // anyway. 186 DownloadStatus GetDownloadStatus(content::WebContents* tab); 187 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, 191 int render_view_id, 192 int request_id, 193 const std::string& request_method, 194 const Callback& callback); 195 196 private: 197 FRIEND_TEST_ALL_PREFIXES(DownloadTest, DownloadResourceThrottleCancels); 198 friend class base::RefCountedThreadSafe<DownloadRequestLimiter>; 199 friend class DownloadRequestLimiterTest; 200 friend class TabDownloadState; 201 202 ~DownloadRequestLimiter(); 203 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 207 // controllers. 208 // 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, 214 bool create); 215 216 // CanDownloadOnIOThread invokes this on the UI thread. This determines the 217 // tab and invokes CanDownloadImpl. 218 void CanDownload(int render_process_host_id, 219 int render_view_id, 220 int request_id, 221 const std::string& request_method, 222 const Callback& callback); 223 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, 227 int request_id, 228 const std::string& request_method, 229 const Callback& callback); 230 231 // Invoked when decision to download has been made. 232 void OnCanDownloadDecided(int render_process_host_id, 233 int render_view_id, 234 int request_id, 235 const std::string& request_method, 236 const Callback& orig_callback, 237 bool allow); 238 239 // Invoked on the UI thread. Schedules a call to NotifyCallback on the io 240 // thread. 241 void ScheduleNotification(const Callback& callback, bool allow); 242 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); 247 248 static HostContentSettingsMap* content_settings_; 249 static HostContentSettingsMap* GetContentSettings( 250 content::WebContents* contents); 251 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; 257 StateMap state_map_; 258 259 // Weak ptr factory used when |CanDownload| asks the delegate asynchronously 260 // about the download. 261 base::WeakPtrFactory<DownloadRequestLimiter> factory_; 262 263 DISALLOW_COPY_AND_ASSIGN(DownloadRequestLimiter); 264 }; 265 266 #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_ 267