| Index: chrome/browser/safe_browsing/malware_details_unittest.cc
|
| ===================================================================
|
| --- chrome/browser/safe_browsing/malware_details_unittest.cc (revision 76771)
|
| +++ chrome/browser/safe_browsing/malware_details_unittest.cc (working copy)
|
| @@ -4,28 +4,156 @@
|
|
|
| #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/render_messages_params.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"
|
|
|
| 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 dropped.
|
| +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);
|
| +}
|
| +
|
| +// Lets us provide a MockURLRequestContext and an InMemory HTTP Cache.
|
| +// Also exposes the constructor.
|
| +class MalwareDetailsWrap : public MalwareDetails {
|
| + public:
|
| + MalwareDetailsWrap(TabContents* tab_contents,
|
| + const SafeBrowsingService::UnsafeResource& unsafe_resource,
|
| + bool provide_cache)
|
| + : MalwareDetails(tab_contents, unsafe_resource),
|
| + request_context_(new MockURLRequestContext()),
|
| + provide_cache_(provide_cache) {
|
| + }
|
| +
|
| + virtual ~MalwareDetailsWrap() {}
|
| +
|
| + virtual net::URLRequestContext* GetURLRequestContext() {
|
| + if (provide_cache_) {
|
| + return request_context_;
|
| + }
|
| + return NULL;
|
| + }
|
| +
|
| + private:
|
| + MockURLRequestContext* request_context_;
|
| + bool provide_cache_;
|
| +};
|
| +
|
| +} // namespace.
|
| +
|
| +class MalwareDetailsTest :
|
| + public RenderViewHostTestHarness {
|
| + // public base::RefCountedThreadSafe<MalwareDetailsTest> {
|
| + public:
|
| MalwareDetailsTest()
|
| : ui_thread_(BrowserThread::UI, MessageLoop::current()),
|
| io_thread_(BrowserThread::IO, MessageLoop::current()) {
|
| @@ -41,6 +169,18 @@
|
| return lhs->id() < rhs->id();
|
| }
|
|
|
| + const std::string* WaitForSerializedReport(MalwareDetails* report) {
|
| + report->StartCacheCollection(
|
| + NewCallback(this, &MalwareDetailsTest::OnReportReady));
|
| + MessageLoop::current()->Run(); // Waits for the callback.
|
| + return report->GetSerializedReport();
|
| + }
|
| +
|
| + void OnReportReady(scoped_refptr<MalwareDetails> report) {
|
| + LOG(ERROR) << "OnReportReady";
|
| + MessageLoop::current()->Quit();
|
| + }
|
| +
|
| protected:
|
| void InitResource(SafeBrowsingService::UnsafeResource* resource,
|
| ResourceType::Type resource_type,
|
| @@ -80,13 +220,42 @@
|
| &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());
|
| }
|
| }
|
|
|
| @@ -102,10 +271,11 @@
|
| SafeBrowsingService::UnsafeResource resource;
|
| InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
|
|
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetails> report = new MalwareDetailsWrap(
|
| + contents(), resource, false);
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + scoped_ptr<const std::string> serialized(WaitForSerializedReport(report));
|
| +
|
| ClientMalwareReportRequest actual;
|
| actual.ParseFromString(*serialized);
|
|
|
| @@ -133,10 +303,10 @@
|
| InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
|
| resource.original_url = GURL(kOriginalLandingURL);
|
|
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetails> report = new MalwareDetailsWrap(
|
| + contents(), resource, false);
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + scoped_ptr<const std::string> serialized(WaitForSerializedReport(report));
|
| ClientMalwareReportRequest actual;
|
| actual.ParseFromString(*serialized);
|
|
|
| @@ -170,8 +340,8 @@
|
| SafeBrowsingService::UnsafeResource resource;
|
| InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
|
|
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetails> report = new MalwareDetailsWrap(
|
| + contents(), resource, false);
|
|
|
| // Send a message from the DOM, with 2 nodes, a parent and a child.
|
| ViewHostMsg_MalwareDOMDetails_Params params;
|
| @@ -188,7 +358,7 @@
|
|
|
| MessageLoop::current()->RunAllPending();
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + scoped_ptr<const std::string> serialized(WaitForSerializedReport(report));
|
| ClientMalwareReportRequest actual;
|
| actual.ParseFromString(*serialized);
|
|
|
| @@ -214,6 +384,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);
|
| }
|
| @@ -223,10 +394,10 @@
|
| 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<MalwareDetails> report = new MalwareDetailsWrap(
|
| + contents(), resource, false);
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + scoped_ptr<const std::string> serialized(WaitForSerializedReport(report));
|
| ClientMalwareReportRequest actual;
|
| actual.ParseFromString(*serialized);
|
|
|
| @@ -254,10 +425,10 @@
|
| resource.redirect_urls.push_back(GURL(kSecondRedirectURL));
|
| resource.redirect_urls.push_back(GURL(kMalwareURL));
|
|
|
| - scoped_refptr<MalwareDetails> report = MalwareDetails::NewMalwareDetails(
|
| - contents(), resource);
|
| + scoped_refptr<MalwareDetails> report = new MalwareDetailsWrap(
|
| + contents(), resource, false);
|
|
|
| - scoped_ptr<const std::string> serialized(report->GetSerializedReport());
|
| + scoped_ptr<const std::string> serialized(WaitForSerializedReport(report));
|
| ClientMalwareReportRequest actual;
|
| actual.ParseFromString(*serialized);
|
|
|
| @@ -291,3 +462,105 @@
|
|
|
| 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(
|
| + contents(), resource, true);
|
| +
|
| + FillCache(report->GetURLRequestContext());
|
| +
|
| + // The cache collection starts after the IPC from the DOM is fired.
|
| + ViewHostMsg_MalwareDOMDetails_Params params;
|
| + report->OnReceivedMalwareDOMDetails(params);
|
| +
|
| + // Let the cache callbacks complete
|
| + MessageLoop::current()->RunAllPending();
|
| +
|
| + LOG(INFO) << "Getting serialized report";
|
| + scoped_ptr<const 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_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(
|
| + contents(), resource, true);
|
| +
|
| + // No call to FillCache
|
| +
|
| + // The cache collection starts after the IPC from the DOM is fired.
|
| + ViewHostMsg_MalwareDOMDetails_Params params;
|
| + report->OnReceivedMalwareDOMDetails(params);
|
| +
|
| + // Let the cache callbacks complete
|
| + MessageLoop::current()->RunAllPending();
|
| +
|
| + LOG(INFO) << "Getting serialized report";
|
| + scoped_ptr<const 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);
|
| +}
|
|
|