• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/pickle.h"
8 #include "base/time.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/safe_browsing/malware_details.h"
11 #include "chrome/browser/safe_browsing/report.pb.h"
12 #include "chrome/common/render_messages.h"
13 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
14 #include "chrome/test/test_url_request_context_getter.h"
15 #include "chrome/test/testing_profile.h"
16 #include "content/browser/browser_thread.h"
17 #include "content/browser/renderer_host/test_render_view_host.h"
18 #include "content/browser/tab_contents/navigation_entry.h"
19 #include "content/browser/tab_contents/test_tab_contents.h"
20 #include "net/base/io_buffer.h"
21 #include "net/base/test_completion_callback.h"
22 #include "net/disk_cache/disk_cache.h"
23 #include "net/http/http_cache.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/http/http_response_info.h"
26 #include "net/http/http_util.h"
27 #include "net/url_request/url_request_context.h"
28 #include "net/url_request/url_request_context_getter.h"
29 
30 static const char* kOriginalLandingURL = "http://www.originallandingpage.com/";
31 static const char* kHttpsURL = "https://www.url.com/";
32 static const char* kDOMChildURL = "http://www.domparent.com/";
33 static const char* kDOMParentURL = "http://www.domchild.com/";
34 static const char* kFirstRedirectURL = "http://redirectone.com/";
35 static const char* kSecondRedirectURL = "http://redirecttwo.com/";
36 
37 static const char* kMalwareURL = "http://www.malware.com/";
38 static const char* kMalwareHeaders =
39     "HTTP/1.1 200 OK\n"
40     "Content-Type: image/jpeg\n";
41 static const char* kMalwareData = "exploit();";
42 
43 static const char* kLandingURL = "http://www.landingpage.com/";
44 static const char* kLandingHeaders =
45     "HTTP/1.1 200 OK\n"
46     "Content-Type: text/html\n"
47     "Content-Length: 1024\n"
48     "Set-Cookie: tastycookie\n";  // This header is stripped.
49 static const char* kLandingData = "<iframe src='http://www.malware.com'>";
50 
51 using safe_browsing::ClientMalwareReportRequest;
52 
53 namespace {
54 
WriteHeaders(disk_cache::Entry * entry,const std::string headers)55 void WriteHeaders(disk_cache::Entry* entry, const std::string headers) {
56   net::HttpResponseInfo responseinfo;
57   std::string raw_headers = net::HttpUtil::AssembleRawHeaders(
58       headers.c_str(), headers.size());
59   responseinfo.headers = new net::HttpResponseHeaders(raw_headers);
60 
61   Pickle pickle;
62   responseinfo.Persist(&pickle, false, false);
63 
64   scoped_refptr<net::WrappedIOBuffer> buf(new net::WrappedIOBuffer(
65       reinterpret_cast<const char*>(pickle.data())));
66   int len = static_cast<int>(pickle.size());
67 
68   TestCompletionCallback cb;
69   int rv = entry->WriteData(0, 0, buf, len, &cb, true);
70   ASSERT_EQ(len, cb.GetResult(rv));
71 }
72 
WriteData(disk_cache::Entry * entry,const std::string data)73 void WriteData(disk_cache::Entry* entry, const std::string data) {
74   if (data.empty())
75     return;
76 
77   int len = data.length();
78   scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(len));
79   memcpy(buf->data(), data.data(), data.length());
80 
81   TestCompletionCallback cb;
82   int rv = entry->WriteData(1, 0, buf, len, &cb, true);
83   ASSERT_EQ(len, cb.GetResult(rv));
84 }
85 
WriteToEntry(disk_cache::Backend * cache,const std::string key,const std::string headers,const std::string data)86 void WriteToEntry(disk_cache::Backend* cache, const std::string key,
87                   const std::string headers, const std::string data) {
88   TestCompletionCallback cb;
89   disk_cache::Entry* entry;
90   int rv = cache->CreateEntry(key, &entry, &cb);
91   rv = cb.GetResult(rv);
92   if (rv != net::OK) {
93     rv = cache->OpenEntry(key, &entry, &cb);
94     ASSERT_EQ(net::OK, cb.GetResult(rv));
95   }
96 
97   WriteHeaders(entry, headers);
98   WriteData(entry, data);
99 
100   entry->Close();
101 }
102 
FillCache(net::URLRequestContext * context)103 void FillCache(net::URLRequestContext* context) {
104   TestCompletionCallback cb;
105   disk_cache::Backend* cache;
106   int rv =
107       context->http_transaction_factory()->GetCache()->GetBackend(&cache, &cb);
108   ASSERT_EQ(net::OK, cb.GetResult(rv));
109 
110   std::string empty;
111   WriteToEntry(cache, kMalwareURL, kMalwareHeaders, kMalwareData);
112   WriteToEntry(cache, kLandingURL, kLandingHeaders, kLandingData);
113 }
114 
QuitUIMessageLoop()115 void QuitUIMessageLoop() {
116   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
117   BrowserThread::PostTask(BrowserThread::UI,
118                           FROM_HERE,
119                           new MessageLoop::QuitTask());
120 }
121 
122 // Lets us provide a MockURLRequestContext with an HTTP Cache we pre-populate.
123 // Also exposes the constructor.
124 class MalwareDetailsWrap : public MalwareDetails {
125  public:
MalwareDetailsWrap(SafeBrowsingService * sb_service,TabContents * tab_contents,const SafeBrowsingService::UnsafeResource & unsafe_resource,net::URLRequestContextGetter * request_context_getter)126   MalwareDetailsWrap(SafeBrowsingService* sb_service,
127                      TabContents* tab_contents,
128                      const SafeBrowsingService::UnsafeResource& unsafe_resource,
129                      net::URLRequestContextGetter* request_context_getter)
130       : MalwareDetails(sb_service, tab_contents, unsafe_resource) {
131     request_context_getter_ = request_context_getter;
132   }
133 
~MalwareDetailsWrap()134   virtual ~MalwareDetailsWrap() {}
135 };
136 
137 class MockSafeBrowsingService : public SafeBrowsingService {
138  public:
MockSafeBrowsingService()139   MockSafeBrowsingService() {}
~MockSafeBrowsingService()140   virtual ~MockSafeBrowsingService() {}
141 
142   // When the MalwareDetails is done, this is called.
SendSerializedMalwareDetails(const std::string & serialized)143   virtual void SendSerializedMalwareDetails(const std::string& serialized) {
144     DVLOG(1) << "SendSerializedMalwareDetails";
145     // Notify WaitForSerializedReport.
146     BrowserThread::PostTask(BrowserThread::IO,
147                             FROM_HERE,
148                             NewRunnableFunction(&QuitUIMessageLoop));
149     serialized_ = serialized;
150   }
151 
GetSerialized()152   const std::string& GetSerialized() {
153     return serialized_;
154   }
155 
156  private:
157   std::string serialized_;
158   DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingService);
159 };
160 
161 }  // namespace.
162 
163 class MalwareDetailsTest : public RenderViewHostTestHarness {
164  public:
MalwareDetailsTest()165   MalwareDetailsTest()
166       : ui_thread_(BrowserThread::UI, &message_loop_),
167         io_thread_(BrowserThread::IO),
168         sb_service_(new MockSafeBrowsingService()) {
169   }
170 
SetUp()171   virtual void SetUp() {
172     RenderViewHostTestHarness::SetUp();
173     // request_context_getter_ = new TestURLRequestContextGetter();
174 
175     // The URLFetcher checks that the messageloop type is IO.
176     ASSERT_TRUE(io_thread_.StartWithOptions(
177         base::Thread::Options(MessageLoop::TYPE_IO, 0)));
178   }
179 
TearDown()180   virtual void TearDown() {
181     io_thread_.Stop();
182     RenderViewHostTestHarness::TearDown();
183   }
184 
ResourceLessThan(const ClientMalwareReportRequest::Resource * lhs,const ClientMalwareReportRequest::Resource * rhs)185   static bool ResourceLessThan(
186       const ClientMalwareReportRequest::Resource* lhs,
187       const ClientMalwareReportRequest::Resource* rhs) {
188     return lhs->id() < rhs->id();
189   }
190 
WaitForSerializedReport(MalwareDetails * report)191   std::string WaitForSerializedReport(MalwareDetails* report) {
192     BrowserThread::PostTask(
193         BrowserThread::IO,
194         FROM_HERE,
195         NewRunnableMethod(
196             report, &MalwareDetails::FinishCollection));
197     // Wait for the callback (SendSerializedMalwareDetails).
198     DVLOG(1) << "Waiting for SendSerializedMalwareDetails";
199     MessageLoop::current()->Run();
200     return sb_service_->GetSerialized();
201   }
202 
203  protected:
InitResource(SafeBrowsingService::UnsafeResource * resource,ResourceType::Type resource_type,const GURL & url)204   void InitResource(SafeBrowsingService::UnsafeResource* resource,
205                     ResourceType::Type resource_type,
206                     const GURL& url) {
207     resource->client = NULL;
208     resource->url = url;
209     resource->resource_type = resource_type;
210     resource->threat_type = SafeBrowsingService::URL_MALWARE;
211     resource->render_process_host_id = contents()->GetRenderProcessHost()->id();
212     resource->render_view_id = contents()->render_view_host()->routing_id();
213   }
214 
VerifyResults(const ClientMalwareReportRequest & report_pb,const ClientMalwareReportRequest & expected_pb)215   void VerifyResults(const ClientMalwareReportRequest& report_pb,
216                      const ClientMalwareReportRequest& expected_pb) {
217     EXPECT_EQ(expected_pb.malware_url(), report_pb.malware_url());
218     EXPECT_EQ(expected_pb.page_url(), report_pb.page_url());
219     EXPECT_EQ(expected_pb.referrer_url(), report_pb.referrer_url());
220 
221     ASSERT_EQ(expected_pb.resources_size(), report_pb.resources_size());
222     // Sort the resources, to make the test deterministic
223     std::vector<const ClientMalwareReportRequest::Resource*> resources;
224     for (int i = 0; i < report_pb.resources_size(); ++i) {
225       const ClientMalwareReportRequest::Resource& resource =
226           report_pb.resources(i);
227       resources.push_back(&resource);
228     }
229     std::sort(resources.begin(), resources.end(),
230               &MalwareDetailsTest::ResourceLessThan);
231 
232     std::vector<const ClientMalwareReportRequest::Resource*> expected;
233     for (int i = 0; i < report_pb.resources_size(); ++i) {
234       const ClientMalwareReportRequest::Resource& resource =
235           expected_pb.resources(i);
236       expected.push_back(&resource);
237     }
238     std::sort(expected.begin(), expected.end(),
239               &MalwareDetailsTest::ResourceLessThan);
240 
241     for (uint32 i = 0; i < expected.size(); ++i) {
242       VerifyResource(resources[i], expected[i]);
243     }
244 
245     EXPECT_EQ(expected_pb.complete(), report_pb.complete());
246   }
247 
VerifyResource(const ClientMalwareReportRequest::Resource * resource,const ClientMalwareReportRequest::Resource * expected)248   void VerifyResource(const ClientMalwareReportRequest::Resource* resource,
249                       const ClientMalwareReportRequest::Resource* expected) {
250     EXPECT_EQ(expected->id(), resource->id());
251     EXPECT_EQ(expected->url(), resource->url());
252     EXPECT_EQ(expected->parent_id(), resource->parent_id());
253     ASSERT_EQ(expected->child_ids_size(), resource->child_ids_size());
254     for (int i = 0; i < expected->child_ids_size(); i++) {
255       EXPECT_EQ(expected->child_ids(i), resource->child_ids(i));
256     }
257 
258     // Verify HTTP Responses
259     if (expected->has_response()) {
260       ASSERT_TRUE(resource->has_response());
261       EXPECT_EQ(expected->response().firstline().code(),
262                 resource->response().firstline().code());
263 
264       ASSERT_EQ(expected->response().headers_size(),
265                 resource->response().headers_size());
266       for (int i = 0; i < expected->response().headers_size(); ++i) {
267         EXPECT_EQ(expected->response().headers(i).name(),
268                   resource->response().headers(i).name());
269         EXPECT_EQ(expected->response().headers(i).value(),
270                   resource->response().headers(i).value());
271       }
272 
273       EXPECT_EQ(expected->response().body(), resource->response().body());
274       EXPECT_EQ(expected->response().bodylength(),
275                 resource->response().bodylength());
276       EXPECT_EQ(expected->response().bodydigest(),
277                 resource->response().bodydigest());
278     }
279   }
280 
281   BrowserThread ui_thread_;
282   BrowserThread io_thread_;
283   scoped_refptr<MockSafeBrowsingService> sb_service_;
284 };
285 
286 // Tests creating a simple malware report.
TEST_F(MalwareDetailsTest,MalwareSubResource)287 TEST_F(MalwareDetailsTest, MalwareSubResource) {
288   // Start a load.
289   controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED);
290 
291   SafeBrowsingService::UnsafeResource resource;
292   InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
293 
294   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
295       sb_service_, contents(), resource, NULL);
296 
297   std::string serialized = WaitForSerializedReport(report);
298 
299   ClientMalwareReportRequest actual;
300   actual.ParseFromString(serialized);
301 
302   ClientMalwareReportRequest expected;
303   expected.set_malware_url(kMalwareURL);
304   expected.set_page_url(kLandingURL);
305   expected.set_referrer_url("");
306 
307   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
308   pb_resource->set_id(0);
309   pb_resource->set_url(kLandingURL);
310   pb_resource = expected.add_resources();
311   pb_resource->set_id(1);
312   pb_resource->set_url(kMalwareURL);
313 
314   VerifyResults(actual, expected);
315 }
316 
317 // Tests creating a simple malware report where the subresource has a
318 // different original_url.
TEST_F(MalwareDetailsTest,MalwareSubResourceWithOriginalUrl)319 TEST_F(MalwareDetailsTest, MalwareSubResourceWithOriginalUrl) {
320   controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED);
321 
322   SafeBrowsingService::UnsafeResource resource;
323   InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
324   resource.original_url = GURL(kOriginalLandingURL);
325 
326   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
327       sb_service_.get(), contents(), resource, NULL);
328 
329   std::string serialized = WaitForSerializedReport(report);
330 
331   ClientMalwareReportRequest actual;
332   actual.ParseFromString(serialized);
333 
334   ClientMalwareReportRequest expected;
335   expected.set_malware_url(kMalwareURL);
336   expected.set_page_url(kLandingURL);
337   expected.set_referrer_url("");
338 
339   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
340   pb_resource->set_id(0);
341   pb_resource->set_url(kLandingURL);
342 
343   pb_resource = expected.add_resources();
344   pb_resource->set_id(1);
345   pb_resource->set_url(kOriginalLandingURL);
346 
347   pb_resource = expected.add_resources();
348   pb_resource->set_id(2);
349   pb_resource->set_url(kMalwareURL);
350   // The Resource for kMmalwareUrl should have the Resource for
351   // kOriginalLandingURL (with id 1) as parent.
352   pb_resource->set_parent_id(1);
353 
354   VerifyResults(actual, expected);
355 }
356 
357 // Tests creating a malware report with data from the renderer.
TEST_F(MalwareDetailsTest,MalwareDOMDetails)358 TEST_F(MalwareDetailsTest, MalwareDOMDetails) {
359   controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED);
360 
361   SafeBrowsingService::UnsafeResource resource;
362   InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
363 
364   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
365       sb_service_.get(), contents(), resource, NULL);
366 
367   // Send a message from the DOM, with 2 nodes, a parent and a child.
368   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
369   SafeBrowsingHostMsg_MalwareDOMDetails_Node child_node;
370   child_node.url = GURL(kDOMChildURL);
371   child_node.tag_name = "iframe";
372   child_node.parent = GURL(kDOMParentURL);
373   params.push_back(child_node);
374   SafeBrowsingHostMsg_MalwareDOMDetails_Node parent_node;
375   parent_node.url = GURL(kDOMParentURL);
376   parent_node.children.push_back(GURL(kDOMChildURL));
377   params.push_back(parent_node);
378   report->OnReceivedMalwareDOMDetails(params);
379 
380   MessageLoop::current()->RunAllPending();
381 
382   std::string serialized = WaitForSerializedReport(report);
383   ClientMalwareReportRequest actual;
384   actual.ParseFromString(serialized);
385 
386   ClientMalwareReportRequest expected;
387   expected.set_malware_url(kMalwareURL);
388   expected.set_page_url(kLandingURL);
389   expected.set_referrer_url("");
390 
391   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
392   pb_resource->set_id(0);
393   pb_resource->set_url(kLandingURL);
394 
395   pb_resource = expected.add_resources();
396   pb_resource->set_id(1);
397   pb_resource->set_url(kMalwareURL);
398 
399   pb_resource = expected.add_resources();
400   pb_resource->set_id(2);
401   pb_resource->set_url(kDOMChildURL);
402   pb_resource->set_parent_id(3);
403 
404   pb_resource = expected.add_resources();
405   pb_resource->set_id(3);
406   pb_resource->set_url(kDOMParentURL);
407   pb_resource->add_child_ids(2);
408   expected.set_complete(false);  // Since the cache was missing.
409 
410   VerifyResults(actual, expected);
411 }
412 
413 // Verify that https:// urls are dropped.
TEST_F(MalwareDetailsTest,NotPublicUrl)414 TEST_F(MalwareDetailsTest, NotPublicUrl) {
415   controller().LoadURL(GURL(kHttpsURL), GURL(), PageTransition::TYPED);
416   SafeBrowsingService::UnsafeResource resource;
417   InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
418   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
419       sb_service_.get(), contents(), resource, NULL);
420 
421   std::string serialized = WaitForSerializedReport(report);
422   ClientMalwareReportRequest actual;
423   actual.ParseFromString(serialized);
424 
425   ClientMalwareReportRequest expected;
426   expected.set_malware_url(kMalwareURL);  // No page_url
427   expected.set_referrer_url("");
428 
429   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
430   pb_resource->set_url(kMalwareURL);  // Only one resource
431 
432   VerifyResults(actual, expected);
433 }
434 
435 // Tests creating a malware report where there are redirect urls to an unsafe
436 // resource url
TEST_F(MalwareDetailsTest,MalwareWithRedirectUrl)437 TEST_F(MalwareDetailsTest, MalwareWithRedirectUrl) {
438   controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED);
439 
440   SafeBrowsingService::UnsafeResource resource;
441   InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
442   resource.original_url = GURL(kOriginalLandingURL);
443 
444   // add some redirect urls
445   resource.redirect_urls.push_back(GURL(kFirstRedirectURL));
446   resource.redirect_urls.push_back(GURL(kSecondRedirectURL));
447   resource.redirect_urls.push_back(GURL(kMalwareURL));
448 
449   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
450       sb_service_.get(), contents(), resource, NULL);
451 
452   std::string serialized = WaitForSerializedReport(report);
453   ClientMalwareReportRequest actual;
454   actual.ParseFromString(serialized);
455 
456   ClientMalwareReportRequest expected;
457   expected.set_malware_url(kMalwareURL);
458   expected.set_page_url(kLandingURL);
459   expected.set_referrer_url("");
460 
461   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
462   pb_resource->set_id(0);
463   pb_resource->set_url(kLandingURL);
464 
465   pb_resource = expected.add_resources();
466   pb_resource->set_id(1);
467   pb_resource->set_url(kOriginalLandingURL);
468 
469   pb_resource = expected.add_resources();
470   pb_resource->set_id(2);
471   pb_resource->set_url(kMalwareURL);
472   pb_resource->set_parent_id(4);
473 
474   pb_resource = expected.add_resources();
475   pb_resource->set_id(3);
476   pb_resource->set_url(kFirstRedirectURL);
477   pb_resource->set_parent_id(1);
478 
479   pb_resource = expected.add_resources();
480   pb_resource->set_id(4);
481   pb_resource->set_url(kSecondRedirectURL);
482   pb_resource->set_parent_id(3);
483 
484   VerifyResults(actual, expected);
485 }
486 
487 // Tests the interaction with the HTTP cache.
TEST_F(MalwareDetailsTest,HTTPCache)488 TEST_F(MalwareDetailsTest, HTTPCache) {
489   controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED);
490 
491   SafeBrowsingService::UnsafeResource resource;
492   InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
493 
494   profile()->CreateRequestContext();
495   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
496       sb_service_.get(), contents(), resource
497       , profile()->GetRequestContext());
498 
499   FillCache(profile()->GetRequestContext()->GetURLRequestContext());
500 
501   // The cache collection starts after the IPC from the DOM is fired.
502   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
503   report->OnReceivedMalwareDOMDetails(params);
504 
505   // Let the cache callbacks complete
506   MessageLoop::current()->RunAllPending();
507 
508   DVLOG(1) << "Getting serialized report";
509   std::string serialized = WaitForSerializedReport(report);
510   ClientMalwareReportRequest actual;
511   actual.ParseFromString(serialized);
512 
513   ClientMalwareReportRequest expected;
514   expected.set_malware_url(kMalwareURL);
515   expected.set_page_url(kLandingURL);
516   expected.set_referrer_url("");
517 
518   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
519   pb_resource->set_id(0);
520   pb_resource->set_url(kLandingURL);
521   safe_browsing::ClientMalwareReportRequest::HTTPResponse* pb_response =
522       pb_resource->mutable_response();
523   pb_response->mutable_firstline()->set_code(200);
524   safe_browsing::ClientMalwareReportRequest::HTTPHeader* pb_header =
525       pb_response->add_headers();
526   pb_header->set_name("Content-Type");
527   pb_header->set_value("text/html");
528   pb_header = pb_response->add_headers();
529   pb_header->set_name("Content-Length");
530   pb_header->set_value("1024");
531   pb_header = pb_response->add_headers();
532   pb_header->set_name("Set-Cookie");
533   pb_header->set_value("");  // The cookie is dropped.
534   pb_response->set_body(kLandingData);
535   pb_response->set_bodylength(37);
536   pb_response->set_bodydigest("9ca97475598a79bc1e8fc9bd6c72cd35");
537 
538   pb_resource = expected.add_resources();
539   pb_resource->set_id(1);
540   pb_resource->set_url(kMalwareURL);
541   pb_response = pb_resource->mutable_response();
542   pb_response->mutable_firstline()->set_code(200);
543   pb_header = pb_response->add_headers();
544   pb_header->set_name("Content-Type");
545   pb_header->set_value("image/jpeg");
546   pb_response->set_body(kMalwareData);
547   pb_response->set_bodylength(10);
548   pb_response->set_bodydigest("581373551c43d4cf33bfb3b26838ff95");
549   expected.set_complete(true);
550 
551   VerifyResults(actual, expected);
552 }
553 
554 // Tests the interaction with the HTTP cache (where the cache is empty).
TEST_F(MalwareDetailsTest,HTTPCacheNoEntries)555 TEST_F(MalwareDetailsTest, HTTPCacheNoEntries) {
556   controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED);
557 
558   SafeBrowsingService::UnsafeResource resource;
559   InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
560 
561   profile()->CreateRequestContext();
562   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
563       sb_service_.get(), contents(), resource,
564       profile()->GetRequestContext());
565 
566   // No call to FillCache
567 
568   // The cache collection starts after the IPC from the DOM is fired.
569   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
570   report->OnReceivedMalwareDOMDetails(params);
571 
572   // Let the cache callbacks complete
573   MessageLoop::current()->RunAllPending();
574 
575   DVLOG(1) << "Getting serialized report";
576   std::string serialized = WaitForSerializedReport(report);
577   ClientMalwareReportRequest actual;
578   actual.ParseFromString(serialized);
579 
580   ClientMalwareReportRequest expected;
581   expected.set_malware_url(kMalwareURL);
582   expected.set_page_url(kLandingURL);
583   expected.set_referrer_url("");
584 
585   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
586   pb_resource->set_id(0);
587   pb_resource->set_url(kLandingURL);
588   pb_resource = expected.add_resources();
589   pb_resource->set_id(1);
590   pb_resource->set_url(kMalwareURL);
591   expected.set_complete(true);
592 
593   VerifyResults(actual, expected);
594 }
595