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 "components/content_settings/core/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 // TODO(gbillock): just make this class implement PermissionBubbleRequest. 74 class TabDownloadState : public content::NotificationObserver, 75 public content::WebContentsObserver { 76 public: 77 // Creates a new TabDownloadState. |controller| is the controller the 78 // TabDownloadState tracks the state of and is the host for any dialogs that 79 // are displayed. |originating_controller| is used to determine the host of 80 // the initial download. If |originating_controller| is null, |controller| 81 // is used. |originating_controller| is typically null, but differs from 82 // |controller| in the case of a constrained popup requesting the download. 83 TabDownloadState(DownloadRequestLimiter* host, 84 content::WebContents* web_contents, 85 content::WebContents* originating_web_contents); 86 virtual ~TabDownloadState(); 87 88 // Status of the download. set_download_status(DownloadRequestLimiter::DownloadStatus status)89 void set_download_status(DownloadRequestLimiter::DownloadStatus status) { 90 status_ = status; 91 } download_status()92 DownloadRequestLimiter::DownloadStatus download_status() const { 93 return status_; 94 } 95 96 // Number of "ALLOWED" downloads. increment_download_count()97 void increment_download_count() { 98 download_count_++; 99 } download_count()100 size_t download_count() const { 101 return download_count_; 102 } 103 104 // content::WebContentsObserver overrides. 105 virtual void AboutToNavigateRenderView( 106 content::RenderViewHost* render_view_host) OVERRIDE; 107 // Invoked when a user gesture occurs (mouse click, enter or space). This 108 // may result in invoking Remove on DownloadRequestLimiter. 109 virtual void DidGetUserGesture() OVERRIDE; 110 virtual void WebContentsDestroyed() OVERRIDE; 111 112 // Asks the user if they really want to allow the download. 113 // See description above CanDownloadOnIOThread for details on lifetime of 114 // callback. 115 void PromptUserForDownload( 116 const DownloadRequestLimiter::Callback& callback); 117 118 // Invoked from DownloadRequestDialogDelegate. Notifies the delegates and 119 // changes the status appropriately. Virtual for testing. 120 virtual void Cancel(); 121 virtual void CancelOnce(); 122 virtual void Accept(); 123 124 protected: 125 // Used for testing. 126 TabDownloadState(); 127 128 private: 129 // Are we showing a prompt to the user? Determined by whether 130 // we have an outstanding weak pointer--weak pointers are only 131 // given to the info bar delegate or permission bubble request. 132 bool is_showing_prompt() const; 133 134 // content::NotificationObserver method. 135 virtual void Observe(int type, 136 const content::NotificationSource& source, 137 const content::NotificationDetails& details) OVERRIDE; 138 139 // Remember to either block or allow automatic downloads from this origin. 140 void SetContentSetting(ContentSetting setting); 141 142 // Notifies the callbacks as to whether the download is allowed or not. 143 // Updates status_ appropriately. 144 void NotifyCallbacks(bool allow); 145 146 content::WebContents* web_contents_; 147 148 DownloadRequestLimiter* host_; 149 150 // Host of the first page the download started on. This may be empty. 151 std::string initial_page_host_; 152 153 DownloadRequestLimiter::DownloadStatus status_; 154 155 size_t download_count_; 156 157 // Callbacks we need to notify. This is only non-empty if we're showing a 158 // dialog. 159 // See description above CanDownloadOnIOThread for details on lifetime of 160 // callbacks. 161 std::vector<DownloadRequestLimiter::Callback> callbacks_; 162 163 // Used to remove observers installed on NavigationController. 164 content::NotificationRegistrar registrar_; 165 166 // Weak pointer factory for generating a weak pointer to pass to the 167 // infobar. User responses to the throttling prompt will be returned 168 // through this channel, and it can be revoked if the user prompt result 169 // becomes moot. 170 base::WeakPtrFactory<DownloadRequestLimiter::TabDownloadState> factory_; 171 172 DISALLOW_COPY_AND_ASSIGN(TabDownloadState); 173 }; 174 175 static void SetContentSettingsForTesting(HostContentSettingsMap* settings); 176 177 DownloadRequestLimiter(); 178 179 // Returns the download status for a page. This does not change the state in 180 // anyway. 181 DownloadStatus GetDownloadStatus(content::WebContents* tab); 182 183 // Updates the state of the page as necessary and notifies the callback. 184 // WARNING: both this call and the callback are invoked on the io thread. 185 void CanDownloadOnIOThread(int render_process_host_id, 186 int render_view_id, 187 const GURL& url, 188 const std::string& request_method, 189 const Callback& callback); 190 191 private: 192 FRIEND_TEST_ALL_PREFIXES(DownloadTest, DownloadResourceThrottleCancels); 193 friend class base::RefCountedThreadSafe<DownloadRequestLimiter>; 194 friend class DownloadRequestLimiterTest; 195 friend class TabDownloadState; 196 197 ~DownloadRequestLimiter(); 198 199 // Gets the download state for the specified controller. If the 200 // TabDownloadState does not exist and |create| is true, one is created. 201 // See TabDownloadState's constructor description for details on the two 202 // controllers. 203 // 204 // The returned TabDownloadState is owned by the DownloadRequestLimiter and 205 // deleted when no longer needed (the Remove method is invoked). 206 TabDownloadState* GetDownloadState( 207 content::WebContents* web_contents, 208 content::WebContents* originating_web_contents, 209 bool create); 210 211 // CanDownloadOnIOThread invokes this on the UI thread. This determines the 212 // tab and invokes CanDownloadImpl. 213 void CanDownload(int render_process_host_id, 214 int render_view_id, 215 const GURL& url, 216 const std::string& request_method, 217 const Callback& callback); 218 219 // Does the work of updating the download status on the UI thread and 220 // potentially prompting the user. 221 void CanDownloadImpl(content::WebContents* originating_contents, 222 const std::string& request_method, 223 const Callback& callback); 224 225 // Invoked when decision to download has been made. 226 void OnCanDownloadDecided(int render_process_host_id, 227 int render_view_id, 228 const std::string& request_method, 229 const Callback& orig_callback, 230 bool allow); 231 232 // Invoked on the UI thread. Schedules a call to NotifyCallback on the io 233 // thread. 234 void ScheduleNotification(const Callback& callback, bool allow); 235 236 // Removes the specified TabDownloadState from the internal map and deletes 237 // it. This has the effect of resetting the status for the tab to 238 // ALLOW_ONE_DOWNLOAD. 239 void Remove(TabDownloadState* state, content::WebContents* contents); 240 241 static HostContentSettingsMap* content_settings_; 242 static HostContentSettingsMap* GetContentSettings( 243 content::WebContents* contents); 244 245 // Maps from tab to download state. The download state for a tab only exists 246 // if the state is other than ALLOW_ONE_DOWNLOAD. Similarly once the state 247 // transitions from anything but ALLOW_ONE_DOWNLOAD back to ALLOW_ONE_DOWNLOAD 248 // the TabDownloadState is removed and deleted (by way of Remove). 249 typedef std::map<content::WebContents*, TabDownloadState*> StateMap; 250 StateMap state_map_; 251 252 // Weak ptr factory used when |CanDownload| asks the delegate asynchronously 253 // about the download. 254 base::WeakPtrFactory<DownloadRequestLimiter> factory_; 255 256 DISALLOW_COPY_AND_ASSIGN(DownloadRequestLimiter); 257 }; 258 259 #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_ 260