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() {
196 #if !defined(OS_ANDROID)
197 PermissionBubbleManager::FromWebContents(web_contents())->
198 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 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_Allow
) {
240 BubbleManagerDocumentLoadCompleted();
242 // All tabs should initially start at ALLOW_ONE_DOWNLOAD.
243 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
244 download_request_limiter_
->GetDownloadStatus(web_contents()));
246 // Ask if the tab can do a download. This moves to PROMPT_BEFORE_DOWNLOAD.
248 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
249 download_request_limiter_
->GetDownloadStatus(web_contents()));
250 // We should have been told we can download.
251 ExpectAndResetCounts(1, 0, 0, __LINE__
);
253 // Ask again. This triggers asking the delegate for allow/disallow.
254 testing_action_
= ACCEPT
;
256 // This should ask us if the download is allowed.
257 // We should have been told we can download.
258 ExpectAndResetCounts(1, 0, 1, __LINE__
);
259 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
260 download_request_limiter_
->GetDownloadStatus(web_contents()));
262 // Ask again and make sure continue is invoked.
264 // The state is at allow_all, which means the delegate shouldn't be asked.
265 // We should have been told we can download.
266 ExpectAndResetCounts(1, 0, 0, __LINE__
);
267 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
268 download_request_limiter_
->GetDownloadStatus(web_contents()));
271 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_ResetOnNavigation
) {
272 NavigateAndCommit(GURL("http://foo.com/bar"));
273 BubbleManagerDocumentLoadCompleted();
275 // Do two downloads, allowing the second so that we end up with allow all.
277 ExpectAndResetCounts(1, 0, 0, __LINE__
);
278 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
279 download_request_limiter_
->GetDownloadStatus(web_contents()));
281 testing_action_
= ACCEPT
;
283 ExpectAndResetCounts(1, 0, 1, __LINE__
);
284 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
285 download_request_limiter_
->GetDownloadStatus(web_contents()));
287 // Navigate to a new URL with the same host, which shouldn't reset the allow
289 NavigateAndCommit(GURL("http://foo.com/bar2"));
290 BubbleManagerDocumentLoadCompleted();
292 ExpectAndResetCounts(1, 0, 0, __LINE__
);
293 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
294 download_request_limiter_
->GetDownloadStatus(web_contents()));
296 // Do a user gesture, because we're at allow all, this shouldn't change the
299 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
300 download_request_limiter_
->GetDownloadStatus(web_contents()));
302 // Navigate to a completely different host, which should reset the state.
303 NavigateAndCommit(GURL("http://fooey.com"));
304 BubbleManagerDocumentLoadCompleted();
305 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
306 download_request_limiter_
->GetDownloadStatus(web_contents()));
308 // Do two downloads, allowing the second so that we end up with allow all.
310 ExpectAndResetCounts(1, 0, 0, __LINE__
);
311 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
312 download_request_limiter_
->GetDownloadStatus(web_contents()));
314 testing_action_
= CANCEL
;
316 ExpectAndResetCounts(0, 1, 1, __LINE__
);
317 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
318 download_request_limiter_
->GetDownloadStatus(web_contents()));
320 // Navigate to a new URL with the same host, which shouldn't reset the allow
322 NavigateAndCommit(GURL("http://fooey.com/bar2"));
323 BubbleManagerDocumentLoadCompleted();
325 ExpectAndResetCounts(0, 1, 0, __LINE__
);
326 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
327 download_request_limiter_
->GetDownloadStatus(web_contents()));
330 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_ResetOnUserGesture
) {
331 NavigateAndCommit(GURL("http://foo.com/bar"));
332 BubbleManagerDocumentLoadCompleted();
334 // Do one download, which should change to prompt before download.
336 ExpectAndResetCounts(1, 0, 0, __LINE__
);
337 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
338 download_request_limiter_
->GetDownloadStatus(web_contents()));
340 // Do a user gesture, which should reset back to allow one.
342 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
343 download_request_limiter_
->GetDownloadStatus(web_contents()));
345 // Ask twice, which triggers calling the delegate. Don't allow the download
346 // so that we end up with not allowed.
348 ExpectAndResetCounts(1, 0, 0, __LINE__
);
349 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
350 download_request_limiter_
->GetDownloadStatus(web_contents()));
352 testing_action_
= CANCEL
;
354 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
355 download_request_limiter_
->GetDownloadStatus(web_contents()));
356 ExpectAndResetCounts(0, 1, 1, __LINE__
);
358 // A user gesture now should NOT change the state.
360 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
361 download_request_limiter_
->GetDownloadStatus(web_contents()));
362 // And make sure we really can't download.
364 ExpectAndResetCounts(0, 1, 0, __LINE__
);
365 // And the state shouldn't have changed.
366 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
367 download_request_limiter_
->GetDownloadStatus(web_contents()));
370 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_ResetOnReload
) {
371 NavigateAndCommit(GURL("http://foo.com/bar"));
372 BubbleManagerDocumentLoadCompleted();
373 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
374 download_request_limiter_
->GetDownloadStatus(web_contents()));
376 // If the user refreshes the page without responding to the infobar, pretend
377 // like the refresh is the initial load: they get 1 free download (probably
378 // the same as the actual initial load), then an infobar.
379 testing_action_
= WAIT
;
382 ExpectAndResetCounts(1, 0, 0, __LINE__
);
383 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
384 download_request_limiter_
->GetDownloadStatus(web_contents()));
387 ExpectAndResetCounts(0, 0, 1, __LINE__
);
388 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
389 download_request_limiter_
->GetDownloadStatus(web_contents()));
392 BubbleManagerDocumentLoadCompleted();
393 base::RunLoop().RunUntilIdle();
394 ExpectAndResetCounts(0, 1, 0, __LINE__
);
395 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
396 download_request_limiter_
->GetDownloadStatus(web_contents()));
399 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
400 download_request_limiter_
->GetDownloadStatus(web_contents()));
401 ExpectAndResetCounts(1, 0, 0, __LINE__
);
403 testing_action_
= CANCEL
;
405 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
406 download_request_limiter_
->GetDownloadStatus(web_contents()));
407 ExpectAndResetCounts(0, 1, 1, __LINE__
);
410 BubbleManagerDocumentLoadCompleted();
411 base::RunLoop().RunUntilIdle();
412 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
413 download_request_limiter_
->GetDownloadStatus(web_contents()));
415 ExpectAndResetCounts(0, 1, 0, __LINE__
);
416 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
417 download_request_limiter_
->GetDownloadStatus(web_contents()));
420 TEST_F(DownloadRequestLimiterTest
, DownloadRequestLimiter_RawWebContents
) {
421 scoped_ptr
<WebContents
> web_contents(CreateTestWebContents());
423 // DownloadRequestLimiter won't try to make a permission bubble if there's
424 // no permission bubble manager, so don't put one on the test WebContents.
426 // DownloadRequestLimiter won't try to make an infobar if it doesn't have an
427 // InfoBarService, and we want to test that it will Cancel() instead of
428 // prompting when it doesn't have a InfoBarService, so unset the delegate.
430 ExpectAndResetCounts(0, 0, 0, __LINE__
);
431 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
432 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
433 // You get one freebie.
434 CanDownloadFor(web_contents
.get());
435 ExpectAndResetCounts(1, 0, 0, __LINE__
);
436 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
437 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
438 OnUserGestureFor(web_contents
.get());
439 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
440 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
441 CanDownloadFor(web_contents
.get());
442 ExpectAndResetCounts(1, 0, 0, __LINE__
);
443 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
444 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
445 CanDownloadFor(web_contents
.get());
446 ExpectAndResetCounts(0, 1, 0, __LINE__
);
447 EXPECT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
448 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
449 OnUserGestureFor(web_contents
.get());
450 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
451 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
452 CanDownloadFor(web_contents
.get());
453 ExpectAndResetCounts(1, 0, 0, __LINE__
);
454 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
455 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
458 TEST_F(DownloadRequestLimiterTest
,
459 DownloadRequestLimiter_SetHostContentSetting
) {
460 NavigateAndCommit(GURL("http://foo.com/bar"));
461 BubbleManagerDocumentLoadCompleted();
462 SetHostContentSetting(web_contents(), CONTENT_SETTING_ALLOW
);
465 ExpectAndResetCounts(1, 0, 0, __LINE__
);
466 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
467 download_request_limiter_
->GetDownloadStatus(web_contents()));
470 ExpectAndResetCounts(1, 0, 0, __LINE__
);
471 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
472 download_request_limiter_
->GetDownloadStatus(web_contents()));
474 SetHostContentSetting(web_contents(), CONTENT_SETTING_BLOCK
);
477 ExpectAndResetCounts(0, 1, 0, __LINE__
);
478 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
479 download_request_limiter_
->GetDownloadStatus(web_contents()));
482 ExpectAndResetCounts(0, 1, 0, __LINE__
);
483 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
484 download_request_limiter_
->GetDownloadStatus(web_contents()));