| 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/download/download_request_infobar_delegate.h" | 9 #include "chrome/browser/download/download_request_infobar_delegate.h" |
| 10 #include "chrome/browser/infobars/infobar_tab_helper.h" | 10 #include "chrome/browser/infobars/infobar_tab_helper.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 | 22 |
| 23 using content::BrowserThread; | 23 using content::BrowserThread; |
| 24 using content::NavigationController; | 24 using content::NavigationController; |
| 25 using content::NavigationEntry; | 25 using content::NavigationEntry; |
| 26 using content::WebContents; | 26 using content::WebContents; |
| 27 | 27 |
| 28 // TabDownloadState ------------------------------------------------------------ | 28 // TabDownloadState ------------------------------------------------------------ |
| 29 | 29 |
| 30 DownloadRequestLimiter::TabDownloadState::TabDownloadState( | 30 DownloadRequestLimiter::TabDownloadState::TabDownloadState( |
| 31 DownloadRequestLimiter* host, | 31 DownloadRequestLimiter* host, |
| 32 NavigationController* controller, | 32 WebContents* contents, |
| 33 NavigationController* originating_controller) | 33 WebContents* originating_web_contents) |
| 34 : host_(host), | 34 : content::WebContentsObserver(contents), |
| 35 controller_(controller), | 35 host_(host), |
| 36 status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD), | 36 status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD), |
| 37 download_count_(0), | 37 download_count_(0), |
| 38 infobar_(NULL) { | 38 infobar_(NULL) { |
| 39 content::Source<NavigationController> notification_source(controller); | 39 content::Source<NavigationController> notification_source( |
| 40 content::Source<content::WebContents> web_contents_source( | 40 &contents->GetController()); |
| 41 controller->GetWebContents()); | 41 content::Source<content::WebContents> web_contents_source(contents); |
| 42 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, | 42 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
| 43 notification_source); | 43 notification_source); |
| 44 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 44 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| 45 web_contents_source); | 45 web_contents_source); |
| 46 | 46 |
| 47 NavigationEntry* active_entry = originating_controller ? | 47 NavigationEntry* active_entry = originating_web_contents ? |
| 48 originating_controller->GetActiveEntry() : controller->GetActiveEntry(); | 48 originating_web_contents->GetController().GetActiveEntry() : |
| 49 contents->GetController().GetActiveEntry(); |
| 49 if (active_entry) | 50 if (active_entry) |
| 50 initial_page_host_ = active_entry->GetURL().host(); | 51 initial_page_host_ = active_entry->GetURL().host(); |
| 51 } | 52 } |
| 52 | 53 |
| 53 DownloadRequestLimiter::TabDownloadState::~TabDownloadState() { | 54 DownloadRequestLimiter::TabDownloadState::~TabDownloadState() { |
| 54 // We should only be destroyed after the callbacks have been notified. | 55 // We should only be destroyed after the callbacks have been notified. |
| 55 DCHECK(callbacks_.empty()); | 56 DCHECK(callbacks_.empty()); |
| 56 | 57 |
| 57 // And we should have closed the infobar. | 58 // And we should have closed the infobar. |
| 58 DCHECK(!infobar_); | 59 DCHECK(!infobar_); |
| 59 } | 60 } |
| 60 | 61 |
| 61 void DownloadRequestLimiter::TabDownloadState::OnUserGesture() { | 62 void DownloadRequestLimiter::TabDownloadState::DidGetUserGesture() { |
| 62 if (is_showing_prompt()) { | 63 if (is_showing_prompt()) { |
| 63 // Don't change the state if the user clicks on the page some where. | 64 // Don't change the state if the user clicks on the page some where. |
| 64 return; | 65 return; |
| 65 } | 66 } |
| 66 | 67 |
| 67 if (status_ != DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS && | 68 TabContentsWrapper* tab_wrapper = |
| 68 status_ != DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED) { | 69 TabContentsWrapper::GetCurrentWrapperForContents(web_contents()); |
| 70 // See PromptUserForDownload(): if there's no TCW, then DOWNLOADS_NOT_ALLOWED |
| 71 // is functionally equivalent to PROMPT_BEFORE_DOWNLOAD. |
| 72 if ((tab_wrapper && |
| 73 status_ != DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS && |
| 74 status_ != DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED) || |
| 75 (!tab_wrapper && |
| 76 status_ != DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS)) { |
| 69 // Revert to default status. | 77 // Revert to default status. |
| 70 host_->Remove(this); | 78 host_->Remove(this); |
| 71 // WARNING: We've been deleted. | 79 // WARNING: We've been deleted. |
| 72 return; | |
| 73 } | 80 } |
| 74 } | 81 } |
| 75 | 82 |
| 76 void DownloadRequestLimiter::TabDownloadState::PromptUserForDownload( | 83 void DownloadRequestLimiter::TabDownloadState::PromptUserForDownload( |
| 77 WebContents* tab, | 84 WebContents* web_contents, |
| 78 const DownloadRequestLimiter::Callback& callback) { | 85 const DownloadRequestLimiter::Callback& callback) { |
| 79 callbacks_.push_back(callback); | 86 callbacks_.push_back(callback); |
| 80 | 87 |
| 81 if (is_showing_prompt()) | 88 if (is_showing_prompt()) |
| 82 return; // Already showing prompt. | 89 return; // Already showing prompt. |
| 83 | 90 |
| 84 if (DownloadRequestLimiter::delegate_) { | 91 if (DownloadRequestLimiter::delegate_) { |
| 85 NotifyCallbacks(DownloadRequestLimiter::delegate_->ShouldAllowDownload()); | 92 NotifyCallbacks(DownloadRequestLimiter::delegate_->ShouldAllowDownload()); |
| 86 } else { | 93 return; |
| 87 InfoBarTabHelper* infobar_helper = | |
| 88 TabContentsWrapper::GetCurrentWrapperForContents(tab)-> | |
| 89 infobar_tab_helper(); | |
| 90 infobar_ = new DownloadRequestInfoBarDelegate(infobar_helper, this); | |
| 91 infobar_helper->AddInfoBar(infobar_); | |
| 92 } | 94 } |
| 95 TabContentsWrapper* tab_wrapper = |
| 96 TabContentsWrapper::GetCurrentWrapperForContents(web_contents); |
| 97 if (!tab_wrapper) { |
| 98 // If |web_contents| doesn't have a tab_wrapper, then it isn't what a user |
| 99 // thinks of as a tab, it's actually a "raw" WebContents like those used |
| 100 // for extension popups/bubbles and hosted apps etc. |
| 101 // TODO(benjhayden): If this is an automatic download from an extension, |
| 102 // it would be convenient for the extension author if we send a message to |
| 103 // the extension's DevTools console (as we do for CSP) about how |
| 104 // extensions should use chrome.downloads.download() (requires the |
| 105 // "downloads" permission) to automatically download >1 files. |
| 106 Cancel(); |
| 107 return; |
| 108 } |
| 109 InfoBarTabHelper* infobar_helper = tab_wrapper->infobar_tab_helper(); |
| 110 infobar_ = new DownloadRequestInfoBarDelegate(infobar_helper, this); |
| 111 infobar_helper->AddInfoBar(infobar_); |
| 93 } | 112 } |
| 94 | 113 |
| 95 void DownloadRequestLimiter::TabDownloadState::Cancel() { | 114 void DownloadRequestLimiter::TabDownloadState::Cancel() { |
| 96 NotifyCallbacks(false); | 115 NotifyCallbacks(false); |
| 97 } | 116 } |
| 98 | 117 |
| 99 void DownloadRequestLimiter::TabDownloadState::Accept() { | 118 void DownloadRequestLimiter::TabDownloadState::Accept() { |
| 100 NotifyCallbacks(true); | 119 NotifyCallbacks(true); |
| 101 } | 120 } |
| 102 | 121 |
| 103 void DownloadRequestLimiter::TabDownloadState::Observe( | 122 void DownloadRequestLimiter::TabDownloadState::Observe( |
| 104 int type, | 123 int type, |
| 105 const content::NotificationSource& source, | 124 const content::NotificationSource& source, |
| 106 const content::NotificationDetails& details) { | 125 const content::NotificationDetails& details) { |
| 107 if (type != content::NOTIFICATION_NAV_ENTRY_PENDING && | 126 if (type != content::NOTIFICATION_NAV_ENTRY_PENDING && |
| 108 type != content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { | 127 type != content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { |
| 109 NOTREACHED(); | 128 NOTREACHED(); |
| 110 return; | 129 return; |
| 111 } | 130 } |
| 131 content::NavigationController* controller = &web_contents()->GetController(); |
| 112 if (type == content::NOTIFICATION_NAV_ENTRY_PENDING && | 132 if (type == content::NOTIFICATION_NAV_ENTRY_PENDING && |
| 113 content::Source<NavigationController>(source).ptr() != controller_) { | 133 content::Source<NavigationController>(source).ptr() != controller) { |
| 114 NOTREACHED(); | 134 NOTREACHED(); |
| 115 return; | 135 return; |
| 116 } | 136 } |
| 117 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED && | 137 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED && |
| 118 &content::Source<content::WebContents>(source).ptr()-> | 138 &content::Source<content::WebContents>(source).ptr()-> |
| 119 GetController() != controller_) { | 139 GetController() != controller) { |
| 120 NOTREACHED(); | 140 NOTREACHED(); |
| 121 return; | 141 return; |
| 122 } | 142 } |
| 123 | 143 |
| 124 switch (type) { | 144 switch (type) { |
| 125 case content::NOTIFICATION_NAV_ENTRY_PENDING: { | 145 case content::NOTIFICATION_NAV_ENTRY_PENDING: { |
| 126 // NOTE: resetting state on a pending navigate isn't ideal. In particular | 146 // NOTE: resetting state on a pending navigate isn't ideal. In particular |
| 127 // it is possible that queued up downloads for the page before the | 147 // it is possible that queued up downloads for the page before the |
| 128 // pending navigate will be delivered to us after we process this | 148 // pending navigate will be delivered to us after we process this |
| 129 // request. If this happens we may let a download through that we | 149 // request. If this happens we may let a download through that we |
| 130 // shouldn't have. But this is rather rare, and it is difficult to get | 150 // shouldn't have. But this is rather rare, and it is difficult to get |
| 131 // 100% right, so we don't deal with it. | 151 // 100% right, so we don't deal with it. |
| 132 NavigationEntry* entry = controller_->GetPendingEntry(); | 152 NavigationEntry* entry = controller->GetPendingEntry(); |
| 133 if (!entry) | 153 if (!entry) |
| 134 return; | 154 return; |
| 135 | 155 |
| 136 if (content::PageTransitionIsRedirect(entry->GetTransitionType())) { | 156 if (content::PageTransitionIsRedirect(entry->GetTransitionType())) { |
| 137 // Redirects don't count. | 157 // Redirects don't count. |
| 138 return; | 158 return; |
| 139 } | 159 } |
| 140 | 160 |
| 141 if (status_ == DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS || | 161 if (status_ == DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS || |
| 142 status_ == DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED) { | 162 status_ == DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 158 | 178 |
| 159 default: | 179 default: |
| 160 NOTREACHED(); | 180 NOTREACHED(); |
| 161 } | 181 } |
| 162 | 182 |
| 163 NotifyCallbacks(false); | 183 NotifyCallbacks(false); |
| 164 host_->Remove(this); | 184 host_->Remove(this); |
| 165 } | 185 } |
| 166 | 186 |
| 167 void DownloadRequestLimiter::TabDownloadState::NotifyCallbacks(bool allow) { | 187 void DownloadRequestLimiter::TabDownloadState::NotifyCallbacks(bool allow) { |
| 168 status_ = allow ? | 188 set_download_status(allow ? |
| 169 DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS : | 189 DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS : |
| 170 DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED; | 190 DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED); |
| 171 std::vector<DownloadRequestLimiter::Callback> callbacks; | 191 std::vector<DownloadRequestLimiter::Callback> callbacks; |
| 172 bool change_status = false; | 192 bool change_status = false; |
| 173 | 193 |
| 174 // Selectively send first few notifications only if number of downloads exceed | 194 // Selectively send first few notifications only if number of downloads exceed |
| 175 // kMaxDownloadsAtOnce. In that case, we also retain the infobar instance and | 195 // kMaxDownloadsAtOnce. In that case, we also retain the infobar instance and |
| 176 // don't close it. If allow is false, we send all the notifications to cancel | 196 // don't close it. If allow is false, we send all the notifications to cancel |
| 177 // all remaining downloads and close the infobar. | 197 // all remaining downloads and close the infobar. |
| 178 if (!allow || (callbacks_.size() < kMaxDownloadsAtOnce)) { | 198 if (!allow || (callbacks_.size() < kMaxDownloadsAtOnce)) { |
| 179 if (infobar_) { | 199 if (infobar_) { |
| 180 // Reset the delegate so we don't get notified again. | 200 // Reset the delegate so we don't get notified again. |
| 181 infobar_->set_host(NULL); | 201 infobar_->set_host(NULL); |
| 182 infobar_ = NULL; | 202 infobar_ = NULL; |
| 183 } | 203 } |
| 184 callbacks.swap(callbacks_); | 204 callbacks.swap(callbacks_); |
| 185 } else { | 205 } else { |
| 186 std::vector<DownloadRequestLimiter::Callback>::iterator start, end; | 206 std::vector<DownloadRequestLimiter::Callback>::iterator start, end; |
| 187 start = callbacks_.begin(); | 207 start = callbacks_.begin(); |
| 188 end = callbacks_.begin() + kMaxDownloadsAtOnce; | 208 end = callbacks_.begin() + kMaxDownloadsAtOnce; |
| 189 callbacks.assign(start, end); | 209 callbacks.assign(start, end); |
| 190 callbacks_.erase(start, end); | 210 callbacks_.erase(start, end); |
| 191 change_status = true; | 211 change_status = true; |
| 192 } | 212 } |
| 193 | 213 |
| 194 for (size_t i = 0; i < callbacks.size(); ++i) | 214 for (size_t i = 0; i < callbacks.size(); ++i) |
| 195 host_->ScheduleNotification(callbacks[i], allow); | 215 host_->ScheduleNotification(callbacks[i], allow); |
| 196 | 216 |
| 197 if (change_status) | 217 if (change_status) |
| 198 status_ = DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD; | 218 set_download_status(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD); |
| 199 } | 219 } |
| 200 | 220 |
| 201 // DownloadRequestLimiter ------------------------------------------------------ | 221 // DownloadRequestLimiter ------------------------------------------------------ |
| 202 | 222 |
| 203 DownloadRequestLimiter::DownloadRequestLimiter() { | 223 DownloadRequestLimiter::DownloadRequestLimiter() { |
| 204 } | 224 } |
| 205 | 225 |
| 206 DownloadRequestLimiter::~DownloadRequestLimiter() { | 226 DownloadRequestLimiter::~DownloadRequestLimiter() { |
| 207 // All the tabs should have closed before us, which sends notification and | 227 // All the tabs should have closed before us, which sends notification and |
| 208 // removes from state_map_. As such, there should be no pending callbacks. | 228 // removes from state_map_. As such, there should be no pending callbacks. |
| 209 DCHECK(state_map_.empty()); | 229 DCHECK(state_map_.empty()); |
| 210 } | 230 } |
| 211 | 231 |
| 212 DownloadRequestLimiter::DownloadStatus | 232 DownloadRequestLimiter::DownloadStatus |
| 213 DownloadRequestLimiter::GetDownloadStatus(WebContents* tab) { | 233 DownloadRequestLimiter::GetDownloadStatus(WebContents* web_contents) { |
| 214 TabDownloadState* state = GetDownloadState(&tab->GetController(), NULL, false)
; | 234 TabDownloadState* state = GetDownloadState(web_contents, NULL, false); |
| 215 return state ? state->download_status() : ALLOW_ONE_DOWNLOAD; | 235 return state ? state->download_status() : ALLOW_ONE_DOWNLOAD; |
| 216 } | 236 } |
| 217 | 237 |
| 218 void DownloadRequestLimiter::CanDownloadOnIOThread( | 238 void DownloadRequestLimiter::CanDownloadOnIOThread( |
| 219 int render_process_host_id, | 239 int render_process_host_id, |
| 220 int render_view_id, | 240 int render_view_id, |
| 221 int request_id, | 241 int request_id, |
| 222 const std::string& request_method, | 242 const std::string& request_method, |
| 223 const Callback& callback) { | 243 const Callback& callback) { |
| 224 // This is invoked on the IO thread. Schedule the task to run on the UI | 244 // This is invoked on the IO thread. Schedule the task to run on the UI |
| 225 // thread so that we can query UI state. | 245 // thread so that we can query UI state. |
| 226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 227 BrowserThread::PostTask( | 247 BrowserThread::PostTask( |
| 228 BrowserThread::UI, FROM_HERE, | 248 BrowserThread::UI, FROM_HERE, |
| 229 base::Bind(&DownloadRequestLimiter::CanDownload, this, | 249 base::Bind(&DownloadRequestLimiter::CanDownload, this, |
| 230 render_process_host_id, render_view_id, request_id, | 250 render_process_host_id, render_view_id, request_id, |
| 231 request_method, callback)); | 251 request_method, callback)); |
| 232 } | 252 } |
| 233 | 253 |
| 234 void DownloadRequestLimiter::OnUserGesture(WebContents* tab) { | |
| 235 TabDownloadState* state = | |
| 236 GetDownloadState(&tab->GetController(), NULL, false); | |
| 237 if (!state) | |
| 238 return; | |
| 239 | |
| 240 state->OnUserGesture(); | |
| 241 } | |
| 242 | |
| 243 // static | 254 // static |
| 244 void DownloadRequestLimiter::SetTestingDelegate(TestingDelegate* delegate) { | 255 void DownloadRequestLimiter::SetTestingDelegate(TestingDelegate* delegate) { |
| 245 delegate_ = delegate; | 256 delegate_ = delegate; |
| 246 } | 257 } |
| 247 | 258 |
| 248 DownloadRequestLimiter::TabDownloadState* DownloadRequestLimiter:: | 259 DownloadRequestLimiter::TabDownloadState* |
| 249 GetDownloadState(NavigationController* controller, | 260 DownloadRequestLimiter::GetDownloadState( |
| 250 NavigationController* originating_controller, | 261 WebContents* web_contents, |
| 251 bool create) { | 262 WebContents* originating_web_contents, |
| 252 DCHECK(controller); | 263 bool create) { |
| 253 StateMap::iterator i = state_map_.find(controller); | 264 DCHECK(web_contents); |
| 265 StateMap::iterator i = state_map_.find(web_contents); |
| 254 if (i != state_map_.end()) | 266 if (i != state_map_.end()) |
| 255 return i->second; | 267 return i->second; |
| 256 | 268 |
| 257 if (!create) | 269 if (!create) |
| 258 return NULL; | 270 return NULL; |
| 259 | 271 |
| 260 TabDownloadState* state = | 272 TabDownloadState* state = |
| 261 new TabDownloadState(this, controller, originating_controller); | 273 new TabDownloadState(this, web_contents, originating_web_contents); |
| 262 state_map_[controller] = state; | 274 state_map_[web_contents] = state; |
| 263 return state; | 275 return state; |
| 264 } | 276 } |
| 265 | 277 |
| 266 void DownloadRequestLimiter::CanDownload(int render_process_host_id, | 278 void DownloadRequestLimiter::CanDownload(int render_process_host_id, |
| 267 int render_view_id, | 279 int render_view_id, |
| 268 int request_id, | 280 int request_id, |
| 269 const std::string& request_method, | 281 const std::string& request_method, |
| 270 const Callback& callback) { | 282 const Callback& callback) { |
| 271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 272 | 284 |
| 273 WebContents* originating_tab = | 285 WebContents* originating_contents = |
| 274 tab_util::GetWebContentsByID(render_process_host_id, render_view_id); | 286 tab_util::GetWebContentsByID(render_process_host_id, render_view_id); |
| 275 if (!originating_tab) { | 287 if (!originating_contents) { |
| 276 // The tab was closed, don't allow the download. | 288 // The WebContents was closed, don't allow the download. |
| 277 ScheduleNotification(callback, false); | 289 ScheduleNotification(callback, false); |
| 278 return; | 290 return; |
| 279 } | 291 } |
| 280 | 292 |
| 281 CanDownloadImpl( | 293 CanDownloadImpl( |
| 282 TabContentsWrapper::GetCurrentWrapperForContents(originating_tab), | 294 originating_contents, |
| 283 request_id, | 295 request_id, |
| 284 request_method, | 296 request_method, |
| 285 callback); | 297 callback); |
| 286 } | 298 } |
| 287 | 299 |
| 288 void DownloadRequestLimiter::CanDownloadImpl( | 300 void DownloadRequestLimiter::CanDownloadImpl(WebContents* originating_contents, |
| 289 TabContentsWrapper* originating_tab, | 301 int request_id, |
| 290 int request_id, | 302 const std::string& request_method, |
| 291 const std::string& request_method, | 303 const Callback& callback) { |
| 292 const Callback& callback) { | 304 DCHECK(originating_contents); |
| 293 DCHECK(originating_tab); | |
| 294 | 305 |
| 295 // FYI: Chrome Frame overrides CanDownload in ExternalTabContainer in order | 306 // FYI: Chrome Frame overrides CanDownload in ExternalTabContainer in order |
| 296 // to cancel the download operation in chrome and let the host browser | 307 // to cancel the download operation in chrome and let the host browser |
| 297 // take care of it. | 308 // take care of it. |
| 298 WebContents* tab = originating_tab->web_contents(); | 309 if (originating_contents->GetDelegate() && |
| 299 if (tab->GetDelegate() && !tab->GetDelegate()->CanDownload( | 310 !originating_contents->GetDelegate()->CanDownload( |
| 300 tab->GetRenderViewHost(), request_id, request_method)) { | 311 originating_contents->GetRenderViewHost(), |
| 312 request_id, |
| 313 request_method)) { |
| 301 ScheduleNotification(callback, false); | 314 ScheduleNotification(callback, false); |
| 302 return; | 315 return; |
| 303 } | 316 } |
| 304 | 317 |
| 305 // If the tab requesting the download is a constrained popup that is not | 318 // If the tab requesting the download is a constrained popup that is not |
| 306 // shown, treat the request as if it came from the parent. | 319 // shown, treat the request as if it came from the parent. |
| 307 TabContentsWrapper* effective_wrapper = originating_tab; | 320 WebContents* effective_contents = originating_contents; |
| 308 if (effective_wrapper->blocked_content_tab_helper()->delegate()) { | 321 TabContentsWrapper* originating_wrapper = |
| 309 effective_wrapper = effective_wrapper->blocked_content_tab_helper()-> | 322 TabContentsWrapper::GetCurrentWrapperForContents(originating_contents); |
| 310 delegate()->GetConstrainingContentsWrapper(effective_wrapper); | 323 if (originating_wrapper && |
| 324 originating_wrapper->blocked_content_tab_helper()->delegate()) { |
| 325 effective_contents = originating_wrapper->blocked_content_tab_helper()-> |
| 326 delegate()->GetConstrainingContentsWrapper(originating_wrapper)-> |
| 327 web_contents(); |
| 311 } | 328 } |
| 312 | 329 |
| 313 TabDownloadState* state = GetDownloadState( | 330 TabDownloadState* state = GetDownloadState( |
| 314 &effective_wrapper->web_contents()->GetController(), | 331 effective_contents, originating_contents, true); |
| 315 &tab->GetController(), true); | |
| 316 switch (state->download_status()) { | 332 switch (state->download_status()) { |
| 317 case ALLOW_ALL_DOWNLOADS: | 333 case ALLOW_ALL_DOWNLOADS: |
| 318 if (state->download_count() && !(state->download_count() % | 334 if (state->download_count() && !(state->download_count() % |
| 319 DownloadRequestLimiter::kMaxDownloadsAtOnce)) | 335 DownloadRequestLimiter::kMaxDownloadsAtOnce)) |
| 320 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); | 336 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); |
| 321 ScheduleNotification(callback, true); | 337 ScheduleNotification(callback, true); |
| 322 state->increment_download_count(); | 338 state->increment_download_count(); |
| 323 break; | 339 break; |
| 324 | 340 |
| 325 case ALLOW_ONE_DOWNLOAD: | 341 case ALLOW_ONE_DOWNLOAD: |
| 326 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); | 342 state->set_download_status(PROMPT_BEFORE_DOWNLOAD); |
| 327 ScheduleNotification(callback, true); | 343 ScheduleNotification(callback, true); |
| 328 break; | 344 break; |
| 329 | 345 |
| 330 case DOWNLOADS_NOT_ALLOWED: | 346 case DOWNLOADS_NOT_ALLOWED: |
| 331 ScheduleNotification(callback, false); | 347 ScheduleNotification(callback, false); |
| 332 break; | 348 break; |
| 333 | 349 |
| 334 case PROMPT_BEFORE_DOWNLOAD: | 350 case PROMPT_BEFORE_DOWNLOAD: |
| 335 state->PromptUserForDownload(effective_wrapper->web_contents(), callback); | 351 state->PromptUserForDownload(effective_contents, callback); |
| 336 state->increment_download_count(); | 352 state->increment_download_count(); |
| 337 break; | 353 break; |
| 338 | 354 |
| 339 default: | 355 default: |
| 340 NOTREACHED(); | 356 NOTREACHED(); |
| 341 } | 357 } |
| 342 } | 358 } |
| 343 | 359 |
| 344 void DownloadRequestLimiter::ScheduleNotification(const Callback& callback, | 360 void DownloadRequestLimiter::ScheduleNotification(const Callback& callback, |
| 345 bool allow) { | 361 bool allow) { |
| 346 BrowserThread::PostTask( | 362 BrowserThread::PostTask( |
| 347 BrowserThread::IO, FROM_HERE, base::Bind(callback, allow)); | 363 BrowserThread::IO, FROM_HERE, base::Bind(callback, allow)); |
| 348 } | 364 } |
| 349 | 365 |
| 350 void DownloadRequestLimiter::Remove(TabDownloadState* state) { | 366 void DownloadRequestLimiter::Remove(TabDownloadState* state) { |
| 351 DCHECK(ContainsKey(state_map_, state->controller())); | 367 DCHECK(ContainsKey(state_map_, state->web_contents())); |
| 352 state_map_.erase(state->controller()); | 368 state_map_.erase(state->web_contents()); |
| 353 delete state; | 369 delete state; |
| 354 } | 370 } |
| 355 | 371 |
| 356 // static | 372 // static |
| 357 DownloadRequestLimiter::TestingDelegate* DownloadRequestLimiter::delegate_ = | 373 DownloadRequestLimiter::TestingDelegate* DownloadRequestLimiter::delegate_ = |
| 358 NULL; | 374 NULL; |
| OLD | NEW |