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/download/download_request_infobar_delegate.h"
12 #include "chrome/browser/infobars/infobar_service.h"
13 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
16 #include "chrome/test/base/testing_profile.h"
17 #include "components/content_settings/core/browser/host_content_settings_map.h"
18 #include "content/public/browser/navigation_controller.h"
19 #include "content/public/browser/navigation_details.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/frame_navigate_params.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using content::WebContents
;
26 class DownloadRequestLimiterTest
;
28 class FakePermissionBubbleView
: public PermissionBubbleView
{
30 class Factory
: public base::RefCounted
<FakePermissionBubbleView::Factory
> {
32 explicit Factory(DownloadRequestLimiterTest
* test
) : test_(test
) {}
34 scoped_ptr
<PermissionBubbleView
> Create(Browser
* browser
) {
35 return make_scoped_ptr(new FakePermissionBubbleView(test_
));
39 friend class base::RefCounted
<FakePermissionBubbleView::Factory
>;
42 DownloadRequestLimiterTest
* test_
;
45 explicit FakePermissionBubbleView(DownloadRequestLimiterTest
*test
)
46 : test_(test
), delegate_(NULL
) {}
48 ~FakePermissionBubbleView() override
{
56 // PermissionBubbleView:
57 void SetDelegate(Delegate
* delegate
) override
{ delegate_
= delegate
; }
59 void Show(const std::vector
<PermissionBubbleRequest
*>& requests
,
60 const std::vector
<bool>& accept_state
) override
;
62 bool CanAcceptRequestUpdate() override
{ return false; }
64 void Hide() override
{}
65 bool IsVisible() override
{ return false; }
66 void UpdateAnchorPosition() override
{};
67 gfx::NativeWindow
GetNativeWindow() override
{ return nullptr; }
70 DownloadRequestLimiterTest
* test_
;
74 class DownloadRequestLimiterTest
: public ChromeRenderViewHostTestHarness
{
82 void SetUp() override
{
83 ChromeRenderViewHostTestHarness::SetUp();
84 profile_
.reset(new TestingProfile());
85 InfoBarService::CreateForWebContents(web_contents());
87 PermissionBubbleManager::CreateForWebContents(web_contents());
88 scoped_refptr
<FakePermissionBubbleView::Factory
> factory
=
89 new FakePermissionBubbleView::Factory(this);
90 PermissionBubbleManager::FromWebContents(web_contents())->view_factory_
=
91 base::Bind(&FakePermissionBubbleView::Factory::Create
, factory
);
92 PermissionBubbleManager::FromWebContents(web_contents())
93 ->DisplayPendingRequests(nullptr);
95 testing_action_
= ACCEPT
;
96 ask_allow_count_
= cancel_count_
= continue_count_
= 0;
97 download_request_limiter_
= new DownloadRequestLimiter();
98 fake_create_callback_
= base::Bind(
99 &DownloadRequestLimiterTest::FakeCreate
, base::Unretained(this));
100 DownloadRequestInfoBarDelegate::SetCallbackForTesting(
101 &fake_create_callback_
);
102 content_settings_
= new HostContentSettingsMap(profile_
->GetPrefs(), false);
103 DownloadRequestLimiter::SetContentSettingsForTesting(
104 content_settings_
.get());
108 return testing_action_
;
116 InfoBarService
* infobar_service
,
117 base::WeakPtr
<DownloadRequestLimiter::TabDownloadState
> host
) {
119 switch (testing_action_
) {
131 void TearDown() override
{
132 content_settings_
->ShutdownOnUIThread();
133 content_settings_
= NULL
;
135 ChromeRenderViewHostTestHarness::TearDown();
138 virtual void UnsetDelegate() {
139 DownloadRequestInfoBarDelegate::SetCallbackForTesting(NULL
);
143 CanDownloadFor(web_contents());
146 void CanDownloadFor(WebContents
* web_contents
) {
147 download_request_limiter_
->CanDownloadImpl(
149 "GET", // request method
150 base::Bind(&DownloadRequestLimiterTest::ContinueDownload
,
151 base::Unretained(this)));
152 base::RunLoop().RunUntilIdle();
155 void OnUserGesture() {
156 OnUserGestureFor(web_contents());
159 void OnUserGestureFor(WebContents
* web_contents
) {
160 DownloadRequestLimiter::TabDownloadState
* state
=
161 download_request_limiter_
->GetDownloadState(web_contents
, NULL
, false);
163 state
->DidGetUserGesture();
166 void ExpectAndResetCounts(
167 int expect_continues
,
171 EXPECT_EQ(expect_continues
, continue_count_
) << "line " << line
;
172 EXPECT_EQ(expect_cancels
, cancel_count_
) << "line " << line
;
173 EXPECT_EQ(expect_asks
, ask_allow_count_
) << "line " << line
;
174 continue_count_
= cancel_count_
= ask_allow_count_
= 0;
178 void ContinueDownload(bool allow
) {
186 void SetHostContentSetting(WebContents
* contents
, ContentSetting setting
) {
187 content_settings_
->SetContentSetting(
188 ContentSettingsPattern::FromURL(contents
->GetURL()),
189 ContentSettingsPattern::Wildcard(),
190 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
,
195 void BubbleManagerDocumentLoadCompleted(bool bubbles_enabled
) {
196 if (!bubbles_enabled
)
198 PermissionBubbleManager::FromWebContents(web_contents())->
199 DocumentOnLoadCompletedInMainFrame();
202 scoped_refptr
<DownloadRequestLimiter
> download_request_limiter_
;
204 // The action that FakeCreate() should take.
205 TestingAction testing_action_
;
207 // Number of times ContinueDownload was invoked.
210 // Number of times CancelDownload was invoked.
213 // Number of times ShouldAllowDownload was invoked.
214 int ask_allow_count_
;
216 scoped_refptr
<HostContentSettingsMap
> content_settings_
;
219 DownloadRequestInfoBarDelegate::FakeCreateCallback fake_create_callback_
;
220 scoped_ptr
<TestingProfile
> profile_
;
223 void FakePermissionBubbleView::Show(
224 const std::vector
<PermissionBubbleRequest
*>& requests
,
225 const std::vector
<bool>& accept_state
) {
227 int action
= test_
->GetAction();
228 if (action
== DownloadRequestLimiterTest::ACCEPT
) {
230 } else if (action
== DownloadRequestLimiterTest::CANCEL
) {
232 } else if (action
== DownloadRequestLimiterTest::WAIT
) {
235 delegate_
->Closing();
239 class DownloadRequestLimiterParamTests
240 : public DownloadRequestLimiterTest
,
241 public ::testing::WithParamInterface
<bool> {
243 DownloadRequestLimiterParamTests() {}
244 ~DownloadRequestLimiterParamTests() override
{}
246 void SetUp() override
{
247 DownloadRequestLimiterTest::SetUp();
248 #if !defined(OS_ANDROID)
250 base::CommandLine::ForCurrentProcess()->AppendSwitch(
251 switches::kEnablePermissionsBubbles
);
252 EXPECT_TRUE(PermissionBubbleManager::Enabled());
254 base::CommandLine::ForCurrentProcess()->AppendSwitch(
255 switches::kDisablePermissionsBubbles
);
260 void BubbleManagerDocumentLoadCompleted() {
261 #if defined(OS_ANDROID)
262 DownloadRequestLimiterTest::BubbleManagerDocumentLoadCompleted(false);
264 DownloadRequestLimiterTest::BubbleManagerDocumentLoadCompleted(GetParam());
268 DISALLOW_COPY_AND_ASSIGN(DownloadRequestLimiterParamTests
);
271 TEST_P(DownloadRequestLimiterParamTests
,
272 DownloadRequestLimiter_Allow
) {
273 BubbleManagerDocumentLoadCompleted();
275 // All tabs should initially start at ALLOW_ONE_DOWNLOAD.
276 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
277 download_request_limiter_
->GetDownloadStatus(web_contents()));
279 // Ask if the tab can do a download. This moves to PROMPT_BEFORE_DOWNLOAD.
281 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
282 download_request_limiter_
->GetDownloadStatus(web_contents()));
283 // We should have been told we can download.
284 ExpectAndResetCounts(1, 0, 0, __LINE__
);
286 // Ask again. This triggers asking the delegate for allow/disallow.
287 testing_action_
= ACCEPT
;
289 // This should ask us if the download is allowed.
290 // We should have been told we can download.
291 ExpectAndResetCounts(1, 0, 1, __LINE__
);
292 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
293 download_request_limiter_
->GetDownloadStatus(web_contents()));
295 // Ask again and make sure continue is invoked.
297 // The state is at allow_all, which means the delegate shouldn't be asked.
298 // We should have been told we can download.
299 ExpectAndResetCounts(1, 0, 0, __LINE__
);
300 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
301 download_request_limiter_
->GetDownloadStatus(web_contents()));
304 TEST_P(DownloadRequestLimiterParamTests
,
305 DownloadRequestLimiter_ResetOnNavigation
) {
306 NavigateAndCommit(GURL("http://foo.com/bar"));
307 BubbleManagerDocumentLoadCompleted();
309 // Do two downloads, allowing the second so that we end up with allow all.
311 ExpectAndResetCounts(1, 0, 0, __LINE__
);
312 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
313 download_request_limiter_
->GetDownloadStatus(web_contents()));
315 testing_action_
= ACCEPT
;
317 ExpectAndResetCounts(1, 0, 1, __LINE__
);
318 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
319 download_request_limiter_
->GetDownloadStatus(web_contents()));
321 // Navigate to a new URL with the same host, which shouldn't reset the allow
323 NavigateAndCommit(GURL("http://foo.com/bar2"));
324 BubbleManagerDocumentLoadCompleted();
326 ExpectAndResetCounts(1, 0, 0, __LINE__
);
327 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
328 download_request_limiter_
->GetDownloadStatus(web_contents()));
330 // Do a user gesture, because we're at allow all, this shouldn't change the
333 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
334 download_request_limiter_
->GetDownloadStatus(web_contents()));
336 // Navigate to a completely different host, which should reset the state.
337 NavigateAndCommit(GURL("http://fooey.com"));
338 BubbleManagerDocumentLoadCompleted();
339 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
340 download_request_limiter_
->GetDownloadStatus(web_contents()));
342 // Do two downloads, allowing the second so that we end up with allow all.
344 ExpectAndResetCounts(1, 0, 0, __LINE__
);
345 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
346 download_request_limiter_
->GetDownloadStatus(web_contents()));
348 testing_action_
= CANCEL
;
350 ExpectAndResetCounts(0, 1, 1, __LINE__
);
351 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
352 download_request_limiter_
->GetDownloadStatus(web_contents()));
354 // Navigate to a new URL with the same host, which shouldn't reset the allow
356 NavigateAndCommit(GURL("http://fooey.com/bar2"));
357 BubbleManagerDocumentLoadCompleted();
359 ExpectAndResetCounts(0, 1, 0, __LINE__
);
360 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
361 download_request_limiter_
->GetDownloadStatus(web_contents()));
364 TEST_P(DownloadRequestLimiterParamTests
,
365 DownloadRequestLimiter_ResetOnUserGesture
) {
366 NavigateAndCommit(GURL("http://foo.com/bar"));
367 BubbleManagerDocumentLoadCompleted();
369 // Do one download, which should change to prompt before download.
371 ExpectAndResetCounts(1, 0, 0, __LINE__
);
372 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
373 download_request_limiter_
->GetDownloadStatus(web_contents()));
375 // Do a user gesture, which should reset back to allow one.
377 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
378 download_request_limiter_
->GetDownloadStatus(web_contents()));
380 // Ask twice, which triggers calling the delegate. Don't allow the download
381 // so that we end up with not allowed.
383 ExpectAndResetCounts(1, 0, 0, __LINE__
);
384 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
385 download_request_limiter_
->GetDownloadStatus(web_contents()));
387 testing_action_
= CANCEL
;
389 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
390 download_request_limiter_
->GetDownloadStatus(web_contents()));
391 ExpectAndResetCounts(0, 1, 1, __LINE__
);
393 // A user gesture now should NOT change the state.
395 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
396 download_request_limiter_
->GetDownloadStatus(web_contents()));
397 // And make sure we really can't download.
399 ExpectAndResetCounts(0, 1, 0, __LINE__
);
400 // And the state shouldn't have changed.
401 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
402 download_request_limiter_
->GetDownloadStatus(web_contents()));
405 TEST_P(DownloadRequestLimiterParamTests
,
406 DownloadRequestLimiter_ResetOnReload
) {
407 NavigateAndCommit(GURL("http://foo.com/bar"));
408 BubbleManagerDocumentLoadCompleted();
409 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
410 download_request_limiter_
->GetDownloadStatus(web_contents()));
412 // If the user refreshes the page without responding to the infobar, pretend
413 // like the refresh is the initial load: they get 1 free download (probably
414 // the same as the actual initial load), then an infobar.
415 testing_action_
= WAIT
;
418 ExpectAndResetCounts(1, 0, 0, __LINE__
);
419 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
420 download_request_limiter_
->GetDownloadStatus(web_contents()));
423 ExpectAndResetCounts(0, 0, 1, __LINE__
);
424 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
425 download_request_limiter_
->GetDownloadStatus(web_contents()));
428 BubbleManagerDocumentLoadCompleted();
429 base::RunLoop().RunUntilIdle();
430 ExpectAndResetCounts(0, 1, 0, __LINE__
);
431 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
432 download_request_limiter_
->GetDownloadStatus(web_contents()));
435 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
436 download_request_limiter_
->GetDownloadStatus(web_contents()));
437 ExpectAndResetCounts(1, 0, 0, __LINE__
);
439 testing_action_
= CANCEL
;
441 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
442 download_request_limiter_
->GetDownloadStatus(web_contents()));
443 ExpectAndResetCounts(0, 1, 1, __LINE__
);
446 BubbleManagerDocumentLoadCompleted();
447 base::RunLoop().RunUntilIdle();
448 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
449 download_request_limiter_
->GetDownloadStatus(web_contents()));
451 ExpectAndResetCounts(0, 1, 0, __LINE__
);
452 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
453 download_request_limiter_
->GetDownloadStatus(web_contents()));
456 TEST_P(DownloadRequestLimiterParamTests
,
457 DownloadRequestLimiter_RawWebContents
) {
458 scoped_ptr
<WebContents
> web_contents(CreateTestWebContents());
460 // DownloadRequestLimiter won't try to make a permission bubble if there's
461 // no permission bubble manager, so don't put one on the test WebContents.
463 // DownloadRequestLimiter won't try to make an infobar if it doesn't have an
464 // InfoBarService, and we want to test that it will Cancel() instead of
465 // prompting when it doesn't have a InfoBarService, so unset the delegate.
467 ExpectAndResetCounts(0, 0, 0, __LINE__
);
468 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
469 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
470 // You get one freebie.
471 CanDownloadFor(web_contents
.get());
472 ExpectAndResetCounts(1, 0, 0, __LINE__
);
473 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
474 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
475 OnUserGestureFor(web_contents
.get());
476 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
477 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
478 CanDownloadFor(web_contents
.get());
479 ExpectAndResetCounts(1, 0, 0, __LINE__
);
480 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
481 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
482 CanDownloadFor(web_contents
.get());
483 ExpectAndResetCounts(0, 1, 0, __LINE__
);
484 EXPECT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
485 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
486 OnUserGestureFor(web_contents
.get());
487 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
488 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
489 CanDownloadFor(web_contents
.get());
490 ExpectAndResetCounts(1, 0, 0, __LINE__
);
491 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
492 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
495 TEST_P(DownloadRequestLimiterParamTests
,
496 DownloadRequestLimiter_SetHostContentSetting
) {
497 NavigateAndCommit(GURL("http://foo.com/bar"));
498 BubbleManagerDocumentLoadCompleted();
499 SetHostContentSetting(web_contents(), CONTENT_SETTING_ALLOW
);
502 ExpectAndResetCounts(1, 0, 0, __LINE__
);
503 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
504 download_request_limiter_
->GetDownloadStatus(web_contents()));
507 ExpectAndResetCounts(1, 0, 0, __LINE__
);
508 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
509 download_request_limiter_
->GetDownloadStatus(web_contents()));
511 SetHostContentSetting(web_contents(), CONTENT_SETTING_BLOCK
);
514 ExpectAndResetCounts(0, 1, 0, __LINE__
);
515 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
516 download_request_limiter_
->GetDownloadStatus(web_contents()));
519 ExpectAndResetCounts(0, 1, 0, __LINE__
);
520 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
521 download_request_limiter_
->GetDownloadStatus(web_contents()));
524 INSTANTIATE_TEST_CASE_P(DownloadRequestLimiterTestsWithAndWithoutBubbles
,
525 DownloadRequestLimiterParamTests
,
526 ::testing::Values(false, true));