diff options
author | kewang@google.com <kewang@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-24 06:46:43 +0000 |
---|---|---|
committer | kewang@google.com <kewang@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-24 06:46:43 +0000 |
commit | db9b9ef42d41951c20e135b7076fb72c9869e35f (patch) | |
tree | 29072ab2e2f4fd7b60060ec625b8ce88cc61a41d /chrome/browser/safe_browsing | |
parent | 03616ddad3438ddde91cbc2c405444346fb341f3 (diff) | |
download | chromium_src-db9b9ef42d41951c20e135b7076fb72c9869e35f.zip chromium_src-db9b9ef42d41951c20e135b7076fb72c9869e35f.tar.gz chromium_src-db9b9ef42d41951c20e135b7076fb72c9869e35f.tar.bz2 |
Querying the history service to get the redirect information for urls.
Bug=60831
TEST=unit_tests
Review URL: http://codereview.chromium.org/6710004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86401 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/safe_browsing')
-rw-r--r-- | chrome/browser/safe_browsing/malware_details.cc | 35 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/malware_details.h | 15 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/malware_details_history.cc | 121 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/malware_details_history.h | 82 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/malware_details_unittest.cc | 79 |
5 files changed, 329 insertions, 3 deletions
diff --git a/chrome/browser/safe_browsing/malware_details.cc b/chrome/browser/safe_browsing/malware_details.cc index 63d3f3a..bc35cec 100644 --- a/chrome/browser/safe_browsing/malware_details.cc +++ b/chrome/browser/safe_browsing/malware_details.cc @@ -11,6 +11,7 @@ #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/malware_details_cache.h" +#include "chrome/browser/safe_browsing/malware_details_history.h" #include "chrome/browser/safe_browsing/report.pb.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/common/safe_browsing/safebrowsing_messages.h" @@ -76,7 +77,8 @@ MalwareDetails::MalwareDetails( request_context_getter_(tab_contents->profile()->GetRequestContext()), sb_service_(sb_service), resource_(resource), - cache_collector_(new MalwareDetailsCacheCollector) { + cache_collector_(new MalwareDetailsCacheCollector), + redirects_collector_(new MalwareDetailsRedirectsCollector) { StartCollection(); } @@ -224,6 +226,11 @@ void MalwareDetails::AddDOMDetails( DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << "Nodes from the DOM: " << params.size(); + // If we have already started getting redirects from history service, + // don't modify state, otherwise will invalidate the iterators. + if (redirects_collector_->HasStarted()) + return; + // If we have already started collecting data from the HTTP cache, don't // modify our state. if (cache_collector_->HasStarted()) @@ -246,6 +253,25 @@ void MalwareDetails::AddDOMDetails( void MalwareDetails::FinishCollection() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + std::vector<GURL> urls; + for (safe_browsing::ResourceMap::const_iterator it = resources_.begin(); + it != resources_.end(); it++) { + urls.push_back(GURL(it->first)); + } + redirects_collector_->StartHistoryCollection( + urls, tab_contents(), + NewRunnableMethod(this, &MalwareDetails::OnRedirectionCollectionReady)); +} + +void MalwareDetails::OnRedirectionCollectionReady() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + const std::vector<safe_browsing::RedirectChain>& redirects = + redirects_collector_->GetCollectedUrls(); + + for (size_t i = 0; i < redirects.size(); ++i) + AddRedirectUrlList(redirects[i]); + + // Call the cache collector cache_collector_->StartCacheCollection( request_context_getter_, &resources_, @@ -253,6 +279,13 @@ void MalwareDetails::FinishCollection() { NewRunnableMethod(this, &MalwareDetails::OnCacheCollectionReady)); } +void MalwareDetails::AddRedirectUrlList(const std::vector<GURL>& urls) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + for (size_t i = 0; i < urls.size()-1; ++i) { + AddUrl(urls[i], urls[i+1], "", NULL); + } +} + void MalwareDetails::OnCacheCollectionReady() { DVLOG(1) << "OnCacheCollectionReady."; // Add all the urls in our |resources_| maps to the |report_| protocol buffer. diff --git a/chrome/browser/safe_browsing/malware_details.h b/chrome/browser/safe_browsing/malware_details.h index 494837e..473eab8 100644 --- a/chrome/browser/safe_browsing/malware_details.h +++ b/chrome/browser/safe_browsing/malware_details.h @@ -21,6 +21,7 @@ #include "base/memory/scoped_ptr.h" #include "chrome/browser/safe_browsing/report.pb.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" +#include "content/browser/browser_thread.h" #include "content/browser/tab_contents/tab_contents_observer.h" #include "net/base/completion_callback.h" @@ -28,6 +29,7 @@ class TabContents; struct SafeBrowsingHostMsg_MalwareDOMDetails_Node; class MalwareDetailsCacheCollector; +class MalwareDetailsRedirectsCollector; class MalwareDetailsFactory; namespace safe_browsing { @@ -54,12 +56,15 @@ class MalwareDetails : public base::RefCountedThreadSafe<MalwareDetails>, // The SafeBrowsingBlockingPage calls this from the IO thread when // the user is leaving the blocking page and has opted-in to sending - // the report. We start the cache collection, and when we are done, - // we send the report. + // the report. We start the redirection urls collection from history service + // in UI thread; then do cache collection back in IO thread. + // When we are done, we send the report. void FinishCollection(); void OnCacheCollectionReady(); + void OnRedirectionCollectionReady(); + // TabContentsObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message); @@ -108,6 +113,8 @@ class MalwareDetails : public base::RefCountedThreadSafe<MalwareDetails>, void OnReceivedMalwareDOMDetails( const std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>& params); + void AddRedirectUrlList(const std::vector<GURL>& urls); + scoped_refptr<SafeBrowsingService> sb_service_; const SafeBrowsingService::UnsafeResource resource_; @@ -127,9 +134,13 @@ class MalwareDetails : public base::RefCountedThreadSafe<MalwareDetails>, // Used to collect details from the HTTP Cache. scoped_refptr<MalwareDetailsCacheCollector> cache_collector_; + // Used to collect redirect urls from the history service + scoped_refptr<MalwareDetailsRedirectsCollector> redirects_collector_; + FRIEND_TEST_ALL_PREFIXES(MalwareDetailsTest, MalwareDOMDetails); FRIEND_TEST_ALL_PREFIXES(MalwareDetailsTest, HTTPCache); FRIEND_TEST_ALL_PREFIXES(MalwareDetailsTest, HTTPCacheNoEntries); + FRIEND_TEST_ALL_PREFIXES(MalwareDetailsTest, HistoryServiceUrls); DISALLOW_COPY_AND_ASSIGN(MalwareDetails); }; diff --git a/chrome/browser/safe_browsing/malware_details_history.cc b/chrome/browser/safe_browsing/malware_details_history.cc new file mode 100644 index 0000000..e28c729 --- /dev/null +++ b/chrome/browser/safe_browsing/malware_details_history.cc @@ -0,0 +1,121 @@ +// 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. +// +// Implementation of the MalwareDetailsRedirectsCollector class. + +#include "chrome/browser/safe_browsing/malware_details_history.h" + +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/malware_details.h" +#include "content/browser/browser_thread.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/tab_contents/navigation_entry.h" +#include "content/browser/tab_contents/tab_contents.h" + + +MalwareDetailsRedirectsCollector::MalwareDetailsRedirectsCollector() + : history_(NULL), + has_started_(false) { +} + +MalwareDetailsRedirectsCollector::~MalwareDetailsRedirectsCollector() { +} + +void MalwareDetailsRedirectsCollector::StartHistoryCollection( + const std::vector<GURL>& urls, + TabContents* tab_contents, + Task* callback) { + DVLOG(1) << "Num of urls to check in history service: " << urls.size(); + tab_contents_ = tab_contents; + has_started_ = true; + callback_ = callback; + + if (urls.size() == 0) { + AllDone(); + return; + } + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod( + this, &MalwareDetailsRedirectsCollector::StartGetRedirects, urls)); +} + +void MalwareDetailsRedirectsCollector::StartGetRedirects( + const std::vector<GURL>& urls) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // History access from profile needs to happen in UI thread + if (history_ == NULL) { + DVLOG(1) << "Getting access to history service"; + history_ = tab_contents_->profile()->GetHistoryService( + Profile::EXPLICIT_ACCESS); + } + + if (history_ == NULL) { + DVLOG(1) << "Could not access history service."; + AllDone(); + return; + } + + for (size_t i = 0; i < urls.size(); ++i) + urls_.push_back(urls[i]); + + urls_it_ = urls_.begin(); + GetRedirects(*urls_it_); +} + +void MalwareDetailsRedirectsCollector::GetRedirects(const GURL& url) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + history_->QueryRedirectsTo( + url, + &request_consumer_, + NewCallback(this, + &MalwareDetailsRedirectsCollector::OnGotQueryRedirectsTo)); +} + +void MalwareDetailsRedirectsCollector::OnGotQueryRedirectsTo( + HistoryService::Handle handle, + GURL url, + bool success, + history::RedirectList* redirect_list) { + + if (success && redirect_list->size() > 0) { + std::vector<GURL> urllist; + urllist.push_back(url); + for (size_t i = 0; i < redirect_list->size(); i++) { + urllist.push_back(redirect_list->at(i)); + } + redirects_urls_.push_back(urllist); + } + + // Proceed to next url + ++urls_it_; + + if (urls_it_ == urls_.end()) { + AllDone(); + return; + } + + GetRedirects(*urls_it_); +} + +bool MalwareDetailsRedirectsCollector::HasStarted() const { + return has_started_; +} + +void MalwareDetailsRedirectsCollector::AllDone() { + DVLOG(1) << "AllDone"; + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback_); +} + +const std::vector<safe_browsing::RedirectChain>& +MalwareDetailsRedirectsCollector::GetCollectedUrls() const { + return redirects_urls_; +} + +void MalwareDetailsRedirectsCollector::SetHistory(HistoryService* history) { + history_ = history; +} diff --git a/chrome/browser/safe_browsing/malware_details_history.h b/chrome/browser/safe_browsing/malware_details_history.h new file mode 100644 index 0000000..23a2571 --- /dev/null +++ b/chrome/browser/safe_browsing/malware_details_history.h @@ -0,0 +1,82 @@ +// 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_MALWARE_DETAILS_HISTORY_H_ +#define CHROME_BROWSER_SAFE_BROWSING_MALWARE_DETAILS_HISTORY_H_ +#pragma once + +// This class gets redirect chain for urls from the history service. + +#include <string> +#include <vector> + +#include "base/hash_tables.h" +#include "base/memory/linked_ptr.h" +#include "base/memory/ref_counted.h" +#include "chrome/browser/history/history.h" +#include "net/base/completion_callback.h" + +class TabContents; + +namespace safe_browsing { +typedef std::vector<GURL> RedirectChain; +} + +class MalwareDetailsRedirectsCollector + : public base::RefCountedThreadSafe<MalwareDetailsRedirectsCollector> { + + public: + MalwareDetailsRedirectsCollector(); + virtual ~MalwareDetailsRedirectsCollector(); + + // Collects urls' redirects chain information from the history service. + // We get access to history service via tab_contents in UI thread. + // Notice the callback will be posted to the IO thread. + void StartHistoryCollection(const std::vector<GURL>& urls, + TabContents* tab_contents, + Task* callback); + + // Returns whether or not StartCacheCollection has been called. + bool HasStarted() const; + + // Returns the redirect urls we get from history service + const std::vector<safe_browsing::RedirectChain>& GetCollectedUrls() const; + + // Sets the pointer to the history service. Use it in unittest. + void SetHistory(HistoryService* history); + + private: + TabContents* tab_contents_; + HistoryService* history_; + CancelableRequestConsumer request_consumer_; + + // Method we call when we are done. The caller must be alive for the + // whole time, we are modifying its state (see above). + Task* callback_; + + // Sets to true once StartHistoryCollection is called + bool has_started_; + + // The urls we need to get redirects for + std::vector<GURL> urls_; + // The iterator goes over urls_ + std::vector<GURL>::iterator urls_it_; + // The collected directs from history service + std::vector<safe_browsing::RedirectChain> redirects_urls_; + + void StartGetRedirects(const std::vector<GURL>& urls); + void GetRedirects(const GURL& url); + void OnGotQueryRedirectsTo(HistoryService::Handle handle, + GURL url, + bool success, + history::RedirectList* redirect_list); + + // Posts the callback method back to IO thread when redirects collecting + // is all done. + void AllDone(); + + DISALLOW_COPY_AND_ASSIGN(MalwareDetailsRedirectsCollector); +}; + +#endif // CHROME_BROWSER_SAFE_BROWSING_MALWARE_DETAILS_HISTORY_H_ diff --git a/chrome/browser/safe_browsing/malware_details_unittest.cc b/chrome/browser/safe_browsing/malware_details_unittest.cc index 73ccfdd..60a65f8 100644 --- a/chrome/browser/safe_browsing/malware_details_unittest.cc +++ b/chrome/browser/safe_browsing/malware_details_unittest.cc @@ -6,8 +6,11 @@ #include "base/pickle.h" #include "base/time.h" +#include "chrome/browser/history/history.h" +#include "chrome/browser/history/history_backend.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/malware_details.h" +#include "chrome/browser/safe_browsing/malware_details_history.h" #include "chrome/browser/safe_browsing/report.pb.h" #include "chrome/common/render_messages.h" #include "chrome/common/safe_browsing/safebrowsing_messages.h" @@ -176,10 +179,13 @@ class MalwareDetailsTest : public RenderViewHostTestHarness { // The URLFetcher checks that the messageloop type is IO. ASSERT_TRUE(io_thread_.StartWithOptions( base::Thread::Options(MessageLoop::TYPE_IO, 0))); + + profile_->CreateHistoryService(true /* delete_file */, false /* no_db */); } virtual void TearDown() { io_thread_.Stop(); + profile_->DestroyHistoryService(); RenderViewHostTestHarness::TearDown(); } @@ -201,6 +207,10 @@ class MalwareDetailsTest : public RenderViewHostTestHarness { return sb_service_->GetSerialized(); } + HistoryService* history_service() { + return profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); + } + protected: void InitResource(SafeBrowsingService::UnsafeResource* resource, ResourceType::Type resource_type, @@ -283,6 +293,18 @@ class MalwareDetailsTest : public RenderViewHostTestHarness { resource->response().remote_ip()); } + // Adds a page to history. + // The redirects is the redirect url chain leading to the url. + void AddPageToHistory(const GURL& url, + history::RedirectList* redirects) { + // The last item of the redirect chain has to be the final url when adding + // to history backend. + redirects->push_back(url); + history_service()->AddPage( + url, static_cast<void*>(this), 0, GURL(), PageTransition::TYPED, + *redirects, history::SOURCE_BROWSED, false); + } + BrowserThread ui_thread_; BrowserThread io_thread_; scoped_refptr<MockSafeBrowsingService> sb_service_; @@ -603,3 +625,60 @@ TEST_F(MalwareDetailsTest, HTTPCacheNoEntries) { VerifyResults(actual, expected); } + +// Test getting redirects from history service. +TEST_F(MalwareDetailsTest, HistoryServiceUrls) { + // Add content to history service. + // There are two redirect urls before reacing malware url: + // kFirstRedirectURL -> kSecondRedirectURL -> kMalwareURL + GURL baseurl(kMalwareURL); + history::RedirectList redirects; + redirects.push_back(GURL(kFirstRedirectURL)); + redirects.push_back(GURL(kSecondRedirectURL)); + AddPageToHistory(baseurl, &redirects); + // Wait for history service operation finished. + profile_->BlockUntilHistoryProcessesPendingRequests(); + + controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED); + + SafeBrowsingService::UnsafeResource resource; + InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL)); + scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap( + sb_service_.get(), contents(), resource, NULL); + + // Reset the history service pointer. + report->redirects_collector_->SetHistory(history_service()); + + // The redirects collection starts after the IPC from the DOM is fired. + std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params; + report->OnReceivedMalwareDOMDetails(params); + + // Let the redirects callbacks complete. + MessageLoop::current()->RunAllPending(); + + std::string serialized = WaitForSerializedReport(report); + ClientMalwareReportRequest actual; + actual.ParseFromString(serialized); + + ClientMalwareReportRequest expected; + expected.set_malware_url(kMalwareURL); + expected.set_page_url(kLandingURL); + expected.set_referrer_url(""); + + ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources(); + pb_resource->set_id(0); + pb_resource->set_url(kLandingURL); + pb_resource = expected.add_resources(); + pb_resource->set_id(1); + pb_resource->set_parent_id(2); + pb_resource->set_url(kMalwareURL); + pb_resource = expected.add_resources(); + pb_resource->set_id(2); + pb_resource->set_parent_id(3); + pb_resource->set_url(kSecondRedirectURL); + pb_resource = expected.add_resources(); + pb_resource->set_id(3); + pb_resource->set_url(kFirstRedirectURL); + + VerifyResults(actual, expected); +} |