safe_browsing_blocking_page_unittest.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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. 4 5#include "chrome/browser/renderer_host/test/test_render_view_host.h" 6 7#include "chrome/browser/chrome_thread.h" 8#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h" 9#include "chrome/browser/tab_contents/navigation_entry.h" 10#include "chrome/browser/tab_contents/test_tab_contents.h" 11#include "chrome/common/render_messages.h" 12#include "chrome/common/render_messages_params.h" 13 14static const char* kGoogleURL = "http://www.google.com/"; 15static const char* kGoodURL = "http://www.goodguys.com/"; 16static const char* kBadURL = "http://www.badguys.com/"; 17static const char* kBadURL2 = "http://www.badguys2.com/"; 18static const char* kBadURL3 = "http://www.badguys3.com/"; 19 20// A SafeBrowingBlockingPage class that does not create windows. 21class TestSafeBrowsingBlockingPage : public SafeBrowsingBlockingPage { 22 public: 23 TestSafeBrowsingBlockingPage(SafeBrowsingService* service, 24 TabContents* tab_contents, 25 const UnsafeResourceList& unsafe_resources) 26 : SafeBrowsingBlockingPage(service, tab_contents, unsafe_resources) { 27 } 28 29 // Overriden from InterstitialPage. Don't create a view. 30 virtual TabContentsView* CreateTabContentsView() { 31 return NULL; 32 } 33}; 34 35class TestSafeBrowsingBlockingPageFactory 36 : public SafeBrowsingBlockingPageFactory { 37 public: 38 TestSafeBrowsingBlockingPageFactory() { } 39 ~TestSafeBrowsingBlockingPageFactory() { } 40 41 virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage( 42 SafeBrowsingService* service, 43 TabContents* tab_contents, 44 const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources) { 45 return new TestSafeBrowsingBlockingPage(service, tab_contents, 46 unsafe_resources); 47 } 48}; 49 50class SafeBrowsingBlockingPageTest : public RenderViewHostTestHarness, 51 public SafeBrowsingService::Client { 52 public: 53 // The decision the user made. 54 enum UserResponse { 55 PENDING, 56 OK, 57 CANCEL 58 }; 59 60 SafeBrowsingBlockingPageTest() 61 : ui_thread_(ChromeThread::UI, MessageLoop::current()), 62 io_thread_(ChromeThread::IO, MessageLoop::current()) { 63 ResetUserResponse(); 64 service_ = new SafeBrowsingService(); 65 } 66 67 virtual void SetUp() { 68 RenderViewHostTestHarness::SetUp(); 69 SafeBrowsingBlockingPage::RegisterFactory(&factory_); 70 ResetUserResponse(); 71 } 72 73 // SafeBrowsingService::Client implementation. 74 virtual void OnUrlCheckResult(const GURL& url, 75 SafeBrowsingService::UrlCheckResult result) { 76 } 77 virtual void OnBlockingPageComplete(bool proceed) { 78 if (proceed) 79 user_response_ = OK; 80 else 81 user_response_ = CANCEL; 82 } 83 84 void Navigate(const char* url, int page_id) { 85 ViewHostMsg_FrameNavigate_Params params; 86 InitNavigateParams(¶ms, page_id, GURL(url), PageTransition::TYPED); 87 contents()->TestDidNavigate(contents_->render_view_host(), params); 88 } 89 90 void GoBack() { 91 NavigationEntry* entry = contents()->controller().GetEntryAtOffset(-1); 92 ASSERT_TRUE(entry); 93 contents()->controller().GoBack(); 94 Navigate(entry->url().spec().c_str(), entry->page_id()); 95 } 96 97 void ShowInterstitial(ResourceType::Type resource_type, 98 const char* url) { 99 SafeBrowsingService::UnsafeResource resource; 100 InitResource(&resource, resource_type, GURL(url)); 101 SafeBrowsingBlockingPage::ShowBlockingPage(service_, resource); 102 } 103 104 // Returns the SafeBrowsingBlockingPage currently showing or NULL if none is 105 // showing. 106 SafeBrowsingBlockingPage* GetSafeBrowsingBlockingPage() { 107 InterstitialPage* interstitial = 108 InterstitialPage::GetInterstitialPage(contents()); 109 if (!interstitial) 110 return NULL; 111 return static_cast<SafeBrowsingBlockingPage*>(interstitial); 112 } 113 114 UserResponse user_response() const { return user_response_; } 115 void ResetUserResponse() { user_response_ = PENDING; } 116 117 static void ProceedThroughInterstitial( 118 SafeBrowsingBlockingPage* sb_interstitial) { 119 sb_interstitial->Proceed(); 120 // Proceed() posts a task to update the SafeBrowsingService::Client. 121 MessageLoop::current()->RunAllPending(); 122 } 123 124 static void DontProceedThroughInterstitial( 125 SafeBrowsingBlockingPage* sb_interstitial) { 126 sb_interstitial->DontProceed(); 127 // DontProceed() posts a task to update the SafeBrowsingService::Client. 128 MessageLoop::current()->RunAllPending(); 129 } 130 131 private: 132 void InitResource(SafeBrowsingService::UnsafeResource* resource, 133 ResourceType::Type resource_type, 134 const GURL& url) { 135 resource->client = this; 136 resource->url = url; 137 resource->resource_type = resource_type; 138 resource->threat_type = SafeBrowsingService::URL_MALWARE; 139 resource->render_process_host_id = contents_->GetRenderProcessHost()->id(); 140 resource->render_view_id = contents_->render_view_host()->routing_id(); 141 } 142 143 UserResponse user_response_; 144 scoped_refptr<SafeBrowsingService> service_; 145 TestSafeBrowsingBlockingPageFactory factory_; 146 ChromeThread ui_thread_; 147 ChromeThread io_thread_; 148}; 149 150// Tests showing a blocking page for a malware page and not proceeding. 151TEST_F(SafeBrowsingBlockingPageTest, MalwarePageDontProceed) { 152 // Start a load. 153 controller().LoadURL(GURL(kBadURL), GURL(), PageTransition::TYPED); 154 155 // Simulate the load causing a safe browsing interstitial to be shown. 156 ShowInterstitial(ResourceType::MAIN_FRAME, kBadURL); 157 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 158 ASSERT_TRUE(sb_interstitial); 159 160 MessageLoop::current()->RunAllPending(); 161 162 // Simulate the user clicking "don't proceed". 163 DontProceedThroughInterstitial(sb_interstitial); 164 165 // The interstitial should be gone. 166 EXPECT_EQ(CANCEL, user_response()); 167 EXPECT_FALSE(GetSafeBrowsingBlockingPage()); 168 169 // We did not proceed, the pending entry should be gone. 170 EXPECT_FALSE(controller().pending_entry()); 171} 172 173// Tests showing a blocking page for a malware page and then proceeding. 174TEST_F(SafeBrowsingBlockingPageTest, MalwarePageProceed) { 175 // Start a load. 176 controller().LoadURL(GURL(kBadURL), GURL(), PageTransition::TYPED); 177 178 // Simulate the load causing a safe browsing interstitial to be shown. 179 ShowInterstitial(ResourceType::MAIN_FRAME, kBadURL); 180 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 181 ASSERT_TRUE(sb_interstitial); 182 183 // Simulate the user clicking "proceed". 184 ProceedThroughInterstitial(sb_interstitial); 185 186 // The interstitial is shown until the navigation commits. 187 ASSERT_TRUE(InterstitialPage::GetInterstitialPage(contents())); 188 // Commit the navigation. 189 Navigate(kBadURL, 1); 190 // The interstitial should be gone now. 191 ASSERT_FALSE(InterstitialPage::GetInterstitialPage(contents())); 192} 193 194// Tests showing a blocking page for a page that contains malware subresources 195// and not proceeding. 196TEST_F(SafeBrowsingBlockingPageTest, PageWithMalwareResourceDontProceed) { 197 // Navigate somewhere. 198 Navigate(kGoogleURL, 1); 199 200 // Navigate somewhere else. 201 Navigate(kGoodURL, 2); 202 203 // Simulate that page loading a bad-resource triggering an interstitial. 204 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL); 205 206 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 207 ASSERT_TRUE(sb_interstitial); 208 209 // Simulate the user clicking "don't proceed". 210 DontProceedThroughInterstitial(sb_interstitial); 211 EXPECT_EQ(CANCEL, user_response()); 212 EXPECT_FALSE(GetSafeBrowsingBlockingPage()); 213 214 // We did not proceed, we should be back to the first page, the 2nd one should 215 // have been removed from the navigation controller. 216 ASSERT_EQ(1, controller().entry_count()); 217 EXPECT_EQ(kGoogleURL, controller().GetActiveEntry()->url().spec()); 218} 219 220// Tests showing a blocking page for a page that contains malware subresources 221// and proceeding. 222TEST_F(SafeBrowsingBlockingPageTest, PageWithMalwareResourceProceed) { 223 // Navigate somewhere. 224 Navigate(kGoodURL, 1); 225 226 // Simulate that page loading a bad-resource triggering an interstitial. 227 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL); 228 229 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 230 ASSERT_TRUE(sb_interstitial); 231 232 // Simulate the user clicking "proceed". 233 ProceedThroughInterstitial(sb_interstitial); 234 EXPECT_EQ(OK, user_response()); 235 EXPECT_FALSE(GetSafeBrowsingBlockingPage()); 236 237 // We did proceed, we should be back to showing the page. 238 ASSERT_EQ(1, controller().entry_count()); 239 EXPECT_EQ(kGoodURL, controller().GetActiveEntry()->url().spec()); 240} 241 242// Tests showing a blocking page for a page that contains multiple malware 243// subresources and not proceeding. This just tests that the extra malware 244// subresources (which trigger queued interstitial pages) do not break anything. 245TEST_F(SafeBrowsingBlockingPageTest, 246 PageWithMultipleMalwareResourceDontProceed) { 247 // Navigate somewhere. 248 Navigate(kGoogleURL, 1); 249 250 // Navigate somewhere else. 251 Navigate(kGoodURL, 2); 252 253 // Simulate that page loading a bad-resource triggering an interstitial. 254 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL); 255 256 // More bad resources loading causing more interstitials. The new 257 // interstitials should be queued. 258 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL2); 259 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL3); 260 261 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 262 ASSERT_TRUE(sb_interstitial); 263 264 // Simulate the user clicking "don't proceed". 265 DontProceedThroughInterstitial(sb_interstitial); 266 EXPECT_EQ(CANCEL, user_response()); 267 EXPECT_FALSE(GetSafeBrowsingBlockingPage()); 268 269 // We did not proceed, we should be back to the first page, the 2nd one should 270 // have been removed from the navigation controller. 271 ASSERT_EQ(1, controller().entry_count()); 272 EXPECT_EQ(kGoogleURL, controller().GetActiveEntry()->url().spec()); 273} 274 275// Tests showing a blocking page for a page that contains multiple malware 276// subresources and proceeding through the first interstitial, but not the next. 277TEST_F(SafeBrowsingBlockingPageTest, 278 PageWithMultipleMalwareResourceProceedThenDontProceed) { 279 // Navigate somewhere. 280 Navigate(kGoogleURL, 1); 281 282 // Navigate somewhere else. 283 Navigate(kGoodURL, 2); 284 285 // Simulate that page loading a bad-resource triggering an interstitial. 286 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL); 287 288 // More bad resources loading causing more interstitials. The new 289 // interstitials should be queued. 290 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL2); 291 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL3); 292 293 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 294 ASSERT_TRUE(sb_interstitial); 295 296 // Proceed through the 1st interstitial. 297 ProceedThroughInterstitial(sb_interstitial); 298 EXPECT_EQ(OK, user_response()); 299 300 ResetUserResponse(); 301 302 // We should land to a 2nd interstitial (aggregating all the malware resources 303 // loaded while the 1st interstitial was showing). 304 sb_interstitial = GetSafeBrowsingBlockingPage(); 305 ASSERT_TRUE(sb_interstitial); 306 307 // Don't proceed through the 2nd interstitial. 308 DontProceedThroughInterstitial(sb_interstitial); 309 EXPECT_EQ(CANCEL, user_response()); 310 EXPECT_FALSE(GetSafeBrowsingBlockingPage()); 311 312 // We did not proceed, we should be back to the first page, the 2nd one should 313 // have been removed from the navigation controller. 314 ASSERT_EQ(1, controller().entry_count()); 315 EXPECT_EQ(kGoogleURL, controller().GetActiveEntry()->url().spec()); 316} 317 318// Tests showing a blocking page for a page that contains multiple malware 319// subresources and proceeding through the multiple interstitials. 320TEST_F(SafeBrowsingBlockingPageTest, PageWithMultipleMalwareResourceProceed) { 321 // Navigate somewhere else. 322 Navigate(kGoodURL, 1); 323 324 // Simulate that page loading a bad-resource triggering an interstitial. 325 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL); 326 327 // More bad resources loading causing more interstitials. The new 328 // interstitials should be queued. 329 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL2); 330 ShowInterstitial(ResourceType::SUB_RESOURCE, kBadURL3); 331 332 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 333 ASSERT_TRUE(sb_interstitial); 334 335 // Proceed through the 1st interstitial. 336 ProceedThroughInterstitial(sb_interstitial); 337 EXPECT_EQ(OK, user_response()); 338 339 ResetUserResponse(); 340 341 // We should land to a 2nd interstitial (aggregating all the malware resources 342 // loaded while the 1st interstitial was showing). 343 sb_interstitial = GetSafeBrowsingBlockingPage(); 344 ASSERT_TRUE(sb_interstitial); 345 346 // Proceed through the 2nd interstitial. 347 ProceedThroughInterstitial(sb_interstitial); 348 EXPECT_EQ(OK, user_response()); 349 350 // We did proceed, we should be back to the initial page. 351 ASSERT_EQ(1, controller().entry_count()); 352 EXPECT_EQ(kGoodURL, controller().GetActiveEntry()->url().spec()); 353} 354 355// Tests showing a blocking page then navigating back and forth to make sure the 356// controller entries are OK. http://crbug.com/17627 357TEST_F(SafeBrowsingBlockingPageTest, NavigatingBackAndForth) { 358 // Navigate somewhere. 359 Navigate(kGoodURL, 1); 360 361 // Now navigate to a bad page triggerring an interstitial. 362 controller().LoadURL(GURL(kBadURL), GURL(), PageTransition::TYPED); 363 ShowInterstitial(ResourceType::MAIN_FRAME, kBadURL); 364 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 365 ASSERT_TRUE(sb_interstitial); 366 367 // Proceed, then navigate back. 368 ProceedThroughInterstitial(sb_interstitial); 369 Navigate(kBadURL, 2); // Commit the navigation. 370 GoBack(); 371 372 // We are back on the good page. 373 sb_interstitial = GetSafeBrowsingBlockingPage(); 374 ASSERT_FALSE(sb_interstitial); 375 ASSERT_EQ(2, controller().entry_count()); 376 EXPECT_EQ(kGoodURL, controller().GetActiveEntry()->url().spec()); 377 378 // Navigate forward to the malware URL. 379 contents()->controller().GoForward(); 380 ShowInterstitial(ResourceType::MAIN_FRAME, kBadURL); 381 sb_interstitial = GetSafeBrowsingBlockingPage(); 382 ASSERT_TRUE(sb_interstitial); 383 384 // Let's proceed and make sure everything is OK (bug 17627). 385 ProceedThroughInterstitial(sb_interstitial); 386 Navigate(kBadURL, 2); // Commit the navigation. 387 sb_interstitial = GetSafeBrowsingBlockingPage(); 388 ASSERT_FALSE(sb_interstitial); 389 ASSERT_EQ(2, controller().entry_count()); 390 EXPECT_EQ(kBadURL, controller().GetActiveEntry()->url().spec()); 391} 392 393// Tests that calling "don't proceed" after "proceed" has been called doesn't 394// cause problems. http://crbug.com/30079 395TEST_F(SafeBrowsingBlockingPageTest, ProceedThenDontProceed) { 396 // Start a load. 397 controller().LoadURL(GURL(kBadURL), GURL(), PageTransition::TYPED); 398 399 // Simulate the load causing a safe browsing interstitial to be shown. 400 ShowInterstitial(ResourceType::MAIN_FRAME, kBadURL); 401 SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage(); 402 ASSERT_TRUE(sb_interstitial); 403 404 MessageLoop::current()->RunAllPending(); 405 406 // Simulate the user clicking "proceed" then "don't proceed" (before the 407 // interstitial is shown). 408 sb_interstitial->Proceed(); 409 sb_interstitial->DontProceed(); 410 // Proceed() and DontProceed() post a task to update the 411 // SafeBrowsingService::Client. 412 MessageLoop::current()->RunAllPending(); 413 414 // The interstitial should be gone. 415 EXPECT_EQ(OK, user_response()); 416 EXPECT_FALSE(GetSafeBrowsingBlockingPage()); 417} 418