| Index: chrome/browser/safe_browsing/malware_details_unittest.cc
|
| ===================================================================
|
| --- chrome/browser/safe_browsing/malware_details_unittest.cc (revision 80624)
|
| +++ chrome/browser/safe_browsing/malware_details_unittest.cc (working copy)
|
| @@ -4,34 +4,191 @@
|
|
|
| #include <algorithm>
|
|
|
| +#include "base/pickle.h"
|
| +#include "base/time.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/safe_browsing/malware_details.h"
|
| #include "chrome/browser/safe_browsing/report.pb.h"
|
| +#include "chrome/common/render_messages.h"
|
| #include "chrome/common/safebrowsing_messages.h"
|
| +#include "chrome/test/testing_profile.h"
|
| #include "content/browser/browser_thread.h"
|
| #include "content/browser/renderer_host/test_render_view_host.h"
|
| #include "content/browser/tab_contents/navigation_entry.h"
|
| #include "content/browser/tab_contents/test_tab_contents.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/base/test_completion_callback.h"
|
| +#include "net/disk_cache/disk_cache.h"
|
| +#include "net/http/http_cache.h"
|
| +#include "net/http/http_response_info.h"
|
| +#include "net/http/http_response_headers.h"
|
| +#include "net/http/http_util.h"
|
| +#include "net/url_request/url_request_context.h"
|
| +#include "net/url_request/url_request_context_getter.h"
|
|
|
| static const char* kOriginalLandingURL = "http://www.originallandingpage.com/";
|
| -static const char* kLandingURL = "http://www.landingpage.com/";
|
| -static const char* kMalwareURL = "http://www.malware.com/";
|
| static const char* kHttpsURL = "https://www.url.com/";
|
| static const char* kDOMChildURL = "http://www.domparent.com/";
|
| static const char* kDOMParentURL = "http://www.domchild.com/";
|
| static const char* kFirstRedirectURL = "http://redirectone.com/";
|
| static const char* kSecondRedirectURL = "http://redirecttwo.com/";
|
|
|
| +static const char* kMalwareURL = "http://www.malware.com/";
|
| +static const char* kMalwareHeaders =
|
| + "HTTP/1.1 200 OK\n"
|
| + "Content-Type: image/jpeg\n";
|
| +static const char* kMalwareData = "exploit();";
|
| +
|
| +static const char* kLandingURL = "http://www.landingpage.com/";
|
| +static const char* kLandingHeaders =
|
| + "HTTP/1.1 200 OK\n"
|
| + "Content-Type: text/html\n"
|
| + "Content-Length: 1024\n"
|
| + "Set-Cookie: tastycookie\n"; // This header is stripped.
|
| +static const char* kLandingData = "<iframe src='http://www.malware.com'>";
|
| +
|
| using safe_browsing::ClientMalwareReportRequest;
|
|
|
| -class MalwareDetailsTest : public RenderViewHostTestHarness {
|
| +namespace {
|
| +
|
| +class MockURLRequestContext : public net::URLRequestContext {
|
| public:
|
| + MockURLRequestContext()
|
| + : cache_(reinterpret_cast<net::HttpTransactionFactory*>(NULL), NULL,
|
| + net::HttpCache::DefaultBackend::InMemory(0)) {
|
| + set_http_transaction_factory(&cache_);
|
| + }
|
| +
|
| + private:
|
| + net::HttpCache cache_;
|
| +};
|
| +
|
| +void WriteHeaders(disk_cache::Entry* entry, const std::string headers) {
|
| + net::HttpResponseInfo responseinfo;
|
| + std::string raw_headers = net::HttpUtil::AssembleRawHeaders(
|
| + headers.c_str(), headers.size());
|
| + responseinfo.headers = new net::HttpResponseHeaders(raw_headers);
|
| +
|
| + Pickle pickle;
|
| + responseinfo.Persist(&pickle, false, false);
|
| +
|
| + scoped_refptr<net::WrappedIOBuffer> buf(new net::WrappedIOBuffer(
|
| + reinterpret_cast<const char*>(pickle.data())));
|
| + int len = static_cast<int>(pickle.size());
|
| +
|
| + TestCompletionCallback cb;
|
| + int rv = entry->WriteData(0, 0, buf, len, &cb, true);
|
| + ASSERT_EQ(len, cb.GetResult(rv));
|
| +}
|
| +
|
| +void WriteData(disk_cache::Entry* entry, const std::string data) {
|
| + if (data.empty())
|
| + return;
|
| +
|
| + int len = data.length();
|
| + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(len));
|
| + memcpy(buf->data(), data.data(), data.length());
|
| +
|
| + TestCompletionCallback cb;
|
| + int rv = entry->WriteData(1, 0, buf, len, &cb, true);
|
| + ASSERT_EQ(len, cb.GetResult(rv));
|
| +}
|
| +
|
| +void WriteToEntry(disk_cache::Backend* cache, const std::string key,
|
| + const std::string headers, const std::string data) {
|
| + TestCompletionCallback cb;
|
| + disk_cache::Entry* entry;
|
| + int rv = cache->CreateEntry(key, &entry, &cb);
|
| + rv = cb.GetResult(rv);
|
| + if (rv != net::OK) {
|
| + rv = cache->OpenEntry(key, &entry, &cb);
|
| + ASSERT_EQ(net::OK, cb.GetResult(rv));
|
| + }
|
| +
|
| + WriteHeaders(entry, headers);
|
| + WriteData(entry, data);
|
| +
|
| + entry->Close();
|
| +}
|
| +
|
| +void FillCache(net::URLRequestContext* context) {
|
| + TestCompletionCallback cb;
|
| + disk_cache::Backend* cache;
|
| + int rv =
|
| + context->http_transaction_factory()->GetCache()->GetBackend(&cache, &cb);
|
| + ASSERT_EQ(net::OK, cb.GetResult(rv));
|
| +
|
| + std::string empty;
|
| + WriteToEntry(cache, kMalwareURL, kMalwareHeaders, kMalwareData);
|
| + WriteToEntry(cache, kLandingURL, kLandingHeaders, kLandingData);
|
| +}
|
| +
|
| +class TestURLRequestContextGetter : public net::URLRequestContextGetter {
|
| + public:
|
| + virtual net::URLRequestContext* GetURLRequestContext() {
|
| + if (!context_)
|
| + context_ = new MockURLRequestContext();
|
| + return context_;
|
| + }
|
| + virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const {
|
| + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
|
| + }
|
| +
|
| + private:
|
| + ~TestURLRequestContextGetter() {}
|
| + scoped_refptr<MockURLRequestContext> context_;
|
| +};
|
| +
|
| +// Lets us provide a MockURLRequestContext and an InMemory HTTP Cache.
|
| +// Also exposes the constructor.
|
| +class MalwareDetailsWrap : public MalwareDetails {
|
| + public:
|
| + MalwareDetailsWrap(SafeBrowsingService* sb_service,
|
| + TabContents* tab_contents,
|
| + const SafeBrowsingService::UnsafeResource& unsafe_resource,
|
| + net::URLRequestContextGetter* request_context_getter)
|
| + : MalwareDetails(sb_service, tab_contents, unsafe_resource) {
|
| + request_context_getter_ = request_context_getter;
|
| + }
|
| +
|
| + virtual ~MalwareDetailsWrap() {}
|
| +};
|
| +
|
| +class MockSafeBrowsingService : public SafeBrowsingService {
|
| + public:
|
| + MockSafeBrowsingService() {}
|
| + virtual ~MockSafeBrowsingService() {}
|
| +
|
| + // When the MalwareDetails is done, this is called.
|
| + virtual void SendSerializedMalwareDetails(const std::string& serialized) {
|
| + // Notify WaitForSerializedReport.
|
| + MessageLoop::current()->Quit();
|
| + serialized_ = serialized;
|
| + }
|
| +
|
| + const std::string& GetSerialized() {
|
| + return serialized_;
|
| + }
|
| +
|
| + private:
|
| + std::string serialized_;
|
| + DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingService);
|
| +};
|
| +
|
| +} // namespace.
|
| +
|
| +class MalwareDetailsTest :
|
| + public RenderViewHostTestHarness {
|
| + public:
|
| MalwareDetailsTest()
|
| : ui_thread_(BrowserThread::UI, MessageLoop::current()),
|
| - io_thread_(BrowserThread::IO, MessageLoop::current()) {
|
| + io_thread_(BrowserThread::IO, MessageLoop::current()),
|
| + sb_service_(new MockSafeBrowsingService()) {
|
| }
|
|
|
| virtual void SetUp() {
|
| RenderViewHostTestHarness::SetUp();
|
| + request_context_getter_ = new TestURLRequestContextGetter();
|
| }
|
|
|
| static bool ResourceLessThan(
|
| @@ -40,6 +197,13 @@
|
| return lhs->id() < rhs->id();
|
| }
|
|
|
| + std::string WaitForSerializedReport(MalwareDetails* report) {
|
| + report->FinishCollection();
|
| + // Wait for the callback (SendSerializedMalwareDetails).
|
| + MessageLoop::current()->Run();
|
| + return sb_service_->GetSerialized();
|
| + }
|
| +
|
| protected:
|
| void InitResource(SafeBrowsingService::UnsafeResource* resource,
|
| ResourceType::Type resource_type,
|
| @@ -79,18 +243,49 @@
|
| &MalwareDetailsTest::ResourceLessThan);
|
|
|
| for (uint32 i = 0; i < expected.size(); ++i) {
|
| - EXPECT_EQ(expected[i]->id(), resources[i]->id());
|
| - EXPECT_EQ(expected[i]->url(), resources[i]->url());
|
| - EXPECT_EQ(expected[i]->parent_id(), resources[i]->parent_id());
|
| - ASSERT_EQ(expected[i]->child_ids_size(), resources[i]->child_ids_size());
|
| - for (int j = 0; j < expected[i]->child_ids_size(); j++) {
|
| - EXPECT_EQ(expected[i]->child_ids(j), resources[i]->child_ids(j));
|
| + VerifyResource(resources[i], expected[i]);
|
| + }
|
| +
|
| + EXPECT_EQ(expected_pb.complete(), report_pb.complete());
|
| + }
|
| +
|
| + void VerifyResource(const ClientMalwareReportRequest::Resource* resource,
|
| + const ClientMalwareReportRequest::Resource* expected) {
|
| + EXPECT_EQ(expected->id(), resource->id());
|
| + EXPECT_EQ(expected->url(), resource->url());
|
| + EXPECT_EQ(expected->parent_id(), resource->parent_id());
|
| + ASSERT_EQ(expected->child_ids_size(), resource->child_ids_size());
|
| + for (int i = 0; i < expected->child_ids_size(); i++) {
|
| + EXPECT_EQ(expected->child_ids(i), resource->child_ids(i));
|
| + }
|
| +
|
| + // Verify HTTP Responses
|
| + if (expected->has_response()) {
|
| + ASSERT_TRUE(resource->has_response());
|
| + EXPECT_EQ(expected->response().firstline().code(),
|
| + resource->response().firstline().code());
|
| +
|
| + ASSERT_EQ(expected->response().headers_size(),
|
| + resource->response().headers_size());
|
| + for (int i = 0; i < expected->response().headers_size(); ++i) {
|
| + EXPECT_EQ(expected->response().headers(i).name(),
|
| + resource->response().headers(i).name());
|
| + EXPECT_EQ(expected->response().headers(i).value(),
|
| + resource->response().headers(i).value());
|
| }
|
| +
|
| + EXPECT_EQ(expected->response().body(), resource->response().body());
|
| + EXPECT_EQ(expected->response().bodylength(),
|
| + resource->response().bodylength());
|
| + EXPECT_EQ(expected->response().bodydigest(),
|
| + resource->response().bodydigest());
|
| }
|
| }
|
|
|
| BrowserThread ui_thread_;
|
| BrowserThread io_thread_;
|
| + scoped_refptr<MockSafeBrowsingService> sb_service_;
|
| + scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
| };
|
|
|
| // Tests creating a simple malware report.
|
| @@ -101,12 +296,13 @@
|
| SafeBrowsingService::UnsafeResource resource;
|
| InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
|
|
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
|
| + sb_service_, contents(), resource, NULL);
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + std::string serialized = WaitForSerializedReport(report);
|
| +
|
| ClientMalwareReportRequest actual;
|
| - actual.ParseFromString(*serialized);
|
| + actual.ParseFromString(serialized);
|
|
|
| ClientMalwareReportRequest expected;
|
| expected.set_malware_url(kMalwareURL);
|
| @@ -132,12 +328,13 @@
|
| InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
|
| resource.original_url = GURL(kOriginalLandingURL);
|
|
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
|
| + sb_service_.get(), contents(), resource, NULL);
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + std::string serialized = WaitForSerializedReport(report);
|
| +
|
| ClientMalwareReportRequest actual;
|
| - actual.ParseFromString(*serialized);
|
| + actual.ParseFromString(serialized);
|
|
|
| ClientMalwareReportRequest expected;
|
| expected.set_malware_url(kMalwareURL);
|
| @@ -169,8 +366,8 @@
|
| SafeBrowsingService::UnsafeResource resource;
|
| InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
|
|
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
|
| + sb_service_.get(), contents(), resource, NULL);
|
|
|
| // Send a message from the DOM, with 2 nodes, a parent and a child.
|
| std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
|
| @@ -187,9 +384,9 @@
|
|
|
| MessageLoop::current()->RunAllPending();
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + std::string serialized = WaitForSerializedReport(report);
|
| ClientMalwareReportRequest actual;
|
| - actual.ParseFromString(*serialized);
|
| + actual.ParseFromString(serialized);
|
|
|
| ClientMalwareReportRequest expected;
|
| expected.set_malware_url(kMalwareURL);
|
| @@ -213,6 +410,7 @@
|
| pb_resource->set_id(3);
|
| pb_resource->set_url(kDOMParentURL);
|
| pb_resource->add_child_ids(2);
|
| + expected.set_complete(false); // Since the cache was missing.
|
|
|
| VerifyResults(actual, expected);
|
| }
|
| @@ -222,12 +420,12 @@
|
| controller().LoadURL(GURL(kHttpsURL), GURL(), PageTransition::TYPED);
|
| SafeBrowsingService::UnsafeResource resource;
|
| InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
|
| + sb_service_.get(), contents(), resource, NULL);
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + std::string serialized = WaitForSerializedReport(report);
|
| ClientMalwareReportRequest actual;
|
| - actual.ParseFromString(*serialized);
|
| + actual.ParseFromString(serialized);
|
|
|
| ClientMalwareReportRequest expected;
|
| expected.set_malware_url(kMalwareURL); // No page_url
|
| @@ -253,12 +451,12 @@
|
| resource.redirect_urls.push_back(GURL(kSecondRedirectURL));
|
| resource.redirect_urls.push_back(GURL(kMalwareURL));
|
|
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
|
| + sb_service_.get(), contents(), resource, NULL);
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + std::string serialized = WaitForSerializedReport(report);
|
| ClientMalwareReportRequest actual;
|
| - actual.ParseFromString(*serialized);
|
| + actual.ParseFromString(serialized);
|
|
|
| ClientMalwareReportRequest expected;
|
| expected.set_malware_url(kMalwareURL);
|
| @@ -290,3 +488,108 @@
|
|
|
| VerifyResults(actual, expected);
|
| }
|
| +
|
| +// Tests the interaction with the HTTP cache.
|
| +TEST_F(MalwareDetailsTest, HTTPCache) {
|
| + 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, request_context_getter_.get());
|
| +
|
| + FillCache(request_context_getter_->GetURLRequestContext());
|
| +
|
| + // The cache collection starts after the IPC from the DOM is fired.
|
| + std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
|
| + report->OnReceivedMalwareDOMDetails(params);
|
| +
|
| + // Let the cache callbacks complete
|
| + MessageLoop::current()->RunAllPending();
|
| +
|
| + DVLOG(1) << "Getting serialized report";
|
| + 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);
|
| + safe_browsing::ClientMalwareReportRequest::HTTPResponse* pb_response =
|
| + pb_resource->mutable_response();
|
| + pb_response->mutable_firstline()->set_code(200);
|
| + safe_browsing::ClientMalwareReportRequest::HTTPHeader* pb_header =
|
| + pb_response->add_headers();
|
| + pb_header->set_name("Content-Type");
|
| + pb_header->set_value("text/html");
|
| + pb_header = pb_response->add_headers();
|
| + pb_header->set_name("Content-Length");
|
| + pb_header->set_value("1024");
|
| + pb_header = pb_response->add_headers();
|
| + pb_header->set_name("Set-Cookie");
|
| + pb_header->set_value(""); // The cookie is dropped.
|
| + pb_response->set_body(kLandingData);
|
| + pb_response->set_bodylength(37);
|
| + pb_response->set_bodydigest("9ca97475598a79bc1e8fc9bd6c72cd35");
|
| +
|
| + pb_resource = expected.add_resources();
|
| + pb_resource->set_id(1);
|
| + pb_resource->set_url(kMalwareURL);
|
| + pb_response = pb_resource->mutable_response();
|
| + pb_response->mutable_firstline()->set_code(200);
|
| + pb_header = pb_response->add_headers();
|
| + pb_header->set_name("Content-Type");
|
| + pb_header->set_value("image/jpeg");
|
| + pb_response->set_body(kMalwareData);
|
| + pb_response->set_bodylength(10);
|
| + pb_response->set_bodydigest("581373551c43d4cf33bfb3b26838ff95");
|
| + expected.set_complete(true);
|
| +
|
| + VerifyResults(actual, expected);
|
| +}
|
| +
|
| +// Tests the interaction with the HTTP cache (where the cache is empty).
|
| +TEST_F(MalwareDetailsTest, HTTPCacheNoEntries) {
|
| + 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, request_context_getter_.get());
|
| +
|
| + // No call to FillCache
|
| +
|
| + // The cache collection starts after the IPC from the DOM is fired.
|
| + std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
|
| + report->OnReceivedMalwareDOMDetails(params);
|
| +
|
| + // Let the cache callbacks complete
|
| + MessageLoop::current()->RunAllPending();
|
| +
|
| + DVLOG(1) << "Getting serialized report";
|
| + 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_url(kMalwareURL);
|
| + expected.set_complete(true);
|
| +
|
| + VerifyResults(actual, expected);
|
| +}
|
|
|