summaryrefslogtreecommitdiffstats
path: root/chrome/browser/safe_browsing
diff options
context:
space:
mode:
authornoelutz@google.com <noelutz@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-17 19:47:13 +0000
committernoelutz@google.com <noelutz@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-17 19:47:13 +0000
commitfa685ffdc706738091a9243e12da2c89f2a01f0f (patch)
treee9635360daabc26604bbf842f9873c0ce12c19ac /chrome/browser/safe_browsing
parentbd6e45ffd4f1c0e805e76a472b50f8f05e3e82e0 (diff)
downloadchromium_src-fa685ffdc706738091a9243e12da2c89f2a01f0f.zip
chromium_src-fa685ffdc706738091a9243e12da2c89f2a01f0f.tar.gz
chromium_src-fa685ffdc706738091a9243e12da2c89f2a01f0f.tar.bz2
Intergration of the client-side phishing detection.
If the client-side phishing detection classifies a page as phishing it will send back a ping to Google to verify whether or not the page is really phishing. If the server also classifies the site as phishing we may show a phishing interstitial if it is enabled. BUG= TEST= Review URL: http://codereview.chromium.org/6014003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75299 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/safe_browsing')
-rw-r--r--chrome/browser/safe_browsing/client_side_detection_host.cc162
-rw-r--r--chrome/browser/safe_browsing/client_side_detection_host.h73
-rw-r--r--chrome/browser/safe_browsing/client_side_detection_host_unittest.cc296
-rw-r--r--chrome/browser/safe_browsing/client_side_detection_service.cc3
-rw-r--r--chrome/browser/safe_browsing/client_side_detection_service.h11
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.h16
6 files changed, 547 insertions, 14 deletions
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
new file mode 100644
index 0000000..b23a9bb
--- /dev/null
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/client_side_detection_host.h"
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/task.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/safe_browsing/client_side_detection_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/safebrowsing_messages.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/render_messages_params.h"
+#include "googleurl/src/gurl.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace safe_browsing {
+
+// This class is used to display the phishing interstitial.
+class CsdClient : public SafeBrowsingService::Client {
+ public:
+ CsdClient() {}
+
+ // Method from SafeBrowsingService::Client. This method is called on the
+ // IO thread once the interstitial is going away. This method simply deletes
+ // the CsdClient object.
+ virtual void OnBlockingPageComplete(bool proceed) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Delete this on the UI thread since it was created there.
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ new DeleteTask<CsdClient>(this));
+ }
+
+ private:
+ friend class DeleteTask<CsdClient>; // Calls the private destructor.
+
+ // We're taking care of deleting this object. No-one else should delete
+ // this object.
+ virtual ~CsdClient() {}
+
+ DISALLOW_COPY_AND_ASSIGN(CsdClient);
+};
+
+ClientSideDetectionHost::ClientSideDetectionHost(TabContents* tab)
+ : TabContentsObserver(tab),
+ service_(g_browser_process->safe_browsing_detection_service()),
+ cb_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+ DCHECK(tab);
+ // Note: service_ and sb_service_ might be NULL.
+ ResourceDispatcherHost* resource =
+ g_browser_process->resource_dispatcher_host();
+ if (resource) {
+ sb_service_ = resource->safe_browsing_service();
+ }
+}
+
+ClientSideDetectionHost::~ClientSideDetectionHost() {
+}
+
+bool ClientSideDetectionHost::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ClientSideDetectionHost, message)
+ IPC_MESSAGE_HANDLER(SafeBrowsingDetectionHostMsg_DetectedPhishingSite,
+ OnDetectedPhishingSite)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void ClientSideDetectionHost::DidNavigateMainFramePostCommit(
+ const NavigationController::LoadCommittedDetails& details,
+ const ViewHostMsg_FrameNavigate_Params& params) {
+ // TODO(noelutz): move this DCHECK to TabContents and fix all the unit tests
+ // that don't call this method on the UI thread.
+ // DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // If we navigate away and there currently is a pending phishing
+ // report request we have to cancel it to make sure we don't display
+ // an interstitial for the wrong page. Note that this won't cancel
+ // the server ping back but only cancel the showing of the
+ // interstial.
+ cb_factory_.RevokeAll();
+}
+
+void ClientSideDetectionHost::OnDetectedPhishingSite(const GURL& phishing_url,
+ double phishing_score) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // There is something seriously wrong if there is no service class but
+ // this method is called. The renderer should not start phishing detection
+ // if there isn't any service class in the browser.
+ DCHECK(service_);
+ if (service_ && tab_contents()) {
+ // There shouldn't be any pending requests because we revoke them everytime
+ // we navigate away.
+ DCHECK(!cb_factory_.HasPendingCallbacks());
+ service_->SendClientReportPhishingRequest(
+ phishing_url,
+ phishing_score,
+ cb_factory_.NewCallback(
+ &ClientSideDetectionHost::MaybeShowPhishingWarning));
+ }
+}
+
+void ClientSideDetectionHost::MaybeShowPhishingWarning(GURL phishing_url,
+ bool is_phishing) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (is_phishing &&
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClientSidePhishingInterstitial)) {
+ DCHECK(tab_contents());
+ // TODO(noelutz): this is not perfect. It's still possible that the
+ // user browses away before the interstitial is shown. Maybe we should
+ // stop all pending navigations?
+ if (sb_service_) {
+ // TODO(noelutz): refactor the SafeBrowsing service class and the
+ // SafeBrowsing blocking page class so that we don't need to depend
+ // on the SafeBrowsingService here and so that we don't need to go
+ // through the IO message loop.
+ std::vector<GURL> redirect_urls;
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(sb_service_.get(),
+ &SafeBrowsingService::DisplayBlockingPage,
+ phishing_url, phishing_url,
+ redirect_urls,
+ // We only classify the main frame URL.
+ ResourceType::MAIN_FRAME,
+ // TODO(noelutz): create a separate threat type
+ // for client-side phishing detection.
+ SafeBrowsingService::URL_PHISHING,
+ new CsdClient() /* will delete itself */,
+ tab_contents()->GetRenderProcessHost()->id(),
+ tab_contents()->render_view_host()->routing_id()));
+ }
+ }
+}
+
+void ClientSideDetectionHost::set_client_side_detection_service(
+ ClientSideDetectionService* service) {
+ service_ = service;
+}
+
+void ClientSideDetectionHost::set_safe_browsing_service(
+ SafeBrowsingService* service) {
+ sb_service_ = service;
+}
+
+} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h
new file mode 100644
index 0000000..20c8eb7
--- /dev/null
+++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_CLIENT_SIDE_DETECTION_HOST_H_
+#define CHROME_BROWSER_SAFE_BROWSING_CLIENT_SIDE_DETECTION_HOST_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_callback_factory.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/tab_contents/tab_contents_observer.h"
+#include "googleurl/src/gurl.h"
+
+class TabContents;
+
+namespace safe_browsing {
+
+class ClientSideDetectionService;
+
+// This class is used to receive the IPC from the renderer which
+// notifies the browser that a URL was classified as phishing. This
+// class relays this information to the client-side detection service
+// class which sends a ping to a server to validate the verdict.
+// TODO(noelutz): move all client-side detection IPCs to this class.
+class ClientSideDetectionHost : public TabContentsObserver {
+ public:
+ // The caller keeps ownership of the tab object and is responsible for
+ // ensuring that it stays valid for the entire lifetime of this object.
+ explicit ClientSideDetectionHost(TabContents* tab);
+ virtual ~ClientSideDetectionHost();
+
+ // From TabContentsObserver.
+ virtual bool OnMessageReceived(const IPC::Message& message);
+
+ // From TabContentsObserver. If we navigate away we cancel all pending
+ // callbacks that could show an interstitial.
+ virtual void DidNavigateMainFramePostCommit(
+ const NavigationController::LoadCommittedDetails& details,
+ const ViewHostMsg_FrameNavigate_Params& params);
+
+ private:
+ friend class ClientSideDetectionHostTest;
+
+ void OnDetectedPhishingSite(const GURL& phishing_url, double phishing_score);
+
+ // Callback that is called when the server ping back is
+ // done. Display an interstitial if |is_phishing| is true.
+ // Otherwise, we do nothgin. Called in UI thread.
+ void MaybeShowPhishingWarning(GURL phishing_url, bool is_phishing);
+
+ // Used for testing. This function does not take ownership of the service
+ // class.
+ void set_client_side_detection_service(ClientSideDetectionService* service);
+
+ // Used for testing. This function does not take ownership of the service
+ // class.
+ void set_safe_browsing_service(SafeBrowsingService* service);
+
+ // This pointer may be NULL if client-side phishing detection is disabled.
+ ClientSideDetectionService* service_;
+ // This pointer may be NULL if SafeBrowsing is disabled.
+ scoped_refptr<SafeBrowsingService> sb_service_;
+
+ base::ScopedCallbackFactory<ClientSideDetectionHost> cb_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientSideDetectionHost);
+};
+
+} // namespace safe_browsing
+
+#endif // CHROME_BROWSER_SAFE_BROWSING_CLIENT_SIDE_DETECTION_HOST_H_
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
new file mode 100644
index 0000000..4ed2e25
--- /dev/null
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -0,0 +1,296 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_temp_dir.h"
+#include "base/task.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/safe_browsing/client_side_detection_host.h"
+#include "chrome/browser/safe_browsing/client_side_detection_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/ui_test_utils.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock/include/gmock/gmock-spec-builders.h"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Mock;
+using ::testing::SaveArg;
+
+namespace safe_browsing {
+
+class MockClientSideDetectionService : public ClientSideDetectionService {
+ public:
+ MockClientSideDetectionService(const FilePath& model_path)
+ : ClientSideDetectionService(model_path, NULL) {}
+ virtual ~MockClientSideDetectionService() {};
+
+ MOCK_METHOD3(SendClientReportPhishingRequest,
+ void(const GURL&, double, ClientReportPhishingRequestCallback*));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
+};
+
+class MockSafeBrowsingService : public SafeBrowsingService {
+ public:
+ MockSafeBrowsingService() {}
+ virtual ~MockSafeBrowsingService() {}
+
+ MOCK_METHOD8(DisplayBlockingPage,
+ void(const GURL&, const GURL&, const std::vector<GURL>&,
+ ResourceType::Type, UrlCheckResult, Client*, int, int));
+
+ // Helper function which calls OnBlockingPageComplete for this client
+ // object.
+ void InvokeOnBlockingPageComplete(SafeBrowsingService::Client* client) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(client);
+ // Note: this will delete the client object in the case of the CsdClient
+ // implementation.
+ client->OnBlockingPageComplete(false);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingService);
+};
+
+// Helper function which quits the UI message loop from the IO message loop.
+void QuitUIMessageLoop() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ new MessageLoop::QuitTask());
+}
+
+class ClientSideDetectionHostTest : public RenderViewHostTestHarness {
+ public:
+ virtual void SetUp() {
+ RenderViewHostTestHarness::SetUp();
+ ui_thread_.reset(new BrowserThread(BrowserThread::UI, &message_loop_));
+ // Note: we're starting a real IO thread to make sure our DCHECKs that
+ // verify which thread is running are actually tested.
+ io_thread_.reset(new BrowserThread(BrowserThread::IO));
+ ASSERT_TRUE(io_thread_->Start());
+
+ // Inject service classes.
+ ScopedTempDir tmp_dir;
+ ASSERT_TRUE(tmp_dir.CreateUniqueTempDir());
+ FilePath model_path = tmp_dir.path().AppendASCII("model");
+
+ csd_service_.reset(new MockClientSideDetectionService(model_path));
+ sb_service_ = new MockSafeBrowsingService();
+ csd_host_ = contents()->safebrowsing_detection_host();
+ csd_host_->set_client_side_detection_service(csd_service_.get());
+ csd_host_->set_safe_browsing_service(sb_service_.get());
+ }
+
+ virtual void TearDown() {
+ io_thread_.reset();
+ ui_thread_.reset();
+ RenderViewHostTestHarness::TearDown();
+ }
+
+ void OnDetectedPhishingSite(const GURL& phishing_url, double phishing_score) {
+ csd_host_->OnDetectedPhishingSite(phishing_url, phishing_score);
+ }
+
+ void FlushIOMessageLoop() {
+ // If there was a message posted on the IO thread to display the
+ // interstitial page we know that it would have been posted before
+ // we put the quit message there.
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableFunction(&QuitUIMessageLoop));
+ MessageLoop::current()->Run();
+ }
+
+ protected:
+ ClientSideDetectionHost* csd_host_;
+ scoped_ptr<MockClientSideDetectionService> csd_service_;
+ scoped_refptr<MockSafeBrowsingService> sb_service_;
+
+ private:
+ scoped_ptr<BrowserThread> ui_thread_;
+ scoped_ptr<BrowserThread> io_thread_;
+};
+
+TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteNotPhishing) {
+ // Case 1: client thinks the page is phishing. The server does not agree.
+ // No interstitial is shown.
+ ClientSideDetectionService::ClientReportPhishingRequestCallback* cb;
+ GURL phishing_url("http://phishingurl.com/");
+
+ EXPECT_CALL(*csd_service_,
+ SendClientReportPhishingRequest(phishing_url, 1.0, _))
+ .WillOnce(SaveArg<2>(&cb));
+ OnDetectedPhishingSite(phishing_url, 1.0);
+ EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
+ ASSERT_TRUE(cb != NULL);
+
+ // Make sure DisplayBlockingPage is not going to be called.
+ EXPECT_CALL(*sb_service_,
+ DisplayBlockingPage(_, _, _, _, _, _, _, _)).Times(0);
+ cb->Run(phishing_url, false);
+ delete cb;
+ // If there was a message posted on the IO thread to display the
+ // interstitial page we know that it would have been posted before
+ // we put the quit message there.
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableFunction(&QuitUIMessageLoop));
+ MessageLoop::current()->Run();
+ EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
+}
+
+TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteDisabled) {
+ // Case 2: client thinks the page is phishing and so does the server but
+ // showing the interstitial is disabled => no interstitial is shown.
+ ClientSideDetectionService::ClientReportPhishingRequestCallback* cb;
+ GURL phishing_url("http://phishingurl.com/");
+
+ EXPECT_CALL(*csd_service_,
+ SendClientReportPhishingRequest(phishing_url, 1.0, _))
+ .WillOnce(SaveArg<2>(&cb));
+ OnDetectedPhishingSite(phishing_url, 1.0);
+ EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
+ ASSERT_TRUE(cb != NULL);
+
+ // Make sure DisplayBlockingPage is not going to be called.
+ EXPECT_CALL(*sb_service_,
+ DisplayBlockingPage(_, _, _, _, _, _, _, _)).Times(0);
+ cb->Run(phishing_url, false);
+ delete cb;
+
+ FlushIOMessageLoop();
+ EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
+}
+
+TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteShowInterstitial) {
+ // Case 3: client thinks the page is phishing and so does the server.
+ // We show an interstitial.
+ ClientSideDetectionService::ClientReportPhishingRequestCallback* cb;
+ GURL phishing_url("http://phishingurl.com/");
+
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableClientSidePhishingInterstitial);
+
+ EXPECT_CALL(*csd_service_,
+ SendClientReportPhishingRequest(phishing_url, 1.0, _))
+ .WillOnce(SaveArg<2>(&cb));
+ OnDetectedPhishingSite(phishing_url, 1.0);
+ EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
+ ASSERT_TRUE(cb != NULL);
+
+ SafeBrowsingService::Client* client;
+ EXPECT_CALL(*sb_service_,
+ DisplayBlockingPage(
+ phishing_url,
+ phishing_url,
+ _,
+ ResourceType::MAIN_FRAME,
+ SafeBrowsingService::URL_PHISHING,
+ _ /* a CsdClient object */,
+ contents()->GetRenderProcessHost()->id(),
+ contents()->render_view_host()->routing_id()))
+ .WillOnce(SaveArg<5>(&client));
+
+ cb->Run(phishing_url, true);
+ delete cb;
+
+ FlushIOMessageLoop();
+ EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
+
+ // Make sure the client object will be deleted.
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(
+ sb_service_.get(),
+ &MockSafeBrowsingService::InvokeOnBlockingPageComplete,
+ client));
+ // Since the CsdClient object will be deleted on the UI thread I need
+ // to run the UI message loop. Post a task to stop the UI message loop
+ // after the client object destructor is called.
+ FlushIOMessageLoop();
+}
+
+TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteMultiplePings) {
+ // Case 4 & 5: client thinks a page is phishing then navigates to
+ // another page which is also considered phishing by the client
+ // before the server responds with a verdict. After a while the
+ // server responds for both requests with a phishing verdict. Only
+ // a single interstitial is shown for the second URL.
+ ClientSideDetectionService::ClientReportPhishingRequestCallback* cb;
+ GURL phishing_url("http://phishingurl.com/");
+
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableClientSidePhishingInterstitial);
+
+ EXPECT_CALL(*csd_service_,
+ SendClientReportPhishingRequest(phishing_url, 1.0, _))
+ .WillOnce(SaveArg<2>(&cb));
+ OnDetectedPhishingSite(phishing_url, 1.0);
+ EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
+ ASSERT_TRUE(cb != NULL);
+ GURL other_phishing_url("http://other_phishing_url.com/bla");
+ // We navigate away. The callback cb should be revoked.
+ NavigateAndCommit(other_phishing_url);
+
+ ClientSideDetectionService::ClientReportPhishingRequestCallback* cb_other;
+ EXPECT_CALL(*csd_service_,
+ SendClientReportPhishingRequest(other_phishing_url, 0.8, _))
+ .WillOnce(SaveArg<2>(&cb_other));
+ OnDetectedPhishingSite(other_phishing_url, 0.8);
+ EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
+ ASSERT_TRUE(cb_other);
+
+ // We expect that the interstitial is shown for the second phishing URL and
+ // not for the first phishing URL.
+ EXPECT_CALL(*sb_service_,
+ DisplayBlockingPage(phishing_url, phishing_url,_, _, _, _, _, _))
+ .Times(0);
+ SafeBrowsingService::Client* client;
+ EXPECT_CALL(*sb_service_,
+ DisplayBlockingPage(
+ other_phishing_url,
+ other_phishing_url,
+ _,
+ ResourceType::MAIN_FRAME,
+ SafeBrowsingService::URL_PHISHING,
+ _ /* a CsdClient object */,
+ contents()->GetRenderProcessHost()->id(),
+ contents()->render_view_host()->routing_id()))
+ .WillOnce(SaveArg<5>(&client));
+
+ cb->Run(phishing_url, true); // Should have no effect.
+ delete cb;
+ cb_other->Run(other_phishing_url, true); // Should show interstitial.
+ delete cb_other;
+
+ FlushIOMessageLoop();
+ EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get()));
+
+ // Make sure the client object will be deleted.
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(
+ sb_service_.get(),
+ &MockSafeBrowsingService::InvokeOnBlockingPageComplete,
+ client));
+ // Since the CsdClient object will be deleted on the UI thread I need
+ // to run the UI message loop. Post a task to stop the UI message loop
+ // after the client object destructor is called.
+ FlushIOMessageLoop();
+}
+
+} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.cc b/chrome/browser/safe_browsing/client_side_detection_service.cc
index 6a0a99e..48bf42e 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service.cc
@@ -445,7 +445,8 @@ void ClientSideDetectionService::HandlePhishingVerdict(
info->callback->Run(info->phishing_url, response.phishy());
} else {
DLOG(ERROR) << "Unable to get the server verdict for URL: "
- << info->phishing_url;
+ << info->phishing_url << " status: " << status.status() << " "
+ << "response_code:" << response_code;
info->callback->Run(info->phishing_url, false);
}
client_phishing_reports_.erase(source);
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.h b/chrome/browser/safe_browsing/client_side_detection_service.h
index fcc823d..2c37202 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.h
+++ b/chrome/browser/safe_browsing/client_side_detection_service.h
@@ -91,11 +91,16 @@ class ClientSideDetectionService : public URLFetcher::Delegate,
// fetch. If an error occurs the phishing verdict will always be false. The
// callback is always called after SendClientReportPhishingRequest() returns
// and on the same thread as SendClientReportPhishingRequest() was called.
- void SendClientReportPhishingRequest(
+ virtual void SendClientReportPhishingRequest(
const GURL& phishing_url,
double score,
ClientReportPhishingRequestCallback* callback);
+ protected:
+ // Use Create() method to create an instance of this object.
+ ClientSideDetectionService(const FilePath& model_path,
+ URLRequestContextGetter* request_context_getter);
+
private:
friend class ClientSideDetectionServiceTest;
friend class ClientSideDetectionServiceHooksTest;
@@ -127,10 +132,6 @@ class ClientSideDetectionService : public URLFetcher::Delegate,
static const base::TimeDelta kNegativeCacheInterval;
static const base::TimeDelta kPositiveCacheInterval;
- // Use Create() method to create an instance of this object.
- ClientSideDetectionService(const FilePath& model_path,
- URLRequestContextGetter* request_context_getter);
-
// Sets the model status and invokes all the pending callbacks in
// |open_callbacks_| with the current |model_file_| as parameter.
void SetModelStatus(ModelStatus status);
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index aa095da..396df13 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -160,14 +160,14 @@ class SafeBrowsingService
// If the request contained a chain of redirects, |url| is the last url
// in the chain, and |original_url| is the first one (the root of the
// chain). Otherwise, |original_url| = |url|.
- void DisplayBlockingPage(const GURL& url,
- const GURL& original_url,
- const std::vector<GURL>& redirect_urls,
- ResourceType::Type resource_type,
- UrlCheckResult result,
- Client* client,
- int render_process_host_id,
- int render_view_id);
+ virtual void DisplayBlockingPage(const GURL& url,
+ const GURL& original_url,
+ const std::vector<GURL>& redirect_urls,
+ ResourceType::Type resource_type,
+ UrlCheckResult result,
+ Client* client,
+ int render_process_host_id,
+ int render_view_id);
// Called on the IO thread when the SafeBrowsingProtocolManager has received
// the full hash results for prefix hits detected in the database.