Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / safe_browsing / safe_browsing_test.cc
blob807a2c2ac376a6a138cefc0cfd65d6bd79625e1e
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.
4 //
5 // This test uses the safebrowsing test server published at
6 // http://code.google.com/p/google-safe-browsing/ to test the safebrowsing
7 // protocol implemetation. Details of the safebrowsing testing flow is
8 // documented at
9 // http://code.google.com/p/google-safe-browsing/wiki/ProtocolTesting
11 // This test launches safebrowsing test server and issues several update
12 // requests against that server. Each update would get different data and after
13 // each update, the test will get a list of URLs from the test server to verify
14 // its repository. The test will succeed only if all updates are performed and
15 // URLs match what the server expected.
17 #include <vector>
19 #include "base/bind.h"
20 #include "base/command_line.h"
21 #include "base/environment.h"
22 #include "base/path_service.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_split.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "base/synchronization/lock.h"
28 #include "base/test/test_timeouts.h"
29 #include "base/threading/platform_thread.h"
30 #include "base/threading/thread.h"
31 #include "base/time/time.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/chrome_notification_types.h"
34 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/safe_browsing/database_manager.h"
36 #include "chrome/browser/safe_browsing/local_database_manager.h"
37 #include "chrome/browser/safe_browsing/local_safebrowsing_test_server.h"
38 #include "chrome/browser/safe_browsing/protocol_manager.h"
39 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
40 #include "chrome/browser/ui/browser.h"
41 #include "chrome/common/chrome_switches.h"
42 #include "chrome/common/url_constants.h"
43 #include "chrome/test/base/in_process_browser_test.h"
44 #include "content/public/browser/browser_context.h"
45 #include "content/public/test/test_browser_thread.h"
46 #include "content/public/test/test_utils.h"
47 #include "net/base/load_flags.h"
48 #include "net/dns/host_resolver.h"
49 #include "net/log/net_log.h"
50 #include "net/test/python_utils.h"
51 #include "net/url_request/url_fetcher.h"
52 #include "net/url_request/url_fetcher_delegate.h"
53 #include "net/url_request/url_request_status.h"
54 #include "testing/gtest/include/gtest/gtest.h"
56 using content::BrowserThread;
58 #ifndef SAFE_BROWSING_DB_LOCAL
59 #error This test requires the SAFE_BROWSING_DB_LOCAL implementation.
60 #endif
62 namespace {
64 const base::FilePath::CharType kDataFile[] =
65 FILE_PATH_LITERAL("testing_input_nomac.dat");
66 const char kUrlVerifyPath[] = "safebrowsing/verify_urls";
67 const char kDBVerifyPath[] = "safebrowsing/verify_database";
68 const char kTestCompletePath[] = "test_complete";
70 struct PhishingUrl {
71 std::string url;
72 std::string list_name;
73 bool is_phishing;
76 // Parses server response for verify_urls. The expected format is:
78 // first.random.url.com/ internal-test-shavar yes
79 // second.random.url.com/ internal-test-shavar yes
80 // ...
81 bool ParsePhishingUrls(const std::string& data,
82 std::vector<PhishingUrl>* phishing_urls) {
83 if (data.empty())
84 return false;
86 for (const base::StringPiece& url_str : base::SplitStringPiece(
87 data, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
88 PhishingUrl phishing_url;
89 std::vector<std::string> record_parts = base::SplitString(
90 url_str, "\t", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
91 if (record_parts.size() != 3) {
92 LOG(ERROR) << "Unexpected URL format in phishing URL list: "
93 << url_str.as_string();
94 return false;
96 phishing_url.url = std::string(url::kHttpScheme) + "://" + record_parts[0];
97 phishing_url.list_name = record_parts[1];
98 if (record_parts[2] == "yes") {
99 phishing_url.is_phishing = true;
100 } else if (record_parts[2] == "no") {
101 phishing_url.is_phishing = false;
102 } else {
103 LOG(ERROR) << "Unrecognized expectation in " << url_str.as_string()
104 << ": " << record_parts[2];
105 return false;
107 phishing_urls->push_back(phishing_url);
109 return true;
112 class FakeSafeBrowsingService : public SafeBrowsingService {
113 public:
114 explicit FakeSafeBrowsingService(const std::string& url_prefix)
115 : url_prefix_(url_prefix) {}
117 SafeBrowsingProtocolConfig GetProtocolConfig() const override {
118 SafeBrowsingProtocolConfig config;
119 config.url_prefix = url_prefix_;
120 // Makes sure the auto update is not triggered. The tests will force the
121 // update when needed.
122 config.disable_auto_update = true;
123 #if defined(OS_ANDROID)
124 config.disable_connection_check = true;
125 #endif
126 config.client_name = "browser_tests";
127 return config;
130 private:
131 ~FakeSafeBrowsingService() override {}
133 std::string url_prefix_;
135 DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingService);
138 // Factory that creates FakeSafeBrowsingService instances.
139 class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory {
140 public:
141 explicit TestSafeBrowsingServiceFactory(const std::string& url_prefix)
142 : url_prefix_(url_prefix) {}
144 SafeBrowsingService* CreateSafeBrowsingService() override {
145 return new FakeSafeBrowsingService(url_prefix_);
148 private:
149 std::string url_prefix_;
152 } // namespace
154 // This starts the browser and keeps status of states related to SafeBrowsing.
155 class SafeBrowsingServerTest : public InProcessBrowserTest {
156 public:
157 SafeBrowsingServerTest()
158 : safe_browsing_service_(NULL),
159 is_database_ready_(true),
160 is_update_scheduled_(false),
161 is_checked_url_in_db_(false),
162 is_checked_url_safe_(false) {
165 ~SafeBrowsingServerTest() override {}
167 void UpdateSafeBrowsingStatus() {
168 ASSERT_TRUE(safe_browsing_service_);
169 base::AutoLock lock(update_status_mutex_);
170 last_update_ = safe_browsing_service_->protocol_manager_->last_update();
171 is_update_scheduled_ =
172 safe_browsing_service_->protocol_manager_->update_timer_.IsRunning();
175 void ForceUpdate() {
176 content::WindowedNotificationObserver observer(
177 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
178 content::Source<SafeBrowsingDatabaseManager>(database_manager()));
179 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
180 base::Bind(&SafeBrowsingServerTest::ForceUpdateOnIOThread,
181 this));
182 observer.Wait();
185 void ForceUpdateOnIOThread() {
186 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
187 ASSERT_TRUE(safe_browsing_service_);
188 safe_browsing_service_->protocol_manager_->ForceScheduleNextUpdate(
189 base::TimeDelta::FromSeconds(0));
193 void CheckIsDatabaseReady() {
194 base::AutoLock lock(update_status_mutex_);
195 is_database_ready_ =
196 !local_database_manager()->database_update_in_progress_;
199 void CheckUrl(SafeBrowsingDatabaseManager::Client* helper, const GURL& url) {
200 ASSERT_TRUE(safe_browsing_service_);
201 base::AutoLock lock(update_status_mutex_);
202 if (database_manager()->CheckBrowseUrl(url, helper)) {
203 is_checked_url_in_db_ = false;
204 is_checked_url_safe_ = true;
205 } else {
206 // In this case, Safebrowsing service will fetch the full hash
207 // from the server and examine that. Once it is done,
208 // set_is_checked_url_safe() will be called via callback.
209 is_checked_url_in_db_ = true;
213 SafeBrowsingDatabaseManager* database_manager() {
214 return safe_browsing_service_->database_manager().get();
217 // TODO(nparker): Remove the need for this by wiring in our own
218 // SafeBrowsingDatabaseManager factory and keep a ptr to the subclass.
219 LocalSafeBrowsingDatabaseManager* local_database_manager() {
220 return static_cast<LocalSafeBrowsingDatabaseManager*>(database_manager());
224 bool is_checked_url_in_db() {
225 base::AutoLock l(update_status_mutex_);
226 return is_checked_url_in_db_;
229 void set_is_checked_url_safe(bool safe) {
230 base::AutoLock l(update_status_mutex_);
231 is_checked_url_safe_ = safe;
234 bool is_checked_url_safe() {
235 base::AutoLock l(update_status_mutex_);
236 return is_checked_url_safe_;
239 bool is_database_ready() {
240 base::AutoLock l(update_status_mutex_);
241 return is_database_ready_;
244 base::Time last_update() {
245 base::AutoLock l(update_status_mutex_);
246 return last_update_;
249 bool is_update_scheduled() {
250 base::AutoLock l(update_status_mutex_);
251 return is_update_scheduled_;
254 scoped_refptr<base::SequencedTaskRunner> SafeBrowsingTaskRunner() {
255 return local_database_manager()->safe_browsing_task_runner_;
258 const net::SpawnedTestServer& test_server() const {
259 return *test_server_;
262 protected:
263 bool InitSafeBrowsingService() {
264 safe_browsing_service_ = g_browser_process->safe_browsing_service();
265 return safe_browsing_service_ != NULL;
268 void SetUp() override {
269 base::FilePath datafile_path;
270 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &datafile_path));
272 datafile_path = datafile_path.Append(FILE_PATH_LITERAL("third_party"))
273 .Append(FILE_PATH_LITERAL("safe_browsing"))
274 .Append(FILE_PATH_LITERAL("testing"))
275 .Append(kDataFile);
276 test_server_.reset(new LocalSafeBrowsingTestServer(datafile_path));
277 ASSERT_TRUE(test_server_->Start());
278 LOG(INFO) << "server is " << test_server_->host_port_pair().ToString();
280 // Point to the testing server for all SafeBrowsing requests.
281 std::string url_prefix = test_server_->GetURL("safebrowsing").spec();
282 sb_factory_.reset(new TestSafeBrowsingServiceFactory(url_prefix));
283 SafeBrowsingService::RegisterFactory(sb_factory_.get());
285 InProcessBrowserTest::SetUp();
288 void TearDown() override {
289 InProcessBrowserTest::TearDown();
291 SafeBrowsingService::RegisterFactory(NULL);
294 void SetUpCommandLine(base::CommandLine* command_line) override {
295 // TODO(lzheng): The test server does not understand download related
296 // requests. We need to fix the server.
297 command_line->AppendSwitch(switches::kSbDisableDownloadProtection);
299 // TODO(gcasto): Generate new testing data that includes the
300 // client-side phishing whitelist.
301 command_line->AppendSwitch(
302 switches::kDisableClientSidePhishingDetection);
304 // TODO(kalman): Generate new testing data that includes the extension
305 // blacklist.
306 command_line->AppendSwitch(switches::kSbDisableExtensionBlacklist);
309 void SetTestStep(int step) {
310 std::string test_step = base::StringPrintf("test_step=%d", step);
311 safe_browsing_service_->protocol_manager_->set_additional_query(test_step);
314 private:
315 scoped_ptr<TestSafeBrowsingServiceFactory> sb_factory_;
317 SafeBrowsingService* safe_browsing_service_;
319 scoped_ptr<net::SpawnedTestServer> test_server_;
321 // Protects all variables below since they are read on UI thread
322 // but updated on IO thread or safebrowsing thread.
323 base::Lock update_status_mutex_;
325 // States associated with safebrowsing service updates.
326 bool is_database_ready_;
327 base::Time last_update_;
328 bool is_update_scheduled_;
329 // Indicates if there is a match between a URL's prefix and safebrowsing
330 // database (thus potentially it is a phishing URL).
331 bool is_checked_url_in_db_;
332 // True if last verified URL is not a phishing URL and thus it is safe.
333 bool is_checked_url_safe_;
335 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServerTest);
338 // A ref counted helper class that handles callbacks between IO thread and UI
339 // thread.
340 class SafeBrowsingServerTestHelper
341 : public base::RefCountedThreadSafe<SafeBrowsingServerTestHelper>,
342 public SafeBrowsingDatabaseManager::Client,
343 public net::URLFetcherDelegate {
344 public:
345 SafeBrowsingServerTestHelper(SafeBrowsingServerTest* safe_browsing_test,
346 net::URLRequestContextGetter* request_context)
347 : safe_browsing_test_(safe_browsing_test),
348 response_status_(net::URLRequestStatus::FAILED),
349 request_context_(request_context) {
352 // Callbacks for SafeBrowsingDatabaseManager::Client.
353 void OnCheckBrowseUrlResult(const GURL& url,
354 SBThreatType threat_type,
355 const std::string& metadata) override {
356 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
357 EXPECT_TRUE(safe_browsing_test_->is_checked_url_in_db());
358 safe_browsing_test_->set_is_checked_url_safe(
359 threat_type == SB_THREAT_TYPE_SAFE);
360 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
361 base::Bind(&SafeBrowsingServerTestHelper::OnCheckUrlDone, this));
364 virtual void OnBlockingPageComplete(bool proceed) {
365 NOTREACHED() << "Not implemented.";
368 // Functions and callbacks related to CheckUrl. These are used to verify
369 // phishing URLs.
370 void CheckUrl(const GURL& url) {
371 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
372 base::Bind(&SafeBrowsingServerTestHelper::CheckUrlOnIOThread,
373 this, url));
374 content::RunMessageLoop();
376 void CheckUrlOnIOThread(const GURL& url) {
377 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
378 safe_browsing_test_->CheckUrl(this, url);
379 if (!safe_browsing_test_->is_checked_url_in_db()) {
380 // Ends the checking since this URL's prefix is not in database.
381 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
382 base::Bind(&SafeBrowsingServerTestHelper::OnCheckUrlDone, this));
384 // Otherwise, OnCheckUrlDone is called in OnUrlCheckResult since
385 // safebrowsing service further fetches hashes from safebrowsing server.
388 void OnCheckUrlDone() {
389 StopUILoop();
392 // Updates status from IO Thread.
393 void CheckStatusOnIOThread() {
394 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
395 safe_browsing_test_->UpdateSafeBrowsingStatus();
396 safe_browsing_test_->SafeBrowsingTaskRunner()->PostTask(
397 FROM_HERE,
398 base::Bind(&SafeBrowsingServerTestHelper::CheckIsDatabaseReady, this));
401 // Checks status in SafeBrowsing Thread.
402 void CheckIsDatabaseReady() {
403 EXPECT_TRUE(safe_browsing_test_->SafeBrowsingTaskRunner()
404 ->RunsTasksOnCurrentThread());
405 safe_browsing_test_->CheckIsDatabaseReady();
406 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
407 base::Bind(&SafeBrowsingServerTestHelper::OnWaitForStatusUpdateDone,
408 this));
411 void OnWaitForStatusUpdateDone() {
412 StopUILoop();
415 // Update safebrowsing status.
416 void UpdateStatus() {
417 BrowserThread::PostTask(
418 BrowserThread::IO,
419 FROM_HERE,
420 base::Bind(&SafeBrowsingServerTestHelper::CheckStatusOnIOThread, this));
421 // Will continue after OnWaitForStatusUpdateDone().
422 content::RunMessageLoop();
425 // Calls test server to fetch database for verification.
426 net::URLRequestStatus::Status FetchDBToVerify(
427 const net::SpawnedTestServer& test_server,
428 int test_step) {
429 // TODO(lzheng): Remove chunk_type=add once it is not needed by the server.
430 std::string path = base::StringPrintf(
431 "%s?client=chromium&appver=1.0&pver=3.0&test_step=%d&chunk_type=add",
432 kDBVerifyPath, test_step);
433 return FetchUrl(test_server.GetURL(path));
436 // Calls test server to fetch URLs for verification.
437 net::URLRequestStatus::Status FetchUrlsToVerify(
438 const net::SpawnedTestServer& test_server,
439 int test_step) {
440 std::string path = base::StringPrintf(
441 "%s?client=chromium&appver=1.0&pver=3.0&test_step=%d",
442 kUrlVerifyPath, test_step);
443 return FetchUrl(test_server.GetURL(path));
446 // Calls test server to check if test data is done. E.g.: if there is a
447 // bad URL that server expects test to fetch full hash but the test didn't,
448 // this verification will fail.
449 net::URLRequestStatus::Status VerifyTestComplete(
450 const net::SpawnedTestServer& test_server,
451 int test_step) {
452 std::string path = base::StringPrintf(
453 "%s?test_step=%d", kTestCompletePath, test_step);
454 return FetchUrl(test_server.GetURL(path));
457 // Callback for URLFetcher.
458 void OnURLFetchComplete(const net::URLFetcher* source) override {
459 source->GetResponseAsString(&response_data_);
460 response_status_ = source->GetStatus().status();
461 StopUILoop();
464 const std::string& response_data() {
465 return response_data_;
468 private:
469 friend class base::RefCountedThreadSafe<SafeBrowsingServerTestHelper>;
470 ~SafeBrowsingServerTestHelper() override {}
472 // Stops UI loop after desired status is updated.
473 void StopUILoop() {
474 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
475 base::MessageLoopForUI::current()->Quit();
478 // Fetch a URL. If message_loop_started is true, starts the message loop
479 // so the caller could wait till OnURLFetchComplete is called.
480 net::URLRequestStatus::Status FetchUrl(const GURL& url) {
481 url_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
482 url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
483 url_fetcher_->SetRequestContext(request_context_);
484 url_fetcher_->Start();
485 content::RunMessageLoop();
486 return response_status_;
489 base::OneShotTimer<SafeBrowsingServerTestHelper> check_update_timer_;
490 SafeBrowsingServerTest* safe_browsing_test_;
491 scoped_ptr<net::URLFetcher> url_fetcher_;
492 std::string response_data_;
493 net::URLRequestStatus::Status response_status_;
494 net::URLRequestContextGetter* request_context_;
495 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServerTestHelper);
498 // TODO(shess): Disabled pending new data for third_party/safe_browsing/testing/
499 IN_PROC_BROWSER_TEST_F(SafeBrowsingServerTest,
500 DISABLED_SafeBrowsingServerTest) {
501 LOG(INFO) << "Start test";
502 ASSERT_TRUE(InitSafeBrowsingService());
504 net::URLRequestContextGetter* request_context =
505 browser()->profile()->GetRequestContext();
506 scoped_refptr<SafeBrowsingServerTestHelper> safe_browsing_helper(
507 new SafeBrowsingServerTestHelper(this, request_context));
508 int last_step = 0;
510 // Waits and makes sure safebrowsing update is not happening.
511 // The wait will stop once OnWaitForStatusUpdateDone in
512 // safe_browsing_helper is called and status from safe_browsing_service_
513 // is checked.
514 safe_browsing_helper->UpdateStatus();
515 EXPECT_TRUE(is_database_ready());
516 EXPECT_FALSE(is_update_scheduled());
517 EXPECT_TRUE(last_update().is_null());
518 // Starts updates. After each update, the test will fetch a list of URLs with
519 // expected results to verify with safebrowsing service. If there is no error,
520 // the test moves on to the next step to get more update chunks.
521 // This repeats till there is no update data.
522 for (int step = 1;; step++) {
523 // Every step should be a fresh start.
524 SCOPED_TRACE(base::StringPrintf("step=%d", step));
525 EXPECT_TRUE(is_database_ready());
526 EXPECT_FALSE(is_update_scheduled());
528 // Starts safebrowsing update on IO thread. Waits till scheduled
529 // update finishes.
530 base::Time now = base::Time::Now();
531 SetTestStep(step);
532 ForceUpdate();
534 safe_browsing_helper->UpdateStatus();
535 EXPECT_TRUE(is_database_ready());
536 EXPECT_FALSE(is_update_scheduled());
537 EXPECT_FALSE(last_update().is_null());
538 if (last_update() < now) {
539 // This means no data available anymore.
540 break;
543 // Fetches URLs to verify and waits till server responses with data.
544 EXPECT_EQ(net::URLRequestStatus::SUCCESS,
545 safe_browsing_helper->FetchUrlsToVerify(test_server(), step));
547 std::vector<PhishingUrl> phishing_urls;
548 EXPECT_TRUE(ParsePhishingUrls(safe_browsing_helper->response_data(),
549 &phishing_urls));
550 EXPECT_GT(phishing_urls.size(), 0U);
551 for (size_t j = 0; j < phishing_urls.size(); ++j) {
552 // Verifes with server if a URL is a phishing URL and waits till server
553 // responses.
554 safe_browsing_helper->CheckUrl(GURL(phishing_urls[j].url));
555 if (phishing_urls[j].is_phishing) {
556 EXPECT_TRUE(is_checked_url_in_db())
557 << phishing_urls[j].url
558 << " is_phishing: " << phishing_urls[j].is_phishing
559 << " test step: " << step;
560 EXPECT_FALSE(is_checked_url_safe())
561 << phishing_urls[j].url
562 << " is_phishing: " << phishing_urls[j].is_phishing
563 << " test step: " << step;
564 } else {
565 EXPECT_TRUE(is_checked_url_safe())
566 << phishing_urls[j].url
567 << " is_phishing: " << phishing_urls[j].is_phishing
568 << " test step: " << step;
571 // TODO(lzheng): We should verify the fetched database with local
572 // database to make sure they match.
573 EXPECT_EQ(net::URLRequestStatus::SUCCESS,
574 safe_browsing_helper->FetchDBToVerify(test_server(), step));
575 EXPECT_GT(safe_browsing_helper->response_data().size(), 0U);
576 last_step = step;
579 // Verifies with server if test is done and waits till server responses.
580 EXPECT_EQ(net::URLRequestStatus::SUCCESS,
581 safe_browsing_helper->VerifyTestComplete(test_server(), last_step));
582 EXPECT_EQ("yes", safe_browsing_helper->response_data());