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 #include "chrome/browser/download/download_request_limiter.h"
8 #include "base/command_line.h"
9 #include "base/run_loop.h"
10 #include "chrome/browser/download/download_permission_request.h"
11 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "components/content_settings/core/browser/host_content_settings_map.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/navigation_details.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/frame_navigate_params.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 #if defined(OS_ANDROID)
23 #include "chrome/browser/download/download_request_infobar_delegate.h"
24 #include "chrome/browser/infobars/infobar_service.h"
27 using content::WebContents
;
29 class DownloadRequestLimiterTest
;
31 class FakePermissionBubbleView
: public PermissionBubbleView
{
33 class Factory
: public base::RefCounted
<FakePermissionBubbleView::Factory
> {
35 explicit Factory(DownloadRequestLimiterTest
* test
) : test_(test
) {}
37 scoped_ptr
<PermissionBubbleView
> Create(Browser
* browser
) {
38 return make_scoped_ptr(new FakePermissionBubbleView(test_
));
42 friend class base::RefCounted
<FakePermissionBubbleView::Factory
>;
45 DownloadRequestLimiterTest
* test_
;
48 explicit FakePermissionBubbleView(DownloadRequestLimiterTest
*test
)
49 : test_(test
), delegate_(NULL
) {}
51 ~FakePermissionBubbleView() override
{
59 // PermissionBubbleView:
60 void SetDelegate(Delegate
* delegate
) override
{ delegate_
= delegate
; }
62 void Show(const std::vector
<PermissionBubbleRequest
*>& requests
,
63 const std::vector
<bool>& accept_state
) override
;
65 bool CanAcceptRequestUpdate() override
{ return false; }
67 void Hide() override
{}
68 bool IsVisible() override
{ return false; }
69 void UpdateAnchorPosition() override
{};
70 gfx::NativeWindow
GetNativeWindow() override
{ return nullptr; }
73 DownloadRequestLimiterTest
* test_
;
77 class DownloadRequestLimiterTest
: public ChromeRenderViewHostTestHarness
{
85 void SetUp() override
{
86 ChromeRenderViewHostTestHarness::SetUp();
87 profile_
.reset(new TestingProfile());
89 if (PermissionBubbleManager::Enabled()) {
90 PermissionBubbleManager::CreateForWebContents(web_contents());
91 scoped_refptr
<FakePermissionBubbleView::Factory
> factory
=
92 new FakePermissionBubbleView::Factory(this);
93 PermissionBubbleManager::FromWebContents(web_contents())->view_factory_
=
94 base::Bind(&FakePermissionBubbleView::Factory::Create
, factory
);
95 PermissionBubbleManager::FromWebContents(web_contents())
96 ->DisplayPendingRequests();
99 testing_action_
= ACCEPT
;
100 ask_allow_count_
= cancel_count_
= continue_count_
= 0;
101 download_request_limiter_
= new DownloadRequestLimiter();
103 #if defined(OS_ANDROID)
104 InfoBarService::CreateForWebContents(web_contents());
105 fake_create_callback_
= base::Bind(
106 &DownloadRequestLimiterTest::FakeCreate
, base::Unretained(this));
107 DownloadRequestInfoBarDelegate::SetCallbackForTesting(
108 &fake_create_callback_
);
111 content_settings_
= new HostContentSettingsMap(profile_
->GetPrefs(), false);
112 DownloadRequestLimiter::SetContentSettingsForTesting(
113 content_settings_
.get());
117 return testing_action_
;
124 void TearDown() override
{
125 content_settings_
->ShutdownOnUIThread();
126 content_settings_
= NULL
;
127 #if defined(OS_ANDROID)
130 ChromeRenderViewHostTestHarness::TearDown();
133 #if defined(OS_ANDROID)
135 InfoBarService
* infobar_service
,
136 base::WeakPtr
<DownloadRequestLimiter::TabDownloadState
> host
) {
138 switch (testing_action_
) {
150 virtual void UnsetDelegate() {
151 DownloadRequestInfoBarDelegate::SetCallbackForTesting(NULL
);
156 CanDownloadFor(web_contents());
159 void CanDownloadFor(WebContents
* web_contents
) {
160 download_request_limiter_
->CanDownloadImpl(
162 "GET", // request method
163 base::Bind(&DownloadRequestLimiterTest::ContinueDownload
,
164 base::Unretained(this)));
165 base::RunLoop().RunUntilIdle();
168 void OnUserGesture() {
169 OnUserGestureFor(web_contents());
172 void OnUserGestureFor(WebContents
* web_contents
) {
173 DownloadRequestLimiter::TabDownloadState
* state
=
174 download_request_limiter_
->GetDownloadState(web_contents
, NULL
, false);
176 state
->DidGetUserGesture();
179 void ExpectAndResetCounts(
180 int expect_continues
,
184 EXPECT_EQ(expect_continues
, continue_count_
) << "line " << line
;
185 EXPECT_EQ(expect_cancels
, cancel_count_
) << "line " << line
;
186 EXPECT_EQ(expect_asks
, ask_allow_count_
) << "line " << line
;
187 continue_count_
= cancel_count_
= ask_allow_count_
= 0;
191 void ContinueDownload(bool allow
) {
199 void SetHostContentSetting(WebContents
* contents
, ContentSetting setting
) {
200 content_settings_
->SetContentSetting(
201 ContentSettingsPattern::FromURL(contents
->GetURL()),
202 ContentSettingsPattern::Wildcard(),
203 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
,
208 void BubbleManagerDocumentLoadCompleted() {
209 #if !defined(OS_ANDROID)
210 PermissionBubbleManager::FromWebContents(web_contents())->
211 DocumentOnLoadCompletedInMainFrame();
215 scoped_refptr
<DownloadRequestLimiter
> download_request_limiter_
;
217 // The action that FakeCreate() should take.
218 TestingAction testing_action_
;
220 // Number of times ContinueDownload was invoked.
223 // Number of times CancelDownload was invoked.
226 // Number of times ShouldAllowDownload was invoked.
227 int ask_allow_count_
;
229 scoped_refptr
<HostContentSettingsMap
> content_settings_
;
232 #if defined(OS_ANDROID)
233 DownloadRequestInfoBarDelegate::FakeCreateCallback fake_create_callback_
;
236 scoped_ptr
<TestingProfile
> profile_
;
239 void FakePermissionBubbleView::Show(
240 const std::vector
<PermissionBubbleRequest
*>& requests
,
241 const std::vector
<bool>& accept_state
) {
243 int action
= test_
->GetAction();
244 if (action
== DownloadRequestLimiterTest::ACCEPT
) {
246 } else if (action
== DownloadRequestLimiterTest::CANCEL
) {
248 } else if (action
== DownloadRequestLimiterTest::WAIT
) {
251 delegate_
->Closing();
255 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_Allow
) {
256 BubbleManagerDocumentLoadCompleted();
258 // All tabs should initially start at ALLOW_ONE_DOWNLOAD.
259 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
260 download_request_limiter_
->GetDownloadStatus(web_contents()));
262 // Ask if the tab can do a download. This moves to PROMPT_BEFORE_DOWNLOAD.
264 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
265 download_request_limiter_
->GetDownloadStatus(web_contents()));
266 // We should have been told we can download.
267 ExpectAndResetCounts(1, 0, 0, __LINE__
);
269 // Ask again. This triggers asking the delegate for allow/disallow.
270 testing_action_
= ACCEPT
;
272 // This should ask us if the download is allowed.
273 // We should have been told we can download.
274 ExpectAndResetCounts(1, 0, 1, __LINE__
);
275 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
276 download_request_limiter_
->GetDownloadStatus(web_contents()));
278 // Ask again and make sure continue is invoked.
280 // The state is at allow_all, which means the delegate shouldn't be asked.
281 // We should have been told we can download.
282 ExpectAndResetCounts(1, 0, 0, __LINE__
);
283 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
284 download_request_limiter_
->GetDownloadStatus(web_contents()));
287 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_ResetOnNavigation
) {
288 NavigateAndCommit(GURL("http://foo.com/bar"));
289 BubbleManagerDocumentLoadCompleted();
291 // Do two downloads, allowing the second so that we end up with allow all.
293 ExpectAndResetCounts(1, 0, 0, __LINE__
);
294 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
295 download_request_limiter_
->GetDownloadStatus(web_contents()));
297 testing_action_
= ACCEPT
;
299 ExpectAndResetCounts(1, 0, 1, __LINE__
);
300 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
301 download_request_limiter_
->GetDownloadStatus(web_contents()));
303 // Navigate to a new URL with the same host, which shouldn't reset the allow
305 NavigateAndCommit(GURL("http://foo.com/bar2"));
306 BubbleManagerDocumentLoadCompleted();
308 ExpectAndResetCounts(1, 0, 0, __LINE__
);
309 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
310 download_request_limiter_
->GetDownloadStatus(web_contents()));
312 // Do a user gesture, because we're at allow all, this shouldn't change the
315 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
316 download_request_limiter_
->GetDownloadStatus(web_contents()));
318 // Navigate to a completely different host, which should reset the state.
319 NavigateAndCommit(GURL("http://fooey.com"));
320 BubbleManagerDocumentLoadCompleted();
321 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
322 download_request_limiter_
->GetDownloadStatus(web_contents()));
324 // Do two downloads, allowing the second so that we end up with allow all.
326 ExpectAndResetCounts(1, 0, 0, __LINE__
);
327 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
328 download_request_limiter_
->GetDownloadStatus(web_contents()));
330 testing_action_
= CANCEL
;
332 ExpectAndResetCounts(0, 1, 1, __LINE__
);
333 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
334 download_request_limiter_
->GetDownloadStatus(web_contents()));
336 // Navigate to a new URL with the same host, which shouldn't reset the allow
338 NavigateAndCommit(GURL("http://fooey.com/bar2"));
339 BubbleManagerDocumentLoadCompleted();
341 ExpectAndResetCounts(0, 1, 0, __LINE__
);
342 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
343 download_request_limiter_
->GetDownloadStatus(web_contents()));
346 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_ResetOnUserGesture
) {
347 NavigateAndCommit(GURL("http://foo.com/bar"));
348 BubbleManagerDocumentLoadCompleted();
350 // Do one download, which should change to prompt before download.
352 ExpectAndResetCounts(1, 0, 0, __LINE__
);
353 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
354 download_request_limiter_
->GetDownloadStatus(web_contents()));
356 // Do a user gesture, which should reset back to allow one.
358 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
359 download_request_limiter_
->GetDownloadStatus(web_contents()));
361 // Ask twice, which triggers calling the delegate. Don't allow the download
362 // so that we end up with not allowed.
364 ExpectAndResetCounts(1, 0, 0, __LINE__
);
365 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
366 download_request_limiter_
->GetDownloadStatus(web_contents()));
368 testing_action_
= CANCEL
;
370 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
371 download_request_limiter_
->GetDownloadStatus(web_contents()));
372 ExpectAndResetCounts(0, 1, 1, __LINE__
);
374 // A user gesture now should NOT change the state.
376 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
377 download_request_limiter_
->GetDownloadStatus(web_contents()));
378 // And make sure we really can't download.
380 ExpectAndResetCounts(0, 1, 0, __LINE__
);
381 // And the state shouldn't have changed.
382 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
383 download_request_limiter_
->GetDownloadStatus(web_contents()));
386 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_ResetOnReload
) {
387 NavigateAndCommit(GURL("http://foo.com/bar"));
388 BubbleManagerDocumentLoadCompleted();
389 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
390 download_request_limiter_
->GetDownloadStatus(web_contents()));
392 // If the user refreshes the page without responding to the infobar, pretend
393 // like the refresh is the initial load: they get 1 free download (probably
394 // the same as the actual initial load), then an infobar.
395 testing_action_
= WAIT
;
398 ExpectAndResetCounts(1, 0, 0, __LINE__
);
399 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
400 download_request_limiter_
->GetDownloadStatus(web_contents()));
403 ExpectAndResetCounts(0, 0, 1, __LINE__
);
404 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
405 download_request_limiter_
->GetDownloadStatus(web_contents()));
408 BubbleManagerDocumentLoadCompleted();
409 base::RunLoop().RunUntilIdle();
410 ExpectAndResetCounts(0, 1, 0, __LINE__
);
411 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
412 download_request_limiter_
->GetDownloadStatus(web_contents()));
415 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
416 download_request_limiter_
->GetDownloadStatus(web_contents()));
417 ExpectAndResetCounts(1, 0, 0, __LINE__
);
419 testing_action_
= CANCEL
;
421 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
422 download_request_limiter_
->GetDownloadStatus(web_contents()));
423 ExpectAndResetCounts(0, 1, 1, __LINE__
);
426 BubbleManagerDocumentLoadCompleted();
427 base::RunLoop().RunUntilIdle();
428 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
429 download_request_limiter_
->GetDownloadStatus(web_contents()));
431 ExpectAndResetCounts(0, 1, 0, __LINE__
);
432 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
433 download_request_limiter_
->GetDownloadStatus(web_contents()));
436 #if defined(OS_ANDROID)
437 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_RawWebContents
) {
438 scoped_ptr
<WebContents
> web_contents(CreateTestWebContents());
440 // DownloadRequestLimiter won't try to make a permission bubble if there's
441 // no permission bubble manager, so don't put one on the test WebContents.
443 // DownloadRequestLimiter won't try to make an infobar if it doesn't have an
444 // InfoBarService, and we want to test that it will Cancel() instead of
445 // prompting when it doesn't have a InfoBarService, so unset the delegate.
447 ExpectAndResetCounts(0, 0, 0, __LINE__
);
448 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
449 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
450 // You get one freebie.
451 CanDownloadFor(web_contents
.get());
452 ExpectAndResetCounts(1, 0, 0, __LINE__
);
453 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
454 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
455 OnUserGestureFor(web_contents
.get());
456 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
457 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
458 CanDownloadFor(web_contents
.get());
459 ExpectAndResetCounts(1, 0, 0, __LINE__
);
460 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
461 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
462 CanDownloadFor(web_contents
.get());
463 ExpectAndResetCounts(0, 1, 0, __LINE__
);
464 EXPECT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
465 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
466 OnUserGestureFor(web_contents
.get());
467 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
468 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
469 CanDownloadFor(web_contents
.get());
470 ExpectAndResetCounts(1, 0, 0, __LINE__
);
471 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
472 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
476 TEST_F(DownloadRequestLimiterTest
,
477 DownloadRequestLimiter_SetHostContentSetting
) {
478 NavigateAndCommit(GURL("http://foo.com/bar"));
479 BubbleManagerDocumentLoadCompleted();
480 SetHostContentSetting(web_contents(), CONTENT_SETTING_ALLOW
);
483 ExpectAndResetCounts(1, 0, 0, __LINE__
);
484 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
485 download_request_limiter_
->GetDownloadStatus(web_contents()));
488 ExpectAndResetCounts(1, 0, 0, __LINE__
);
489 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
490 download_request_limiter_
->GetDownloadStatus(web_contents()));
492 SetHostContentSetting(web_contents(), CONTENT_SETTING_BLOCK
);
495 ExpectAndResetCounts(0, 1, 0, __LINE__
);
496 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
497 download_request_limiter_
->GetDownloadStatus(web_contents()));
500 ExpectAndResetCounts(0, 1, 0, __LINE__
);
501 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
502 download_request_limiter_
->GetDownloadStatus(web_contents()));