OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/download/download_request_limiter.h" | 5 #include "chrome/browser/download/download_request_limiter.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "chrome/browser/chrome_notification_types.h" | 9 #include "chrome/browser/chrome_notification_types.h" |
10 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 10 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
11 #include "chrome/browser/content_settings/tab_specific_content_settings.h" | 11 #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
12 #include "chrome/browser/infobars/infobar_service.h" | 12 #include "chrome/browser/infobars/infobar_service.h" |
13 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
14 #include "chrome/browser/tab_contents/tab_util.h" | 14 #include "chrome/browser/tab_contents/tab_util.h" |
15 #include "chrome/common/features.h" | 15 #include "chrome/common/features.h" |
16 #include "components/content_settings/core/browser/host_content_settings_map.h" | 16 #include "components/content_settings/core/browser/host_content_settings_map.h" |
17 #include "content/public/browser/browser_context.h" | 17 #include "content/public/browser/browser_context.h" |
18 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
19 #include "content/public/browser/navigation_controller.h" | 19 #include "content/public/browser/navigation_controller.h" |
20 #include "content/public/browser/navigation_entry.h" | 20 #include "content/public/browser/navigation_entry.h" |
21 #include "content/public/browser/navigation_handle.h" | |
21 #include "content/public/browser/notification_source.h" | 22 #include "content/public/browser/notification_source.h" |
22 #include "content/public/browser/notification_types.h" | 23 #include "content/public/browser/notification_types.h" |
23 #include "content/public/browser/render_process_host.h" | 24 #include "content/public/browser/render_process_host.h" |
24 #include "content/public/browser/resource_dispatcher_host.h" | 25 #include "content/public/browser/resource_dispatcher_host.h" |
25 #include "content/public/browser/web_contents.h" | 26 #include "content/public/browser/web_contents.h" |
26 #include "content/public/browser/web_contents_delegate.h" | 27 #include "content/public/browser/web_contents_delegate.h" |
27 #include "url/gurl.h" | 28 #include "url/gurl.h" |
28 | 29 |
29 #if BUILDFLAG(ANDROID_JAVA_UI) | 30 #if BUILDFLAG(ANDROID_JAVA_UI) |
30 #include "chrome/browser/download/download_request_infobar_delegate_android.h" | 31 #include "chrome/browser/download/download_request_infobar_delegate_android.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
42 DownloadRequestLimiter::TabDownloadState::TabDownloadState( | 43 DownloadRequestLimiter::TabDownloadState::TabDownloadState( |
43 DownloadRequestLimiter* host, | 44 DownloadRequestLimiter* host, |
44 content::WebContents* contents, | 45 content::WebContents* contents, |
45 content::WebContents* originating_web_contents) | 46 content::WebContents* originating_web_contents) |
46 : content::WebContentsObserver(contents), | 47 : content::WebContentsObserver(contents), |
47 web_contents_(contents), | 48 web_contents_(contents), |
48 host_(host), | 49 host_(host), |
49 status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD), | 50 status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD), |
50 download_count_(0), | 51 download_count_(0), |
51 factory_(this) { | 52 factory_(this) { |
52 registrar_.Add( | |
53 this, content::NOTIFICATION_NAV_ENTRY_PENDING, | |
54 content::Source<NavigationController>(&contents->GetController())); | |
55 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, | 53 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, |
56 content::Source<content::WebContents>(contents)); | 54 content::Source<content::WebContents>(contents)); |
57 NavigationEntry* last_entry = originating_web_contents ? | 55 NavigationEntry* last_entry = |
58 originating_web_contents->GetController().GetLastCommittedEntry() : | 56 originating_web_contents |
59 contents->GetController().GetLastCommittedEntry(); | 57 ? originating_web_contents->GetController().GetLastCommittedEntry() |
58 : contents->GetController().GetLastCommittedEntry(); | |
60 if (last_entry) | 59 if (last_entry) |
61 initial_page_host_ = last_entry->GetURL().host(); | 60 initial_page_host_ = last_entry->GetURL().host(); |
62 } | 61 } |
63 | 62 |
64 DownloadRequestLimiter::TabDownloadState::~TabDownloadState() { | 63 DownloadRequestLimiter::TabDownloadState::~TabDownloadState() { |
65 // We should only be destroyed after the callbacks have been notified. | 64 // We should only be destroyed after the callbacks have been notified. |
66 DCHECK(callbacks_.empty()); | 65 DCHECK(callbacks_.empty()); |
67 | 66 |
68 // And we should have invalidated the back pointer. | 67 // And we should have invalidated the back pointer. |
69 DCHECK(!factory_.HasWeakPtrs()); | 68 DCHECK(!factory_.HasWeakPtrs()); |
70 } | 69 } |
71 | 70 |
72 void DownloadRequestLimiter::TabDownloadState::DidNavigateMainFrame( | 71 void DownloadRequestLimiter::TabDownloadState::DidStartNavigation( |
73 const content::LoadCommittedDetails& details, | 72 content::NavigationHandle* navigation_handle) { |
74 const content::FrameNavigateParams& params) { | 73 if (!navigation_handle->IsInMainFrame()) |
75 switch (status_) { | 74 return; |
76 case ALLOW_ONE_DOWNLOAD: | 75 |
77 case PROMPT_BEFORE_DOWNLOAD: | 76 // If the navigation is renderer-initiated, ensure that a prompting or |
78 // When the user reloads the page without responding to the infobar, they | 77 // blocking limiter state is not reset, so window.location.href or meta |
79 // are expecting DownloadRequestLimiter to behave as if they had just | 78 // refresh can't be abused to avoid the limiter. |
Charlie Reis
2016/05/13 00:36:12
Might mention where renderer-initiated navigations
dominickn
2016/05/17 01:31:48
Done.
| |
80 // initially navigated to this page. See http://crbug.com/171372 | 79 if (navigation_handle->IsRendererInitiated() && |
81 NotifyCallbacks(false); | 80 (status_ == PROMPT_BEFORE_DOWNLOAD || status_ == DOWNLOADS_NOT_ALLOWED)) { |
82 host_->Remove(this, web_contents()); | 81 return; |
83 // WARNING: We've been deleted. | 82 } |
84 break; | 83 |
85 case DOWNLOADS_NOT_ALLOWED: | 84 if (status_ == DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS || |
86 case ALLOW_ALL_DOWNLOADS: | 85 status_ == DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED) { |
87 // Don't drop this information. The user has explicitly said that they | 86 // User has either allowed all downloads or canceled all downloads. Only |
88 // do/don't want downloads from this host. If they accidentally Accepted | 87 // reset the download state if the user is navigating to a different host |
89 // or Canceled, they can adjust the limiter state by adjusting the | 88 // (or host is empty). |
90 // automatic downloads content settings. Alternatively, they can copy the | 89 if (!initial_page_host_.empty() && |
91 // URL into a new tab, which will make a new DownloadRequestLimiter. | 90 navigation_handle->GetURL().host() == initial_page_host_) { |
Charlie Reis
2016/05/13 00:36:12
Host comparisons always catch my eye, since there'
dominickn
2016/05/17 01:31:48
I think the fact that a prompt/block state is pers
asanka
2016/05/19 02:18:30
I believe this is safe. If the navigation was rend
| |
92 // See also the initial_page_host_ logic in Observe() for | 91 return; |
93 // NOTIFICATION_NAV_ENTRY_PENDING. | 92 } |
94 break; | 93 } |
95 default: | 94 |
96 NOTREACHED(); | 95 NotifyCallbacks(false); |
96 host_->Remove(this, web_contents()); | |
97 } | |
98 | |
99 void DownloadRequestLimiter::TabDownloadState::DidFinishNavigation( | |
100 content::NavigationHandle* navigation_handle) { | |
101 if (!navigation_handle->IsInMainFrame()) | |
102 return; | |
103 | |
104 // When the status is ALLOW_ALL_DOWNLOADS or DOWNLOADS_NOT_ALLOWED, don't drop | |
105 // this information. The user has explicitly said that they | |
106 // do/don't want downloads from this host. If they accidentally Accepted | |
107 // or Canceled, they can adjust the limiter state by adjusting the | |
108 // automatic downloads content settings. Alternatively, they can copy | |
109 // the URL into a new tab, which will make a new DownloadRequestLimiter. | |
110 // See also the initial_page_host_ logic in DidStartNavigation or Observe() | |
111 // for NOTIFICATION_NAV_ENTRY_PENDING. | |
112 if (status_ == ALLOW_ONE_DOWNLOAD || | |
113 (status_ == PROMPT_BEFORE_DOWNLOAD && | |
114 !navigation_handle->IsRendererInitiated())) { | |
115 // When the user reloads the page without responding to the infobar, | |
116 // they are expecting DownloadRequestLimiter to behave as if they had | |
117 // just initially navigated to this page. See http://crbug.com/171372. | |
118 // However, explicitly leave the limiter in place if the navigation was | |
119 // renderer-initiated and we are in a prompt state. | |
120 NotifyCallbacks(false); | |
121 host_->Remove(this, web_contents()); | |
122 // WARNING: We've been deleted. | |
97 } | 123 } |
98 } | 124 } |
99 | 125 |
100 void DownloadRequestLimiter::TabDownloadState::DidGetUserInteraction( | 126 void DownloadRequestLimiter::TabDownloadState::DidGetUserInteraction( |
101 const blink::WebInputEvent::Type type) { | 127 const blink::WebInputEvent::Type type) { |
102 if (is_showing_prompt() || type == blink::WebInputEvent::GestureScrollBegin) { | 128 if (is_showing_prompt() || type == blink::WebInputEvent::GestureScrollBegin) { |
103 // Don't change state if a prompt is showing or if the user has scrolled. | 129 // Don't change state if a prompt is showing or if the user has scrolled. |
104 return; | 130 return; |
105 } | 131 } |
106 | 132 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 if (is_showing_prompt()) | 164 if (is_showing_prompt()) |
139 return; | 165 return; |
140 | 166 |
141 #if BUILDFLAG(ANDROID_JAVA_UI) | 167 #if BUILDFLAG(ANDROID_JAVA_UI) |
142 DownloadRequestInfoBarDelegateAndroid::Create( | 168 DownloadRequestInfoBarDelegateAndroid::Create( |
143 InfoBarService::FromWebContents(web_contents_), factory_.GetWeakPtr()); | 169 InfoBarService::FromWebContents(web_contents_), factory_.GetWeakPtr()); |
144 #else | 170 #else |
145 PermissionBubbleManager* bubble_manager = | 171 PermissionBubbleManager* bubble_manager = |
146 PermissionBubbleManager::FromWebContents(web_contents_); | 172 PermissionBubbleManager::FromWebContents(web_contents_); |
147 if (bubble_manager) { | 173 if (bubble_manager) { |
148 bubble_manager->AddRequest(new DownloadPermissionRequest( | 174 bubble_manager->AddRequest( |
149 factory_.GetWeakPtr())); | 175 new DownloadPermissionRequest(factory_.GetWeakPtr())); |
150 } else { | 176 } else { |
151 Cancel(); | 177 Cancel(); |
152 } | 178 } |
153 #endif | 179 #endif |
154 } | 180 } |
155 | 181 |
156 void DownloadRequestLimiter::TabDownloadState::SetContentSetting( | 182 void DownloadRequestLimiter::TabDownloadState::SetContentSetting( |
157 ContentSetting setting) { | 183 ContentSetting setting) { |
158 if (!web_contents_) | 184 if (!web_contents_) |
159 return; | 185 return; |
160 HostContentSettingsMap* settings = | 186 HostContentSettingsMap* settings = |
161 DownloadRequestLimiter::GetContentSettings(web_contents_); | 187 DownloadRequestLimiter::GetContentSettings(web_contents_); |
162 if (!settings) | 188 if (!settings) |
163 return; | 189 return; |
164 settings->SetContentSettingDefaultScope( | 190 settings->SetContentSettingDefaultScope( |
165 web_contents_->GetURL(), GURL(), | 191 web_contents_->GetURL(), GURL(), |
166 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, std::string(), setting); | 192 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, std::string(), setting); |
167 } | 193 } |
168 | 194 |
169 void DownloadRequestLimiter::TabDownloadState::Cancel() { | 195 void DownloadRequestLimiter::TabDownloadState::Cancel() { |
170 SetContentSetting(CONTENT_SETTING_BLOCK); | 196 SetContentSetting(CONTENT_SETTING_BLOCK); |
171 NotifyCallbacks(false); | 197 NotifyCallbacks(false); |
172 } | 198 } |
173 | 199 |
174 void DownloadRequestLimiter::TabDownloadState::CancelOnce() { | 200 void DownloadRequestLimiter::TabDownloadState::CancelOnce() { |
175 NotifyCallbacks(false); | 201 NotifyCallbacks(false); |
176 } | 202 } |
177 | 203 |
178 void DownloadRequestLimiter::TabDownloadState::Accept() { | 204 void DownloadRequestLimiter::TabDownloadState::Accept() { |
179 SetContentSetting(CONTENT_SETTING_ALLOW); | 205 SetContentSetting(CONTENT_SETTING_ALLOW); |
180 NotifyCallbacks(true); | 206 NotifyCallbacks(true); |
181 } | 207 } |
182 | 208 |
183 DownloadRequestLimiter::TabDownloadState::TabDownloadState() | 209 DownloadRequestLimiter::TabDownloadState::TabDownloadState() |
184 : web_contents_(NULL), | 210 : web_contents_(NULL), |
185 host_(NULL), | 211 host_(NULL), |
186 status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD), | 212 status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD), |
187 download_count_(0), | 213 download_count_(0), |
188 factory_(this) { | 214 factory_(this) {} |
189 } | |
190 | 215 |
191 bool DownloadRequestLimiter::TabDownloadState::is_showing_prompt() const { | 216 bool DownloadRequestLimiter::TabDownloadState::is_showing_prompt() const { |
192 return factory_.HasWeakPtrs(); | 217 return factory_.HasWeakPtrs(); |
193 } | 218 } |
194 | 219 |
195 void DownloadRequestLimiter::TabDownloadState::Observe( | 220 void DownloadRequestLimiter::TabDownloadState::Observe( |
196 int type, | 221 int type, |
197 const content::NotificationSource& source, | 222 const content::NotificationSource& source, |
198 const content::NotificationDetails& details) { | 223 const content::NotificationDetails& details) { |
199 DCHECK(type == chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED || | 224 DCHECK(type == chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED); |
200 type == content::NOTIFICATION_NAV_ENTRY_PENDING); | |
201 | 225 |
202 // Content settings have been updated for our web contents, e.g. via the OIB | 226 // Content settings have been updated for our web contents, e.g. via the OIB |
203 // or the settings page. Check to see if the automatic downloads setting is | 227 // or the settings page. Check to see if the automatic downloads setting is |
204 // different to our internal state, and update the internal state to match if | 228 // different to our internal state, and update the internal state to match if |
205 // necessary. If there is no content setting persisted, then retain the | 229 // necessary. If there is no content setting persisted, then retain the |
206 // current state and do nothing. | 230 // current state and do nothing. |
207 // | 231 // |
208 // NotifyCallbacks is not called as this notification should be triggered when | 232 // NotifyCallbacks is not called as this notification should be triggered when |
209 // a download is not pending. | 233 // a download is not pending. |
210 if (type == chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED) { | 234 content::WebContents* contents = |
211 content::WebContents* contents = | 235 content::Source<content::WebContents>(source).ptr(); |
212 content::Source<content::WebContents>(source).ptr(); | 236 DCHECK_EQ(contents, web_contents()); |
213 DCHECK_EQ(contents, web_contents()); | |
214 | 237 |
215 // Fetch the content settings map for this web contents, and extract the | 238 // Fetch the content settings map for this web contents, and extract the |
216 // automatic downloads permission value. | 239 // automatic downloads permission value. |
217 HostContentSettingsMap* content_settings = GetContentSettings(contents); | 240 HostContentSettingsMap* content_settings = GetContentSettings(contents); |
218 if (content_settings) { | 241 if (content_settings) { |
219 ContentSetting setting = content_settings->GetContentSetting( | 242 ContentSetting setting = content_settings->GetContentSetting( |
220 contents->GetURL(), contents->GetURL(), | 243 contents->GetURL(), contents->GetURL(), |
221 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, std::string()); | 244 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, std::string()); |
222 | 245 |
223 // Update the internal state to match if necessary. | 246 // Update the internal state to match if necessary. |
224 switch (setting) { | 247 switch (setting) { |
225 case CONTENT_SETTING_ALLOW: | 248 case CONTENT_SETTING_ALLOW: |
226 set_download_status(ALLOW_ALL_DOWNLOADS); | 249 set_download_status(ALLOW_ALL_DOWNLOADS); |
227 break; | 250 break; |
228 case CONTENT_SETTING_BLOCK: | 251 case CONTENT_SETTING_BLOCK: |
229 set_download_status(DOWNLOADS_NOT_ALLOWED); | 252 set_download_status(DOWNLOADS_NOT_ALLOWED); |
230 break; | 253 break; |
231 case CONTENT_SETTING_ASK: | 254 case CONTENT_SETTING_ASK: |
232 case CONTENT_SETTING_DEFAULT: | 255 case CONTENT_SETTING_DEFAULT: |
233 case CONTENT_SETTING_SESSION_ONLY: | 256 case CONTENT_SETTING_SESSION_ONLY: |
234 set_download_status(PROMPT_BEFORE_DOWNLOAD); | 257 set_download_status(PROMPT_BEFORE_DOWNLOAD); |
235 break; | 258 break; |
236 case CONTENT_SETTING_NUM_SETTINGS: | 259 case CONTENT_SETTING_NUM_SETTINGS: |
237 case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT: | 260 case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT: |
238 NOTREACHED(); | 261 NOTREACHED(); |
239 return; | 262 return; |
240 } | |
241 } | 263 } |
242 return; | |
243 } | 264 } |
244 | |
245 // Otherwise, there is a pending navigation entry. | |
246 content::NavigationController* controller = &web_contents()->GetController(); | |
247 DCHECK_EQ(controller, content::Source<NavigationController>(source).ptr()); | |
248 | |
249 // NOTE: Resetting state on a pending navigate isn't ideal. In particular it | |
250 // is possible that queued up downloads for the page before the pending | |
251 // navigation will be delivered to us after we process this request. If this | |
252 // happens we may let a download through that we shouldn't have. But this is | |
253 // rather rare, and it is difficult to get 100% right, so we don't deal with | |
254 // it. | |
255 NavigationEntry* entry = controller->GetPendingEntry(); | |
256 if (!entry) | |
257 return; | |
258 | |
259 // Redirects don't count. | |
260 if (ui::PageTransitionIsRedirect(entry->GetTransitionType())) | |
261 return; | |
262 | |
263 if (status_ == DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS || | |
264 status_ == DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED) { | |
265 // User has either allowed all downloads or canceled all downloads. Only | |
266 // reset the download state if the user is navigating to a different host | |
267 // (or host is empty). | |
268 if (!initial_page_host_.empty() && !entry->GetURL().host().empty() && | |
269 entry->GetURL().host() == initial_page_host_) | |
270 return; | |
271 } | |
272 | |
273 NotifyCallbacks(false); | |
274 host_->Remove(this, web_contents()); | |
275 } | 265 } |
276 | 266 |
277 void DownloadRequestLimiter::TabDownloadState::NotifyCallbacks(bool allow) { | 267 void DownloadRequestLimiter::TabDownloadState::NotifyCallbacks(bool allow) { |
278 set_download_status(allow ? | 268 set_download_status(allow ? DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS |
279 DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS : | 269 : DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED); |
280 DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED); | |
281 std::vector<DownloadRequestLimiter::Callback> callbacks; | 270 std::vector<DownloadRequestLimiter::Callback> callbacks; |
282 bool change_status = false; | 271 bool change_status = false; |
283 | 272 |
284 // Selectively send first few notifications only if number of downloads exceed | 273 // Selectively send first few notifications only if number of downloads exceed |
285 // kMaxDownloadsAtOnce. In that case, we also retain the infobar instance and | 274 // kMaxDownloadsAtOnce. In that case, we also retain the infobar instance and |
286 // don't close it. If allow is false, we send all the notifications to cancel | 275 // don't close it. If allow is false, we send all the notifications to cancel |
287 // all remaining downloads and close the infobar. | 276 // all remaining downloads and close the infobar. |
288 if (!allow || (callbacks_.size() < kMaxDownloadsAtOnce)) { | 277 if (!allow || (callbacks_.size() < kMaxDownloadsAtOnce)) { |
289 // Null the generated weak pointer so we don't get notified again. | 278 // Null the generated weak pointer so we don't get notified again. |
290 factory_.InvalidateWeakPtrs(); | 279 factory_.InvalidateWeakPtrs(); |
(...skipping 19 matching lines...) Expand all Loading... | |
310 | 299 |
311 // DownloadRequestLimiter ------------------------------------------------------ | 300 // DownloadRequestLimiter ------------------------------------------------------ |
312 | 301 |
313 HostContentSettingsMap* DownloadRequestLimiter::content_settings_ = NULL; | 302 HostContentSettingsMap* DownloadRequestLimiter::content_settings_ = NULL; |
314 | 303 |
315 void DownloadRequestLimiter::SetContentSettingsForTesting( | 304 void DownloadRequestLimiter::SetContentSettingsForTesting( |
316 HostContentSettingsMap* content_settings) { | 305 HostContentSettingsMap* content_settings) { |
317 content_settings_ = content_settings; | 306 content_settings_ = content_settings; |
318 } | 307 } |
319 | 308 |
320 DownloadRequestLimiter::DownloadRequestLimiter() | 309 DownloadRequestLimiter::DownloadRequestLimiter() : factory_(this) {} |
321 : factory_(this) { | |
322 } | |
323 | 310 |
324 DownloadRequestLimiter::~DownloadRequestLimiter() { | 311 DownloadRequestLimiter::~DownloadRequestLimiter() { |
325 // All the tabs should have closed before us, which sends notification and | 312 // All the tabs should have closed before us, which sends notification and |
326 // removes from state_map_. As such, there should be no pending callbacks. | 313 // removes from state_map_. As such, there should be no pending callbacks. |
327 DCHECK(state_map_.empty()); | 314 DCHECK(state_map_.empty()); |
328 } | 315 } |
329 | 316 |
330 DownloadRequestLimiter::DownloadStatus | 317 DownloadRequestLimiter::DownloadStatus |
331 DownloadRequestLimiter::GetDownloadStatus(content::WebContents* web_contents) { | 318 DownloadRequestLimiter::GetDownloadStatus(content::WebContents* web_contents) { |
332 TabDownloadState* state = GetDownloadState(web_contents, NULL, false); | 319 TabDownloadState* state = GetDownloadState(web_contents, NULL, false); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
371 return; | 358 return; |
372 } | 359 } |
373 | 360 |
374 // Note that because |originating_contents| might go away before | 361 // Note that because |originating_contents| might go away before |
375 // OnCanDownloadDecided is invoked, we look it up by |render_process_host_id| | 362 // OnCanDownloadDecided is invoked, we look it up by |render_process_host_id| |
376 // and |render_view_id|. | 363 // and |render_view_id|. |
377 base::Callback<void(bool)> can_download_callback = base::Bind( | 364 base::Callback<void(bool)> can_download_callback = base::Bind( |
378 &DownloadRequestLimiter::OnCanDownloadDecided, factory_.GetWeakPtr(), | 365 &DownloadRequestLimiter::OnCanDownloadDecided, factory_.GetWeakPtr(), |
379 web_contents_getter, request_method, callback); | 366 web_contents_getter, request_method, callback); |
380 | 367 |
381 originating_contents->GetDelegate()->CanDownload( | 368 originating_contents->GetDelegate()->CanDownload(url, request_method, |
382 url, | 369 can_download_callback); |
383 request_method, | |
384 can_download_callback); | |
385 } | 370 } |
386 | 371 |
387 void DownloadRequestLimiter::OnCanDownloadDecided( | 372 void DownloadRequestLimiter::OnCanDownloadDecided( |
388 const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, | 373 const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, |
389 const std::string& request_method, | 374 const std::string& request_method, |
390 const Callback& orig_callback, | 375 const Callback& orig_callback, |
391 bool allow) { | 376 bool allow) { |
392 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 377 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
393 content::WebContents* originating_contents = web_contents_getter.Run(); | 378 content::WebContents* originating_contents = web_contents_getter.Run(); |
394 if (!originating_contents || !allow) { | 379 if (!originating_contents || !allow) { |
395 orig_callback.Run(false); | 380 orig_callback.Run(false); |
396 return; | 381 return; |
397 } | 382 } |
398 | 383 |
399 CanDownloadImpl(originating_contents, | 384 CanDownloadImpl(originating_contents, request_method, orig_callback); |
400 request_method, | |
401 orig_callback); | |
402 } | 385 } |
403 | 386 |
404 HostContentSettingsMap* DownloadRequestLimiter::GetContentSettings( | 387 HostContentSettingsMap* DownloadRequestLimiter::GetContentSettings( |
405 content::WebContents* contents) { | 388 content::WebContents* contents) { |
406 return content_settings_ ? content_settings_ : | 389 return content_settings_ |
407 HostContentSettingsMapFactory::GetForProfile( | 390 ? content_settings_ |
408 Profile::FromBrowserContext(contents->GetBrowserContext())); | 391 : HostContentSettingsMapFactory::GetForProfile( |
392 Profile::FromBrowserContext(contents->GetBrowserContext())); | |
409 } | 393 } |
410 | 394 |
411 void DownloadRequestLimiter::CanDownloadImpl( | 395 void DownloadRequestLimiter::CanDownloadImpl( |
412 content::WebContents* originating_contents, | 396 content::WebContents* originating_contents, |
413 const std::string& request_method, | 397 const std::string& request_method, |
414 const Callback& callback) { | 398 const Callback& callback) { |
415 DCHECK(originating_contents); | 399 DCHECK(originating_contents); |
416 | 400 |
417 TabDownloadState* state = GetDownloadState( | 401 TabDownloadState* state = |
418 originating_contents, originating_contents, true); | 402 GetDownloadState(originating_contents, originating_contents, true); |
419 switch (state->download_status()) { | 403 switch (state->download_status()) { |
420 case ALLOW_ALL_DOWNLOADS: | 404 case ALLOW_ALL_DOWNLOADS: |
421 if (state->download_count() && !(state->download_count() % | 405 if (state->download_count() && |
406 !(state->download_count() % | |
422 DownloadRequestLimiter::kMaxDownloadsAtOnce)) | 407 DownloadRequestLimiter::kMaxDownloadsAtOnce)) |
423 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); | 408 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); |
424 callback.Run(true); | 409 callback.Run(true); |
425 state->increment_download_count(); | 410 state->increment_download_count(); |
426 break; | 411 break; |
427 | 412 |
428 case ALLOW_ONE_DOWNLOAD: | 413 case ALLOW_ONE_DOWNLOAD: |
429 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); | 414 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); |
430 callback.Run(true); | 415 callback.Run(true); |
431 state->increment_download_count(); | 416 state->increment_download_count(); |
432 break; | 417 break; |
433 | 418 |
434 case DOWNLOADS_NOT_ALLOWED: | 419 case DOWNLOADS_NOT_ALLOWED: |
435 callback.Run(false); | 420 callback.Run(false); |
436 break; | 421 break; |
437 | 422 |
438 case PROMPT_BEFORE_DOWNLOAD: { | 423 case PROMPT_BEFORE_DOWNLOAD: { |
439 HostContentSettingsMap* content_settings = GetContentSettings( | 424 HostContentSettingsMap* content_settings = |
440 originating_contents); | 425 GetContentSettings(originating_contents); |
441 ContentSetting setting = CONTENT_SETTING_ASK; | 426 ContentSetting setting = CONTENT_SETTING_ASK; |
442 if (content_settings) | 427 if (content_settings) |
443 setting = content_settings->GetContentSetting( | 428 setting = content_settings->GetContentSetting( |
444 originating_contents->GetURL(), | 429 originating_contents->GetURL(), originating_contents->GetURL(), |
445 originating_contents->GetURL(), | 430 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, std::string()); |
446 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, | |
447 std::string()); | |
448 switch (setting) { | 431 switch (setting) { |
449 case CONTENT_SETTING_ALLOW: { | 432 case CONTENT_SETTING_ALLOW: { |
450 TabSpecificContentSettings* settings = | 433 TabSpecificContentSettings* settings = |
451 TabSpecificContentSettings::FromWebContents( | 434 TabSpecificContentSettings::FromWebContents(originating_contents); |
452 originating_contents); | |
453 if (settings) | 435 if (settings) |
454 settings->SetDownloadsBlocked(false); | 436 settings->SetDownloadsBlocked(false); |
455 callback.Run(true); | 437 callback.Run(true); |
456 state->increment_download_count(); | 438 state->increment_download_count(); |
457 return; | 439 return; |
458 } | 440 } |
459 case CONTENT_SETTING_BLOCK: { | 441 case CONTENT_SETTING_BLOCK: { |
460 TabSpecificContentSettings* settings = | 442 TabSpecificContentSettings* settings = |
461 TabSpecificContentSettings::FromWebContents( | 443 TabSpecificContentSettings::FromWebContents(originating_contents); |
462 originating_contents); | |
463 if (settings) | 444 if (settings) |
464 settings->SetDownloadsBlocked(true); | 445 settings->SetDownloadsBlocked(true); |
465 callback.Run(false); | 446 callback.Run(false); |
466 return; | 447 return; |
467 } | 448 } |
468 case CONTENT_SETTING_DEFAULT: | 449 case CONTENT_SETTING_DEFAULT: |
469 case CONTENT_SETTING_ASK: | 450 case CONTENT_SETTING_ASK: |
470 case CONTENT_SETTING_SESSION_ONLY: | 451 case CONTENT_SETTING_SESSION_ONLY: |
471 state->PromptUserForDownload(callback); | 452 state->PromptUserForDownload(callback); |
472 state->increment_download_count(); | 453 state->increment_download_count(); |
(...skipping 10 matching lines...) Expand all Loading... | |
483 NOTREACHED(); | 464 NOTREACHED(); |
484 } | 465 } |
485 } | 466 } |
486 | 467 |
487 void DownloadRequestLimiter::Remove(TabDownloadState* state, | 468 void DownloadRequestLimiter::Remove(TabDownloadState* state, |
488 content::WebContents* contents) { | 469 content::WebContents* contents) { |
489 DCHECK(ContainsKey(state_map_, contents)); | 470 DCHECK(ContainsKey(state_map_, contents)); |
490 state_map_.erase(contents); | 471 state_map_.erase(contents); |
491 delete state; | 472 delete state; |
492 } | 473 } |
OLD | NEW |