Home | History | Annotate | Download | only in safe_browsing
      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 #include <algorithm>
      6 
      7 #include "base/bind.h"
      8 #include "base/pickle.h"
      9 #include "base/run_loop.h"
     10 #include "base/time/time.h"
     11 #include "chrome/browser/history/history_backend.h"
     12 #include "chrome/browser/history/history_service.h"
     13 #include "chrome/browser/history/history_service_factory.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/safe_browsing/malware_details.h"
     16 #include "chrome/browser/safe_browsing/malware_details_history.h"
     17 #include "chrome/browser/safe_browsing/report.pb.h"
     18 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
     19 #include "chrome/browser/safe_browsing/ui_manager.h"
     20 #include "chrome/common/render_messages.h"
     21 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
     22 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     23 #include "chrome/test/base/testing_profile.h"
     24 #include "content/public/browser/render_process_host.h"
     25 #include "content/public/browser/web_contents.h"
     26 #include "net/base/io_buffer.h"
     27 #include "net/base/net_errors.h"
     28 #include "net/base/test_completion_callback.h"
     29 #include "net/disk_cache/disk_cache.h"
     30 #include "net/http/http_cache.h"
     31 #include "net/http/http_response_headers.h"
     32 #include "net/http/http_response_info.h"
     33 #include "net/http/http_util.h"
     34 #include "net/url_request/url_request_context.h"
     35 #include "net/url_request/url_request_context_getter.h"
     36 
     37 static const char* kOriginalLandingURL = "http://www.originallandingpage.com/";
     38 static const char* kHttpsURL = "https://www.url.com/";
     39 static const char* kDOMChildURL = "http://www.domparent.com/";
     40 static const char* kDOMParentURL = "http://www.domchild.com/";
     41 static const char* kFirstRedirectURL = "http://redirectone.com/";
     42 static const char* kSecondRedirectURL = "http://redirecttwo.com/";
     43 
     44 static const char* kMalwareURL = "http://www.malware.com/";
     45 static const char* kMalwareHeaders =
     46     "HTTP/1.1 200 OK\n"
     47     "Content-Type: image/jpeg\n";
     48 static const char* kMalwareData = "exploit();";
     49 
     50 static const char* kLandingURL = "http://www.landingpage.com/";
     51 static const char* kLandingHeaders =
     52     "HTTP/1.1 200 OK\n"
     53     "Content-Type: text/html\n"
     54     "Content-Length: 1024\n"
     55     "Set-Cookie: tastycookie\n";  // This header is stripped.
     56 static const char* kLandingData = "<iframe src='http://www.malware.com'>";
     57 
     58 using content::BrowserThread;
     59 using content::WebContents;
     60 using safe_browsing::ClientMalwareReportRequest;
     61 
     62 namespace {
     63 
     64 void WriteHeaders(disk_cache::Entry* entry, const std::string& headers) {
     65   net::HttpResponseInfo responseinfo;
     66   std::string raw_headers = net::HttpUtil::AssembleRawHeaders(
     67       headers.c_str(), headers.size());
     68   responseinfo.socket_address = net::HostPortPair("1.2.3.4", 80);
     69   responseinfo.headers = new net::HttpResponseHeaders(raw_headers);
     70 
     71   Pickle pickle;
     72   responseinfo.Persist(&pickle, false, false);
     73 
     74   scoped_refptr<net::WrappedIOBuffer> buf(new net::WrappedIOBuffer(
     75       reinterpret_cast<const char*>(pickle.data())));
     76   int len = static_cast<int>(pickle.size());
     77 
     78   net::TestCompletionCallback cb;
     79   int rv = entry->WriteData(0, 0, buf.get(), len, cb.callback(), true);
     80   ASSERT_EQ(len, cb.GetResult(rv));
     81 }
     82 
     83 void WriteData(disk_cache::Entry* entry, const std::string& data) {
     84   if (data.empty())
     85     return;
     86 
     87   int len = data.length();
     88   scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(len));
     89   memcpy(buf->data(), data.data(), data.length());
     90 
     91   net::TestCompletionCallback cb;
     92   int rv = entry->WriteData(1, 0, buf.get(), len, cb.callback(), true);
     93   ASSERT_EQ(len, cb.GetResult(rv));
     94 }
     95 
     96 void WriteToEntry(disk_cache::Backend* cache, const std::string& key,
     97                   const std::string& headers, const std::string& data) {
     98   net::TestCompletionCallback cb;
     99   disk_cache::Entry* entry;
    100   int rv = cache->CreateEntry(key, &entry, cb.callback());
    101   rv = cb.GetResult(rv);
    102   if (rv != net::OK) {
    103     rv = cache->OpenEntry(key, &entry, cb.callback());
    104     ASSERT_EQ(net::OK, cb.GetResult(rv));
    105   }
    106 
    107   WriteHeaders(entry, headers);
    108   WriteData(entry, data);
    109   entry->Close();
    110 }
    111 
    112 void FillCache(net::URLRequestContextGetter* context_getter) {
    113   net::TestCompletionCallback cb;
    114   disk_cache::Backend* cache;
    115   int rv =
    116       context_getter->GetURLRequestContext()->http_transaction_factory()->
    117       GetCache()->GetBackend(&cache, cb.callback());
    118   ASSERT_EQ(net::OK, cb.GetResult(rv));
    119 
    120   WriteToEntry(cache, kMalwareURL, kMalwareHeaders, kMalwareData);
    121   WriteToEntry(cache, kLandingURL, kLandingHeaders, kLandingData);
    122 }
    123 
    124 // Lets us provide a MockURLRequestContext with an HTTP Cache we pre-populate.
    125 // Also exposes the constructor.
    126 class MalwareDetailsWrap : public MalwareDetails {
    127  public:
    128   MalwareDetailsWrap(
    129       SafeBrowsingUIManager* ui_manager,
    130       WebContents* web_contents,
    131       const SafeBrowsingUIManager::UnsafeResource& unsafe_resource,
    132       net::URLRequestContextGetter* request_context_getter)
    133       : MalwareDetails(ui_manager, web_contents, unsafe_resource) {
    134 
    135     request_context_getter_ = request_context_getter;
    136   }
    137 
    138  private:
    139   virtual ~MalwareDetailsWrap() {}
    140 };
    141 
    142 class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
    143  public:
    144   base::RunLoop* run_loop_;
    145   // The safe browsing UI manager does not need a service for this test.
    146   MockSafeBrowsingUIManager()
    147       : SafeBrowsingUIManager(NULL), run_loop_(NULL) {}
    148 
    149   // When the MalwareDetails is done, this is called.
    150   virtual void SendSerializedMalwareDetails(
    151       const std::string& serialized) OVERRIDE {
    152     DVLOG(1) << "SendSerializedMalwareDetails";
    153     run_loop_->Quit();
    154     run_loop_ = NULL;
    155     serialized_ = serialized;
    156   }
    157 
    158   // Used to synchronize SendSerializedMalwareDetails() with
    159   // WaitForSerializedReport(). RunLoop::RunUntilIdle() is not sufficient
    160   // because the MessageLoop task queue completely drains at some point
    161   // between the send and the wait.
    162   void SetRunLoopToQuit(base::RunLoop* run_loop) {
    163     DCHECK(run_loop_ == NULL);
    164     run_loop_ = run_loop;
    165   }
    166 
    167   const std::string& GetSerialized() {
    168     return serialized_;
    169   }
    170 
    171  private:
    172   virtual ~MockSafeBrowsingUIManager() {}
    173 
    174   std::string serialized_;
    175   DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager);
    176 };
    177 
    178 }  // namespace.
    179 
    180 class MalwareDetailsTest : public ChromeRenderViewHostTestHarness {
    181  public:
    182   typedef SafeBrowsingUIManager::UnsafeResource UnsafeResource;
    183 
    184   MalwareDetailsTest()
    185       : ui_manager_(new MockSafeBrowsingUIManager()) {
    186   }
    187 
    188   virtual void SetUp() OVERRIDE {
    189     ChromeRenderViewHostTestHarness::SetUp();
    190     ASSERT_TRUE(profile()->CreateHistoryService(
    191         true /* delete_file */, false /* no_db */));
    192   }
    193 
    194   virtual void TearDown() OVERRIDE {
    195     profile()->DestroyHistoryService();
    196     ChromeRenderViewHostTestHarness::TearDown();
    197   }
    198 
    199   static bool ResourceLessThan(
    200       const ClientMalwareReportRequest::Resource* lhs,
    201       const ClientMalwareReportRequest::Resource* rhs) {
    202     return lhs->id() < rhs->id();
    203   }
    204 
    205   std::string WaitForSerializedReport(MalwareDetails* report) {
    206     BrowserThread::PostTask(
    207         BrowserThread::IO,
    208         FROM_HERE,
    209         base::Bind(&MalwareDetails::FinishCollection, report));
    210     // Wait for the callback (SendSerializedMalwareDetails).
    211     DVLOG(1) << "Waiting for SendSerializedMalwareDetails";
    212     base::RunLoop run_loop;
    213     ui_manager_->SetRunLoopToQuit(&run_loop);
    214     run_loop.Run();
    215     return ui_manager_->GetSerialized();
    216   }
    217 
    218   HistoryService* history_service() {
    219     return HistoryServiceFactory::GetForProfile(profile(),
    220                                                 Profile::EXPLICIT_ACCESS);
    221   }
    222 
    223  protected:
    224   void InitResource(UnsafeResource* resource,
    225                     bool is_subresource,
    226                     const GURL& url) {
    227     resource->url = url;
    228     resource->is_subresource = is_subresource;
    229     resource->threat_type = SB_THREAT_TYPE_URL_MALWARE;
    230     resource->render_process_host_id =
    231         web_contents()->GetRenderProcessHost()->GetID();
    232     resource->render_view_id =
    233         web_contents()->GetRenderViewHost()->GetRoutingID();
    234   }
    235 
    236   void VerifyResults(const ClientMalwareReportRequest& report_pb,
    237                      const ClientMalwareReportRequest& expected_pb) {
    238     EXPECT_EQ(expected_pb.malware_url(), report_pb.malware_url());
    239     EXPECT_EQ(expected_pb.page_url(), report_pb.page_url());
    240     EXPECT_EQ(expected_pb.referrer_url(), report_pb.referrer_url());
    241 
    242     ASSERT_EQ(expected_pb.resources_size(), report_pb.resources_size());
    243     // Sort the resources, to make the test deterministic
    244     std::vector<const ClientMalwareReportRequest::Resource*> resources;
    245     for (int i = 0; i < report_pb.resources_size(); ++i) {
    246       const ClientMalwareReportRequest::Resource& resource =
    247           report_pb.resources(i);
    248       resources.push_back(&resource);
    249     }
    250     std::sort(resources.begin(), resources.end(),
    251               &MalwareDetailsTest::ResourceLessThan);
    252 
    253     std::vector<const ClientMalwareReportRequest::Resource*> expected;
    254     for (int i = 0; i < report_pb.resources_size(); ++i) {
    255       const ClientMalwareReportRequest::Resource& resource =
    256           expected_pb.resources(i);
    257       expected.push_back(&resource);
    258     }
    259     std::sort(expected.begin(), expected.end(),
    260               &MalwareDetailsTest::ResourceLessThan);
    261 
    262     for (uint32 i = 0; i < expected.size(); ++i) {
    263       VerifyResource(resources[i], expected[i]);
    264     }
    265 
    266     EXPECT_EQ(expected_pb.complete(), report_pb.complete());
    267   }
    268 
    269   void VerifyResource(const ClientMalwareReportRequest::Resource* resource,
    270                       const ClientMalwareReportRequest::Resource* expected) {
    271     EXPECT_EQ(expected->id(), resource->id());
    272     EXPECT_EQ(expected->url(), resource->url());
    273     EXPECT_EQ(expected->parent_id(), resource->parent_id());
    274     ASSERT_EQ(expected->child_ids_size(), resource->child_ids_size());
    275     for (int i = 0; i < expected->child_ids_size(); i++) {
    276       EXPECT_EQ(expected->child_ids(i), resource->child_ids(i));
    277     }
    278 
    279     // Verify HTTP Responses
    280     if (expected->has_response()) {
    281       ASSERT_TRUE(resource->has_response());
    282       EXPECT_EQ(expected->response().firstline().code(),
    283                 resource->response().firstline().code());
    284 
    285       ASSERT_EQ(expected->response().headers_size(),
    286                 resource->response().headers_size());
    287       for (int i = 0; i < expected->response().headers_size(); ++i) {
    288         EXPECT_EQ(expected->response().headers(i).name(),
    289                   resource->response().headers(i).name());
    290         EXPECT_EQ(expected->response().headers(i).value(),
    291                   resource->response().headers(i).value());
    292       }
    293 
    294       EXPECT_EQ(expected->response().body(), resource->response().body());
    295       EXPECT_EQ(expected->response().bodylength(),
    296                 resource->response().bodylength());
    297       EXPECT_EQ(expected->response().bodydigest(),
    298                 resource->response().bodydigest());
    299     }
    300 
    301     // Verify IP:port pair
    302     EXPECT_EQ(expected->response().remote_ip(),
    303               resource->response().remote_ip());
    304   }
    305 
    306   // Adds a page to history.
    307   // The redirects is the redirect url chain leading to the url.
    308   void AddPageToHistory(const GURL& url,
    309                         history::RedirectList* redirects) {
    310     // The last item of the redirect chain has to be the final url when adding
    311     // to history backend.
    312     redirects->push_back(url);
    313     history_service()->AddPage(
    314         url, base::Time::Now(), static_cast<void*>(this), 0, GURL(),
    315         *redirects, content::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
    316         false);
    317   }
    318 
    319   scoped_refptr<MockSafeBrowsingUIManager> ui_manager_;
    320 };
    321 
    322 // Tests creating a simple malware report.
    323 TEST_F(MalwareDetailsTest, MalwareSubResource) {
    324   // Start a load.
    325   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
    326                        content::PAGE_TRANSITION_TYPED, std::string());
    327 
    328   UnsafeResource resource;
    329   InitResource(&resource, true, GURL(kMalwareURL));
    330 
    331   scoped_refptr<MalwareDetailsWrap> report =
    332       new MalwareDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL);
    333 
    334   std::string serialized = WaitForSerializedReport(report.get());
    335 
    336   ClientMalwareReportRequest actual;
    337   actual.ParseFromString(serialized);
    338 
    339   ClientMalwareReportRequest expected;
    340   expected.set_malware_url(kMalwareURL);
    341   expected.set_page_url(kLandingURL);
    342   expected.set_referrer_url("");
    343 
    344   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
    345   pb_resource->set_id(0);
    346   pb_resource->set_url(kLandingURL);
    347   pb_resource = expected.add_resources();
    348   pb_resource->set_id(1);
    349   pb_resource->set_url(kMalwareURL);
    350 
    351   VerifyResults(actual, expected);
    352 }
    353 
    354 // Tests creating a simple malware report where the subresource has a
    355 // different original_url.
    356 TEST_F(MalwareDetailsTest, MalwareSubResourceWithOriginalUrl) {
    357   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
    358                        content::PAGE_TRANSITION_TYPED, std::string());
    359 
    360   UnsafeResource resource;
    361   InitResource(&resource, true, GURL(kMalwareURL));
    362   resource.original_url = GURL(kOriginalLandingURL);
    363 
    364   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
    365       ui_manager_.get(), web_contents(), resource, NULL);
    366 
    367   std::string serialized = WaitForSerializedReport(report.get());
    368 
    369   ClientMalwareReportRequest actual;
    370   actual.ParseFromString(serialized);
    371 
    372   ClientMalwareReportRequest expected;
    373   expected.set_malware_url(kMalwareURL);
    374   expected.set_page_url(kLandingURL);
    375   expected.set_referrer_url("");
    376 
    377   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
    378   pb_resource->set_id(0);
    379   pb_resource->set_url(kLandingURL);
    380 
    381   pb_resource = expected.add_resources();
    382   pb_resource->set_id(1);
    383   pb_resource->set_url(kOriginalLandingURL);
    384 
    385   pb_resource = expected.add_resources();
    386   pb_resource->set_id(2);
    387   pb_resource->set_url(kMalwareURL);
    388   // The Resource for kMmalwareUrl should have the Resource for
    389   // kOriginalLandingURL (with id 1) as parent.
    390   pb_resource->set_parent_id(1);
    391 
    392   VerifyResults(actual, expected);
    393 }
    394 
    395 // Tests creating a malware report with data from the renderer.
    396 TEST_F(MalwareDetailsTest, MalwareDOMDetails) {
    397   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
    398                        content::PAGE_TRANSITION_TYPED, std::string());
    399 
    400   UnsafeResource resource;
    401   InitResource(&resource, true, GURL(kMalwareURL));
    402 
    403   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
    404       ui_manager_.get(), web_contents(), resource, NULL);
    405 
    406   // Send a message from the DOM, with 2 nodes, a parent and a child.
    407   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
    408   SafeBrowsingHostMsg_MalwareDOMDetails_Node child_node;
    409   child_node.url = GURL(kDOMChildURL);
    410   child_node.tag_name = "iframe";
    411   child_node.parent = GURL(kDOMParentURL);
    412   params.push_back(child_node);
    413   SafeBrowsingHostMsg_MalwareDOMDetails_Node parent_node;
    414   parent_node.url = GURL(kDOMParentURL);
    415   parent_node.children.push_back(GURL(kDOMChildURL));
    416   params.push_back(parent_node);
    417   report->OnReceivedMalwareDOMDetails(params);
    418 
    419   std::string serialized = WaitForSerializedReport(report.get());
    420   ClientMalwareReportRequest actual;
    421   actual.ParseFromString(serialized);
    422 
    423   ClientMalwareReportRequest expected;
    424   expected.set_malware_url(kMalwareURL);
    425   expected.set_page_url(kLandingURL);
    426   expected.set_referrer_url("");
    427 
    428   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
    429   pb_resource->set_id(0);
    430   pb_resource->set_url(kLandingURL);
    431 
    432   pb_resource = expected.add_resources();
    433   pb_resource->set_id(1);
    434   pb_resource->set_url(kMalwareURL);
    435 
    436   pb_resource = expected.add_resources();
    437   pb_resource->set_id(2);
    438   pb_resource->set_url(kDOMChildURL);
    439   pb_resource->set_parent_id(3);
    440 
    441   pb_resource = expected.add_resources();
    442   pb_resource->set_id(3);
    443   pb_resource->set_url(kDOMParentURL);
    444   pb_resource->add_child_ids(2);
    445   expected.set_complete(false);  // Since the cache was missing.
    446 
    447   VerifyResults(actual, expected);
    448 }
    449 
    450 // Verify that https:// urls are dropped.
    451 TEST_F(MalwareDetailsTest, NotPublicUrl) {
    452   controller().LoadURL(GURL(kHttpsURL), content::Referrer(),
    453                        content::PAGE_TRANSITION_TYPED, std::string());
    454   UnsafeResource resource;
    455   InitResource(&resource, true, GURL(kMalwareURL));
    456   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
    457       ui_manager_.get(), web_contents(), resource, NULL);
    458 
    459   std::string serialized = WaitForSerializedReport(report.get());
    460   ClientMalwareReportRequest actual;
    461   actual.ParseFromString(serialized);
    462 
    463   ClientMalwareReportRequest expected;
    464   expected.set_malware_url(kMalwareURL);  // No page_url
    465   expected.set_referrer_url("");
    466 
    467   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
    468   pb_resource->set_url(kMalwareURL);  // Only one resource
    469 
    470   VerifyResults(actual, expected);
    471 }
    472 
    473 // Tests creating a malware report where there are redirect urls to an unsafe
    474 // resource url
    475 TEST_F(MalwareDetailsTest, MalwareWithRedirectUrl) {
    476   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
    477                        content::PAGE_TRANSITION_TYPED, std::string());
    478 
    479   UnsafeResource resource;
    480   InitResource(&resource, true, GURL(kMalwareURL));
    481   resource.original_url = GURL(kOriginalLandingURL);
    482 
    483   // add some redirect urls
    484   resource.redirect_urls.push_back(GURL(kFirstRedirectURL));
    485   resource.redirect_urls.push_back(GURL(kSecondRedirectURL));
    486   resource.redirect_urls.push_back(GURL(kMalwareURL));
    487 
    488   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
    489       ui_manager_.get(), web_contents(), resource, NULL);
    490 
    491   std::string serialized = WaitForSerializedReport(report.get());
    492   ClientMalwareReportRequest actual;
    493   actual.ParseFromString(serialized);
    494 
    495   ClientMalwareReportRequest expected;
    496   expected.set_malware_url(kMalwareURL);
    497   expected.set_page_url(kLandingURL);
    498   expected.set_referrer_url("");
    499 
    500   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
    501   pb_resource->set_id(0);
    502   pb_resource->set_url(kLandingURL);
    503 
    504   pb_resource = expected.add_resources();
    505   pb_resource->set_id(1);
    506   pb_resource->set_url(kOriginalLandingURL);
    507 
    508   pb_resource = expected.add_resources();
    509   pb_resource->set_id(2);
    510   pb_resource->set_url(kMalwareURL);
    511   pb_resource->set_parent_id(4);
    512 
    513   pb_resource = expected.add_resources();
    514   pb_resource->set_id(3);
    515   pb_resource->set_url(kFirstRedirectURL);
    516   pb_resource->set_parent_id(1);
    517 
    518   pb_resource = expected.add_resources();
    519   pb_resource->set_id(4);
    520   pb_resource->set_url(kSecondRedirectURL);
    521   pb_resource->set_parent_id(3);
    522 
    523   VerifyResults(actual, expected);
    524 }
    525 
    526 // Tests the interaction with the HTTP cache.
    527 TEST_F(MalwareDetailsTest, HTTPCache) {
    528   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
    529                        content::PAGE_TRANSITION_TYPED, std::string());
    530 
    531   UnsafeResource resource;
    532   InitResource(&resource, true, GURL(kMalwareURL));
    533 
    534   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
    535       ui_manager_.get(), web_contents(), resource,
    536       profile()->GetRequestContext());
    537 
    538   BrowserThread::PostTask(
    539       BrowserThread::IO, FROM_HERE,
    540       base::Bind(&FillCache,
    541                  make_scoped_refptr(profile()->GetRequestContext())));
    542 
    543   // The cache collection starts after the IPC from the DOM is fired.
    544   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
    545   report->OnReceivedMalwareDOMDetails(params);
    546 
    547   // Let the cache callbacks complete.
    548   base::RunLoop().RunUntilIdle();
    549 
    550   DVLOG(1) << "Getting serialized report";
    551   std::string serialized = WaitForSerializedReport(report.get());
    552   ClientMalwareReportRequest actual;
    553   actual.ParseFromString(serialized);
    554 
    555   ClientMalwareReportRequest expected;
    556   expected.set_malware_url(kMalwareURL);
    557   expected.set_page_url(kLandingURL);
    558   expected.set_referrer_url("");
    559 
    560   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
    561   pb_resource->set_id(0);
    562   pb_resource->set_url(kLandingURL);
    563   safe_browsing::ClientMalwareReportRequest::HTTPResponse* pb_response =
    564       pb_resource->mutable_response();
    565   pb_response->mutable_firstline()->set_code(200);
    566   safe_browsing::ClientMalwareReportRequest::HTTPHeader* pb_header =
    567       pb_response->add_headers();
    568   pb_header->set_name("Content-Type");
    569   pb_header->set_value("text/html");
    570   pb_header = pb_response->add_headers();
    571   pb_header->set_name("Content-Length");
    572   pb_header->set_value("1024");
    573   pb_header = pb_response->add_headers();
    574   pb_header->set_name("Set-Cookie");
    575   pb_header->set_value("");  // The cookie is dropped.
    576   pb_response->set_body(kLandingData);
    577   pb_response->set_bodylength(37);
    578   pb_response->set_bodydigest("9ca97475598a79bc1e8fc9bd6c72cd35");
    579   pb_response->set_remote_ip("1.2.3.4:80");
    580 
    581   pb_resource = expected.add_resources();
    582   pb_resource->set_id(1);
    583   pb_resource->set_url(kMalwareURL);
    584   pb_response = pb_resource->mutable_response();
    585   pb_response->mutable_firstline()->set_code(200);
    586   pb_header = pb_response->add_headers();
    587   pb_header->set_name("Content-Type");
    588   pb_header->set_value("image/jpeg");
    589   pb_response->set_body(kMalwareData);
    590   pb_response->set_bodylength(10);
    591   pb_response->set_bodydigest("581373551c43d4cf33bfb3b26838ff95");
    592   pb_response->set_remote_ip("1.2.3.4:80");
    593   expected.set_complete(true);
    594 
    595   VerifyResults(actual, expected);
    596 }
    597 
    598 // Tests the interaction with the HTTP cache (where the cache is empty).
    599 TEST_F(MalwareDetailsTest, HTTPCacheNoEntries) {
    600   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
    601                        content::PAGE_TRANSITION_TYPED, std::string());
    602 
    603   UnsafeResource resource;
    604   InitResource(&resource, true, GURL(kMalwareURL));
    605 
    606   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
    607       ui_manager_.get(), web_contents(), resource,
    608       profile()->GetRequestContext());
    609 
    610   // No call to FillCache
    611 
    612   // The cache collection starts after the IPC from the DOM is fired.
    613   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
    614   report->OnReceivedMalwareDOMDetails(params);
    615 
    616   // Let the cache callbacks complete.
    617   base::RunLoop().RunUntilIdle();
    618 
    619   DVLOG(1) << "Getting serialized report";
    620   std::string serialized = WaitForSerializedReport(report.get());
    621   ClientMalwareReportRequest actual;
    622   actual.ParseFromString(serialized);
    623 
    624   ClientMalwareReportRequest expected;
    625   expected.set_malware_url(kMalwareURL);
    626   expected.set_page_url(kLandingURL);
    627   expected.set_referrer_url("");
    628 
    629   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
    630   pb_resource->set_id(0);
    631   pb_resource->set_url(kLandingURL);
    632   pb_resource = expected.add_resources();
    633   pb_resource->set_id(1);
    634   pb_resource->set_url(kMalwareURL);
    635   expected.set_complete(true);
    636 
    637   VerifyResults(actual, expected);
    638 }
    639 
    640 // Test getting redirects from history service.
    641 TEST_F(MalwareDetailsTest, HistoryServiceUrls) {
    642   // Add content to history service.
    643   // There are two redirect urls before reacing malware url:
    644   // kFirstRedirectURL -> kSecondRedirectURL -> kMalwareURL
    645   GURL baseurl(kMalwareURL);
    646   history::RedirectList redirects;
    647   redirects.push_back(GURL(kFirstRedirectURL));
    648   redirects.push_back(GURL(kSecondRedirectURL));
    649   AddPageToHistory(baseurl, &redirects);
    650   // Wait for history service operation finished.
    651   profile()->BlockUntilHistoryProcessesPendingRequests();
    652 
    653   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
    654                        content::PAGE_TRANSITION_TYPED, std::string());
    655 
    656   UnsafeResource resource;
    657   InitResource(&resource, true, GURL(kMalwareURL));
    658   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
    659       ui_manager_.get(), web_contents(), resource, NULL);
    660 
    661   // The redirects collection starts after the IPC from the DOM is fired.
    662   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
    663   report->OnReceivedMalwareDOMDetails(params);
    664 
    665   // Let the redirects callbacks complete.
    666   base::RunLoop().RunUntilIdle();
    667 
    668   std::string serialized = WaitForSerializedReport(report.get());
    669   ClientMalwareReportRequest actual;
    670   actual.ParseFromString(serialized);
    671 
    672   ClientMalwareReportRequest expected;
    673   expected.set_malware_url(kMalwareURL);
    674   expected.set_page_url(kLandingURL);
    675   expected.set_referrer_url("");
    676 
    677   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
    678   pb_resource->set_id(0);
    679   pb_resource->set_url(kLandingURL);
    680   pb_resource = expected.add_resources();
    681   pb_resource->set_id(1);
    682   pb_resource->set_parent_id(2);
    683   pb_resource->set_url(kMalwareURL);
    684   pb_resource = expected.add_resources();
    685   pb_resource->set_id(2);
    686   pb_resource->set_parent_id(3);
    687   pb_resource->set_url(kSecondRedirectURL);
    688   pb_resource = expected.add_resources();
    689   pb_resource->set_id(3);
    690   pb_resource->set_url(kFirstRedirectURL);
    691 
    692   VerifyResults(actual, expected);
    693 }
    694