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/run_loop.h"
9 #include "chrome/browser/content_settings/host_content_settings_map.h"
10 #include "chrome/browser/download/download_request_infobar_delegate.h"
11 #include "chrome/browser/infobars/infobar_service.h"
12 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
13 #include "chrome/test/base/testing_profile.h"
14 #include "content/public/browser/navigation_controller.h"
15 #include "content/public/browser/web_contents.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using content::WebContents
;
20 class DownloadRequestLimiterTest
: public ChromeRenderViewHostTestHarness
{
28 virtual void SetUp() {
29 ChromeRenderViewHostTestHarness::SetUp();
30 InfoBarService::CreateForWebContents(web_contents());
31 testing_action_
= ACCEPT
;
32 ask_allow_count_
= cancel_count_
= continue_count_
= 0;
33 download_request_limiter_
= new DownloadRequestLimiter();
34 fake_create_callback_
= base::Bind(
35 &DownloadRequestLimiterTest::FakeCreate
, base::Unretained(this));
36 DownloadRequestInfoBarDelegate::SetCallbackForTesting(
37 &fake_create_callback_
);
38 content_settings_
= new HostContentSettingsMap(profile_
.GetPrefs(), false);
39 DownloadRequestLimiter::SetContentSettingsForTesting(
40 content_settings_
.get());
44 InfoBarService
* infobar_service
,
45 base::WeakPtr
<DownloadRequestLimiter::TabDownloadState
> host
) {
47 switch (testing_action_
) {
59 virtual void TearDown() {
60 content_settings_
->ShutdownOnUIThread();
61 content_settings_
= NULL
;
63 ChromeRenderViewHostTestHarness::TearDown();
66 virtual void UnsetDelegate() {
67 DownloadRequestInfoBarDelegate::SetCallbackForTesting(NULL
);
71 CanDownloadFor(web_contents());
74 void CanDownloadFor(WebContents
* web_contents
) {
75 download_request_limiter_
->CanDownloadImpl(
78 "GET", // request method
79 base::Bind(&DownloadRequestLimiterTest::ContinueDownload
,
80 base::Unretained(this)));
81 base::RunLoop().RunUntilIdle();
84 void OnUserGesture() {
85 OnUserGestureFor(web_contents());
88 void OnUserGestureFor(WebContents
* web_contents
) {
89 DownloadRequestLimiter::TabDownloadState
* state
=
90 download_request_limiter_
->GetDownloadState(web_contents
, NULL
, false);
92 state
->DidGetUserGesture();
95 void AboutToNavigateRenderView() {
96 DownloadRequestLimiter::TabDownloadState
* state
=
97 download_request_limiter_
->GetDownloadState(
98 web_contents(), NULL
, false);
99 state
->AboutToNavigateRenderView(NULL
);
102 void ExpectAndResetCounts(
103 int expect_continues
,
107 EXPECT_EQ(expect_continues
, continue_count_
) << "line " << line
;
108 EXPECT_EQ(expect_cancels
, cancel_count_
) << "line " << line
;
109 EXPECT_EQ(expect_asks
, ask_allow_count_
) << "line " << line
;
110 continue_count_
= cancel_count_
= ask_allow_count_
= 0;
114 void ContinueDownload(bool allow
) {
122 void SetHostContentSetting(WebContents
* contents
, ContentSetting setting
) {
123 content_settings_
->SetContentSetting(
124 ContentSettingsPattern::FromURL(contents
->GetURL()),
125 ContentSettingsPattern::Wildcard(),
126 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
,
131 scoped_refptr
<DownloadRequestLimiter
> download_request_limiter_
;
133 // The action that FakeCreate() should take.
134 TestingAction testing_action_
;
136 // Number of times ContinueDownload was invoked.
139 // Number of times CancelDownload was invoked.
142 // Number of times ShouldAllowDownload was invoked.
143 int ask_allow_count_
;
145 scoped_refptr
<HostContentSettingsMap
> content_settings_
;
148 DownloadRequestInfoBarDelegate::FakeCreateCallback fake_create_callback_
;
149 TestingProfile profile_
;
152 TEST_F(DownloadRequestLimiterTest
,
153 DownloadRequestLimiter_Allow
) {
154 // All tabs should initially start at ALLOW_ONE_DOWNLOAD.
155 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
156 download_request_limiter_
->GetDownloadStatus(web_contents()));
158 // Ask if the tab can do a download. This moves to PROMPT_BEFORE_DOWNLOAD.
160 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
161 download_request_limiter_
->GetDownloadStatus(web_contents()));
162 // We should have been told we can download.
163 ExpectAndResetCounts(1, 0, 0, __LINE__
);
165 // Ask again. This triggers asking the delegate for allow/disallow.
166 testing_action_
= ACCEPT
;
168 // This should ask us if the download is allowed.
169 // We should have been told we can download.
170 ExpectAndResetCounts(1, 0, 1, __LINE__
);
171 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
172 download_request_limiter_
->GetDownloadStatus(web_contents()));
174 // Ask again and make sure continue is invoked.
176 // The state is at allow_all, which means the delegate shouldn't be asked.
177 // We should have been told we can download.
178 ExpectAndResetCounts(1, 0, 0, __LINE__
);
179 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
180 download_request_limiter_
->GetDownloadStatus(web_contents()));
183 TEST_F(DownloadRequestLimiterTest
,
184 DownloadRequestLimiter_ResetOnNavigation
) {
185 NavigateAndCommit(GURL("http://foo.com/bar"));
187 // Do two downloads, allowing the second so that we end up with allow all.
189 ExpectAndResetCounts(1, 0, 0, __LINE__
);
190 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
191 download_request_limiter_
->GetDownloadStatus(web_contents()));
193 testing_action_
= ACCEPT
;
195 ExpectAndResetCounts(1, 0, 1, __LINE__
);
196 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
197 download_request_limiter_
->GetDownloadStatus(web_contents()));
199 // Navigate to a new URL with the same host, which shouldn't reset the allow
201 NavigateAndCommit(GURL("http://foo.com/bar2"));
203 ExpectAndResetCounts(1, 0, 0, __LINE__
);
204 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
205 download_request_limiter_
->GetDownloadStatus(web_contents()));
207 // Do a user gesture, because we're at allow all, this shouldn't change the
210 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS
,
211 download_request_limiter_
->GetDownloadStatus(web_contents()));
213 // Navigate to a completely different host, which should reset the state.
214 NavigateAndCommit(GURL("http://fooey.com"));
215 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
216 download_request_limiter_
->GetDownloadStatus(web_contents()));
218 // Do two downloads, allowing the second so that we end up with allow all.
220 ExpectAndResetCounts(1, 0, 0, __LINE__
);
221 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
222 download_request_limiter_
->GetDownloadStatus(web_contents()));
224 testing_action_
= CANCEL
;
226 ExpectAndResetCounts(0, 1, 1, __LINE__
);
227 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
228 download_request_limiter_
->GetDownloadStatus(web_contents()));
230 // Navigate to a new URL with the same host, which shouldn't reset the allow
232 NavigateAndCommit(GURL("http://fooey.com/bar2"));
234 ExpectAndResetCounts(0, 1, 0, __LINE__
);
235 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
236 download_request_limiter_
->GetDownloadStatus(web_contents()));
239 TEST_F(DownloadRequestLimiterTest
,
240 DownloadRequestLimiter_ResetOnUserGesture
) {
241 NavigateAndCommit(GURL("http://foo.com/bar"));
243 // Do one download, which should change to prompt before download.
245 ExpectAndResetCounts(1, 0, 0, __LINE__
);
246 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
247 download_request_limiter_
->GetDownloadStatus(web_contents()));
249 // Do a user gesture, which should reset back to allow one.
251 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
252 download_request_limiter_
->GetDownloadStatus(web_contents()));
254 // Ask twice, which triggers calling the delegate. Don't allow the download
255 // so that we end up with not allowed.
257 ExpectAndResetCounts(1, 0, 0, __LINE__
);
258 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
259 download_request_limiter_
->GetDownloadStatus(web_contents()));
261 testing_action_
= CANCEL
;
263 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
264 download_request_limiter_
->GetDownloadStatus(web_contents()));
265 ExpectAndResetCounts(0, 1, 1, __LINE__
);
267 // A user gesture now should NOT change the state.
269 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
270 download_request_limiter_
->GetDownloadStatus(web_contents()));
271 // And make sure we really can't download.
273 ExpectAndResetCounts(0, 1, 0, __LINE__
);
274 // And the state shouldn't have changed.
275 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
276 download_request_limiter_
->GetDownloadStatus(web_contents()));
279 TEST_F(DownloadRequestLimiterTest
,
280 DownloadRequestLimiter_ResetOnReload
) {
281 NavigateAndCommit(GURL("http://foo.com/bar"));
282 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
283 download_request_limiter_
->GetDownloadStatus(web_contents()));
285 // If the user refreshes the page without responding to the infobar, pretend
286 // like the refresh is the initial load: they get 1 free download (probably
287 // the same as the actual initial load), then an infobar.
288 testing_action_
= WAIT
;
291 ExpectAndResetCounts(1, 0, 0, __LINE__
);
292 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
293 download_request_limiter_
->GetDownloadStatus(web_contents()));
296 ExpectAndResetCounts(0, 0, 1, __LINE__
);
297 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
298 download_request_limiter_
->GetDownloadStatus(web_contents()));
300 AboutToNavigateRenderView();
301 base::RunLoop().RunUntilIdle();
302 ExpectAndResetCounts(0, 1, 0, __LINE__
);
303 ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
304 download_request_limiter_
->GetDownloadStatus(web_contents()));
307 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
308 download_request_limiter_
->GetDownloadStatus(web_contents()));
309 ExpectAndResetCounts(1, 0, 0, __LINE__
);
311 testing_action_
= CANCEL
;
313 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
314 download_request_limiter_
->GetDownloadStatus(web_contents()));
315 ExpectAndResetCounts(0, 1, 1, __LINE__
);
317 AboutToNavigateRenderView();
318 base::RunLoop().RunUntilIdle();
319 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
320 download_request_limiter_
->GetDownloadStatus(web_contents()));
322 ExpectAndResetCounts(0, 1, 0, __LINE__
);
323 ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
324 download_request_limiter_
->GetDownloadStatus(web_contents()));
327 TEST_F(DownloadRequestLimiterTest
,
328 DownloadRequestLimiter_RawWebContents
) {
329 scoped_ptr
<WebContents
> web_contents(CreateTestWebContents());
330 // DownloadRequestLimiter won't try to make an infobar if it doesn't have an
331 // InfoBarService, and we want to test that it will Cancel() instead of
332 // prompting when it doesn't have a InfoBarService, so unset the delegate.
334 ExpectAndResetCounts(0, 0, 0, __LINE__
);
335 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
336 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
337 // You get one freebie.
338 CanDownloadFor(web_contents
.get());
339 ExpectAndResetCounts(1, 0, 0, __LINE__
);
340 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
341 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
342 OnUserGestureFor(web_contents
.get());
343 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
344 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
345 CanDownloadFor(web_contents
.get());
346 ExpectAndResetCounts(1, 0, 0, __LINE__
);
347 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
348 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
349 CanDownloadFor(web_contents
.get());
350 ExpectAndResetCounts(0, 1, 0, __LINE__
);
351 EXPECT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED
,
352 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
353 OnUserGestureFor(web_contents
.get());
354 EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD
,
355 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
356 CanDownloadFor(web_contents
.get());
357 ExpectAndResetCounts(1, 0, 0, __LINE__
);
358 EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
359 download_request_limiter_
->GetDownloadStatus(web_contents
.get()));
362 TEST_F(DownloadRequestLimiterTest
,
363 DownloadRequestLimiter_SetHostContentSetting
) {
364 NavigateAndCommit(GURL("http://foo.com/bar"));
365 SetHostContentSetting(web_contents(), CONTENT_SETTING_ALLOW
);
368 ExpectAndResetCounts(1, 0, 0, __LINE__
);
369 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
370 download_request_limiter_
->GetDownloadStatus(web_contents()));
373 ExpectAndResetCounts(1, 0, 0, __LINE__
);
374 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
375 download_request_limiter_
->GetDownloadStatus(web_contents()));
377 SetHostContentSetting(web_contents(), CONTENT_SETTING_BLOCK
);
380 ExpectAndResetCounts(0, 1, 0, __LINE__
);
381 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
382 download_request_limiter_
->GetDownloadStatus(web_contents()));
385 ExpectAndResetCounts(0, 1, 0, __LINE__
);
386 ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD
,
387 download_request_limiter_
->GetDownloadStatus(web_contents()));