Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / safe_browsing / malware_details_unittest.cc
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   ~MalwareDetailsWrap() override {}
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   void SendSerializedMalwareDetails(const std::string& serialized) override {
151     DVLOG(1) << "SendSerializedMalwareDetails";
152     run_loop_->Quit();
153     run_loop_ = NULL;
154     serialized_ = serialized;
155   }
156
157   // Used to synchronize SendSerializedMalwareDetails() with
158   // WaitForSerializedReport(). RunLoop::RunUntilIdle() is not sufficient
159   // because the MessageLoop task queue completely drains at some point
160   // between the send and the wait.
161   void SetRunLoopToQuit(base::RunLoop* run_loop) {
162     DCHECK(run_loop_ == NULL);
163     run_loop_ = run_loop;
164   }
165
166   const std::string& GetSerialized() {
167     return serialized_;
168   }
169
170  private:
171   ~MockSafeBrowsingUIManager() override {}
172
173   std::string serialized_;
174   DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager);
175 };
176
177 }  // namespace.
178
179 class MalwareDetailsTest : public ChromeRenderViewHostTestHarness {
180  public:
181   typedef SafeBrowsingUIManager::UnsafeResource UnsafeResource;
182
183   MalwareDetailsTest()
184       : ui_manager_(new MockSafeBrowsingUIManager()) {
185   }
186
187   void SetUp() override {
188     ChromeRenderViewHostTestHarness::SetUp();
189     ASSERT_TRUE(profile()->CreateHistoryService(
190         true /* delete_file */, false /* no_db */));
191   }
192
193   void TearDown() override {
194     profile()->DestroyHistoryService();
195     ChromeRenderViewHostTestHarness::TearDown();
196   }
197
198   static bool ResourceLessThan(
199       const ClientMalwareReportRequest::Resource* lhs,
200       const ClientMalwareReportRequest::Resource* rhs) {
201     return lhs->id() < rhs->id();
202   }
203
204   std::string WaitForSerializedReport(MalwareDetails* report) {
205     BrowserThread::PostTask(
206         BrowserThread::IO,
207         FROM_HERE,
208         base::Bind(&MalwareDetails::FinishCollection, report));
209     // Wait for the callback (SendSerializedMalwareDetails).
210     DVLOG(1) << "Waiting for SendSerializedMalwareDetails";
211     base::RunLoop run_loop;
212     ui_manager_->SetRunLoopToQuit(&run_loop);
213     run_loop.Run();
214     return ui_manager_->GetSerialized();
215   }
216
217   HistoryService* history_service() {
218     return HistoryServiceFactory::GetForProfile(profile(),
219                                                 Profile::EXPLICIT_ACCESS);
220   }
221
222  protected:
223   void InitResource(UnsafeResource* resource,
224                     bool is_subresource,
225                     const GURL& url) {
226     resource->url = url;
227     resource->is_subresource = is_subresource;
228     resource->threat_type = SB_THREAT_TYPE_URL_MALWARE;
229     resource->render_process_host_id =
230         web_contents()->GetRenderProcessHost()->GetID();
231     resource->render_view_id =
232         web_contents()->GetRenderViewHost()->GetRoutingID();
233   }
234
235   void VerifyResults(const ClientMalwareReportRequest& report_pb,
236                      const ClientMalwareReportRequest& expected_pb) {
237     EXPECT_EQ(expected_pb.malware_url(), report_pb.malware_url());
238     EXPECT_EQ(expected_pb.page_url(), report_pb.page_url());
239     EXPECT_EQ(expected_pb.referrer_url(), report_pb.referrer_url());
240
241     ASSERT_EQ(expected_pb.resources_size(), report_pb.resources_size());
242     // Sort the resources, to make the test deterministic
243     std::vector<const ClientMalwareReportRequest::Resource*> resources;
244     for (int i = 0; i < report_pb.resources_size(); ++i) {
245       const ClientMalwareReportRequest::Resource& resource =
246           report_pb.resources(i);
247       resources.push_back(&resource);
248     }
249     std::sort(resources.begin(), resources.end(),
250               &MalwareDetailsTest::ResourceLessThan);
251
252     std::vector<const ClientMalwareReportRequest::Resource*> expected;
253     for (int i = 0; i < report_pb.resources_size(); ++i) {
254       const ClientMalwareReportRequest::Resource& resource =
255           expected_pb.resources(i);
256       expected.push_back(&resource);
257     }
258     std::sort(expected.begin(), expected.end(),
259               &MalwareDetailsTest::ResourceLessThan);
260
261     for (uint32 i = 0; i < expected.size(); ++i) {
262       VerifyResource(resources[i], expected[i]);
263     }
264
265     EXPECT_EQ(expected_pb.complete(), report_pb.complete());
266   }
267
268   void VerifyResource(const ClientMalwareReportRequest::Resource* resource,
269                       const ClientMalwareReportRequest::Resource* expected) {
270     EXPECT_EQ(expected->id(), resource->id());
271     EXPECT_EQ(expected->url(), resource->url());
272     EXPECT_EQ(expected->parent_id(), resource->parent_id());
273     ASSERT_EQ(expected->child_ids_size(), resource->child_ids_size());
274     for (int i = 0; i < expected->child_ids_size(); i++) {
275       EXPECT_EQ(expected->child_ids(i), resource->child_ids(i));
276     }
277
278     // Verify HTTP Responses
279     if (expected->has_response()) {
280       ASSERT_TRUE(resource->has_response());
281       EXPECT_EQ(expected->response().firstline().code(),
282                 resource->response().firstline().code());
283
284       ASSERT_EQ(expected->response().headers_size(),
285                 resource->response().headers_size());
286       for (int i = 0; i < expected->response().headers_size(); ++i) {
287         EXPECT_EQ(expected->response().headers(i).name(),
288                   resource->response().headers(i).name());
289         EXPECT_EQ(expected->response().headers(i).value(),
290                   resource->response().headers(i).value());
291       }
292
293       EXPECT_EQ(expected->response().body(), resource->response().body());
294       EXPECT_EQ(expected->response().bodylength(),
295                 resource->response().bodylength());
296       EXPECT_EQ(expected->response().bodydigest(),
297                 resource->response().bodydigest());
298     }
299
300     // Verify IP:port pair
301     EXPECT_EQ(expected->response().remote_ip(),
302               resource->response().remote_ip());
303   }
304
305   // Adds a page to history.
306   // The redirects is the redirect url chain leading to the url.
307   void AddPageToHistory(const GURL& url,
308                         history::RedirectList* redirects) {
309     // The last item of the redirect chain has to be the final url when adding
310     // to history backend.
311     redirects->push_back(url);
312     history_service()->AddPage(
313         url, base::Time::Now(), reinterpret_cast<history::ContextID>(1), 0,
314         GURL(), *redirects, ui::PAGE_TRANSITION_TYPED,
315         history::SOURCE_BROWSED, false);
316   }
317
318   scoped_refptr<MockSafeBrowsingUIManager> ui_manager_;
319 };
320
321 // Tests creating a simple malware report.
322 TEST_F(MalwareDetailsTest, MalwareSubResource) {
323   // Start a load.
324   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
325                        ui::PAGE_TRANSITION_TYPED, std::string());
326
327   UnsafeResource resource;
328   InitResource(&resource, true, GURL(kMalwareURL));
329
330   scoped_refptr<MalwareDetailsWrap> report =
331       new MalwareDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL);
332
333   std::string serialized = WaitForSerializedReport(report.get());
334
335   ClientMalwareReportRequest actual;
336   actual.ParseFromString(serialized);
337
338   ClientMalwareReportRequest expected;
339   expected.set_malware_url(kMalwareURL);
340   expected.set_page_url(kLandingURL);
341   expected.set_referrer_url("");
342
343   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
344   pb_resource->set_id(0);
345   pb_resource->set_url(kLandingURL);
346   pb_resource = expected.add_resources();
347   pb_resource->set_id(1);
348   pb_resource->set_url(kMalwareURL);
349
350   VerifyResults(actual, expected);
351 }
352
353 // Tests creating a simple malware report where the subresource has a
354 // different original_url.
355 TEST_F(MalwareDetailsTest, MalwareSubResourceWithOriginalUrl) {
356   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
357                        ui::PAGE_TRANSITION_TYPED, std::string());
358
359   UnsafeResource resource;
360   InitResource(&resource, true, GURL(kMalwareURL));
361   resource.original_url = GURL(kOriginalLandingURL);
362
363   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
364       ui_manager_.get(), web_contents(), resource, NULL);
365
366   std::string serialized = WaitForSerializedReport(report.get());
367
368   ClientMalwareReportRequest actual;
369   actual.ParseFromString(serialized);
370
371   ClientMalwareReportRequest expected;
372   expected.set_malware_url(kMalwareURL);
373   expected.set_page_url(kLandingURL);
374   expected.set_referrer_url("");
375
376   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
377   pb_resource->set_id(0);
378   pb_resource->set_url(kLandingURL);
379
380   pb_resource = expected.add_resources();
381   pb_resource->set_id(1);
382   pb_resource->set_url(kOriginalLandingURL);
383
384   pb_resource = expected.add_resources();
385   pb_resource->set_id(2);
386   pb_resource->set_url(kMalwareURL);
387   // The Resource for kMmalwareUrl should have the Resource for
388   // kOriginalLandingURL (with id 1) as parent.
389   pb_resource->set_parent_id(1);
390
391   VerifyResults(actual, expected);
392 }
393
394 // Tests creating a malware report with data from the renderer.
395 TEST_F(MalwareDetailsTest, MalwareDOMDetails) {
396   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
397                        ui::PAGE_TRANSITION_TYPED, std::string());
398
399   UnsafeResource resource;
400   InitResource(&resource, true, GURL(kMalwareURL));
401
402   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
403       ui_manager_.get(), web_contents(), resource, NULL);
404
405   // Send a message from the DOM, with 2 nodes, a parent and a child.
406   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
407   SafeBrowsingHostMsg_MalwareDOMDetails_Node child_node;
408   child_node.url = GURL(kDOMChildURL);
409   child_node.tag_name = "iframe";
410   child_node.parent = GURL(kDOMParentURL);
411   params.push_back(child_node);
412   SafeBrowsingHostMsg_MalwareDOMDetails_Node parent_node;
413   parent_node.url = GURL(kDOMParentURL);
414   parent_node.children.push_back(GURL(kDOMChildURL));
415   params.push_back(parent_node);
416   report->OnReceivedMalwareDOMDetails(params);
417
418   std::string serialized = WaitForSerializedReport(report.get());
419   ClientMalwareReportRequest actual;
420   actual.ParseFromString(serialized);
421
422   ClientMalwareReportRequest expected;
423   expected.set_malware_url(kMalwareURL);
424   expected.set_page_url(kLandingURL);
425   expected.set_referrer_url("");
426
427   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
428   pb_resource->set_id(0);
429   pb_resource->set_url(kLandingURL);
430
431   pb_resource = expected.add_resources();
432   pb_resource->set_id(1);
433   pb_resource->set_url(kMalwareURL);
434
435   pb_resource = expected.add_resources();
436   pb_resource->set_id(2);
437   pb_resource->set_url(kDOMChildURL);
438   pb_resource->set_parent_id(3);
439
440   pb_resource = expected.add_resources();
441   pb_resource->set_id(3);
442   pb_resource->set_url(kDOMParentURL);
443   pb_resource->add_child_ids(2);
444   expected.set_complete(false);  // Since the cache was missing.
445
446   VerifyResults(actual, expected);
447 }
448
449 // Verify that https:// urls are dropped.
450 TEST_F(MalwareDetailsTest, NotPublicUrl) {
451   controller().LoadURL(GURL(kHttpsURL), content::Referrer(),
452                        ui::PAGE_TRANSITION_TYPED, std::string());
453   UnsafeResource resource;
454   InitResource(&resource, true, GURL(kMalwareURL));
455   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
456       ui_manager_.get(), web_contents(), resource, NULL);
457
458   std::string serialized = WaitForSerializedReport(report.get());
459   ClientMalwareReportRequest actual;
460   actual.ParseFromString(serialized);
461
462   ClientMalwareReportRequest expected;
463   expected.set_malware_url(kMalwareURL);  // No page_url
464   expected.set_referrer_url("");
465
466   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
467   pb_resource->set_url(kMalwareURL);  // Only one resource
468
469   VerifyResults(actual, expected);
470 }
471
472 // Tests creating a malware report where there are redirect urls to an unsafe
473 // resource url
474 TEST_F(MalwareDetailsTest, MalwareWithRedirectUrl) {
475   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
476                        ui::PAGE_TRANSITION_TYPED, std::string());
477
478   UnsafeResource resource;
479   InitResource(&resource, true, GURL(kMalwareURL));
480   resource.original_url = GURL(kOriginalLandingURL);
481
482   // add some redirect urls
483   resource.redirect_urls.push_back(GURL(kFirstRedirectURL));
484   resource.redirect_urls.push_back(GURL(kSecondRedirectURL));
485   resource.redirect_urls.push_back(GURL(kMalwareURL));
486
487   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
488       ui_manager_.get(), web_contents(), resource, NULL);
489
490   std::string serialized = WaitForSerializedReport(report.get());
491   ClientMalwareReportRequest actual;
492   actual.ParseFromString(serialized);
493
494   ClientMalwareReportRequest expected;
495   expected.set_malware_url(kMalwareURL);
496   expected.set_page_url(kLandingURL);
497   expected.set_referrer_url("");
498
499   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
500   pb_resource->set_id(0);
501   pb_resource->set_url(kLandingURL);
502
503   pb_resource = expected.add_resources();
504   pb_resource->set_id(1);
505   pb_resource->set_url(kOriginalLandingURL);
506
507   pb_resource = expected.add_resources();
508   pb_resource->set_id(2);
509   pb_resource->set_url(kMalwareURL);
510   pb_resource->set_parent_id(4);
511
512   pb_resource = expected.add_resources();
513   pb_resource->set_id(3);
514   pb_resource->set_url(kFirstRedirectURL);
515   pb_resource->set_parent_id(1);
516
517   pb_resource = expected.add_resources();
518   pb_resource->set_id(4);
519   pb_resource->set_url(kSecondRedirectURL);
520   pb_resource->set_parent_id(3);
521
522   VerifyResults(actual, expected);
523 }
524
525 // Tests the interaction with the HTTP cache.
526 TEST_F(MalwareDetailsTest, HTTPCache) {
527   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
528                        ui::PAGE_TRANSITION_TYPED, std::string());
529
530   UnsafeResource resource;
531   InitResource(&resource, true, GURL(kMalwareURL));
532
533   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
534       ui_manager_.get(), web_contents(), resource,
535       profile()->GetRequestContext());
536
537   BrowserThread::PostTask(
538       BrowserThread::IO, FROM_HERE,
539       base::Bind(&FillCache,
540                  make_scoped_refptr(profile()->GetRequestContext())));
541
542   // The cache collection starts after the IPC from the DOM is fired.
543   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
544   report->OnReceivedMalwareDOMDetails(params);
545
546   // Let the cache callbacks complete.
547   base::RunLoop().RunUntilIdle();
548
549   DVLOG(1) << "Getting serialized report";
550   std::string serialized = WaitForSerializedReport(report.get());
551   ClientMalwareReportRequest actual;
552   actual.ParseFromString(serialized);
553
554   ClientMalwareReportRequest expected;
555   expected.set_malware_url(kMalwareURL);
556   expected.set_page_url(kLandingURL);
557   expected.set_referrer_url("");
558
559   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
560   pb_resource->set_id(0);
561   pb_resource->set_url(kLandingURL);
562   safe_browsing::ClientMalwareReportRequest::HTTPResponse* pb_response =
563       pb_resource->mutable_response();
564   pb_response->mutable_firstline()->set_code(200);
565   safe_browsing::ClientMalwareReportRequest::HTTPHeader* pb_header =
566       pb_response->add_headers();
567   pb_header->set_name("Content-Type");
568   pb_header->set_value("text/html");
569   pb_header = pb_response->add_headers();
570   pb_header->set_name("Content-Length");
571   pb_header->set_value("1024");
572   pb_header = pb_response->add_headers();
573   pb_header->set_name("Set-Cookie");
574   pb_header->set_value("");  // The cookie is dropped.
575   pb_response->set_body(kLandingData);
576   pb_response->set_bodylength(37);
577   pb_response->set_bodydigest("9ca97475598a79bc1e8fc9bd6c72cd35");
578   pb_response->set_remote_ip("1.2.3.4:80");
579
580   pb_resource = expected.add_resources();
581   pb_resource->set_id(1);
582   pb_resource->set_url(kMalwareURL);
583   pb_response = pb_resource->mutable_response();
584   pb_response->mutable_firstline()->set_code(200);
585   pb_header = pb_response->add_headers();
586   pb_header->set_name("Content-Type");
587   pb_header->set_value("image/jpeg");
588   pb_response->set_body(kMalwareData);
589   pb_response->set_bodylength(10);
590   pb_response->set_bodydigest("581373551c43d4cf33bfb3b26838ff95");
591   pb_response->set_remote_ip("1.2.3.4:80");
592   expected.set_complete(true);
593
594   VerifyResults(actual, expected);
595 }
596
597 // Tests the interaction with the HTTP cache (where the cache is empty).
598 TEST_F(MalwareDetailsTest, HTTPCacheNoEntries) {
599   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
600                        ui::PAGE_TRANSITION_TYPED, std::string());
601
602   UnsafeResource resource;
603   InitResource(&resource, true, GURL(kMalwareURL));
604
605   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
606       ui_manager_.get(), web_contents(), resource,
607       profile()->GetRequestContext());
608
609   // No call to FillCache
610
611   // The cache collection starts after the IPC from the DOM is fired.
612   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
613   report->OnReceivedMalwareDOMDetails(params);
614
615   // Let the cache callbacks complete.
616   base::RunLoop().RunUntilIdle();
617
618   DVLOG(1) << "Getting serialized report";
619   std::string serialized = WaitForSerializedReport(report.get());
620   ClientMalwareReportRequest actual;
621   actual.ParseFromString(serialized);
622
623   ClientMalwareReportRequest expected;
624   expected.set_malware_url(kMalwareURL);
625   expected.set_page_url(kLandingURL);
626   expected.set_referrer_url("");
627
628   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
629   pb_resource->set_id(0);
630   pb_resource->set_url(kLandingURL);
631   pb_resource = expected.add_resources();
632   pb_resource->set_id(1);
633   pb_resource->set_url(kMalwareURL);
634   expected.set_complete(true);
635
636   VerifyResults(actual, expected);
637 }
638
639 // Test getting redirects from history service.
640 TEST_F(MalwareDetailsTest, HistoryServiceUrls) {
641   // Add content to history service.
642   // There are two redirect urls before reacing malware url:
643   // kFirstRedirectURL -> kSecondRedirectURL -> kMalwareURL
644   GURL baseurl(kMalwareURL);
645   history::RedirectList redirects;
646   redirects.push_back(GURL(kFirstRedirectURL));
647   redirects.push_back(GURL(kSecondRedirectURL));
648   AddPageToHistory(baseurl, &redirects);
649   // Wait for history service operation finished.
650   profile()->BlockUntilHistoryProcessesPendingRequests();
651
652   controller().LoadURL(GURL(kLandingURL), content::Referrer(),
653                        ui::PAGE_TRANSITION_TYPED, std::string());
654
655   UnsafeResource resource;
656   InitResource(&resource, true, GURL(kMalwareURL));
657   scoped_refptr<MalwareDetailsWrap> report = new MalwareDetailsWrap(
658       ui_manager_.get(), web_contents(), resource, NULL);
659
660   // The redirects collection starts after the IPC from the DOM is fired.
661   std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node> params;
662   report->OnReceivedMalwareDOMDetails(params);
663
664   // Let the redirects callbacks complete.
665   base::RunLoop().RunUntilIdle();
666
667   std::string serialized = WaitForSerializedReport(report.get());
668   ClientMalwareReportRequest actual;
669   actual.ParseFromString(serialized);
670
671   ClientMalwareReportRequest expected;
672   expected.set_malware_url(kMalwareURL);
673   expected.set_page_url(kLandingURL);
674   expected.set_referrer_url("");
675
676   ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources();
677   pb_resource->set_id(0);
678   pb_resource->set_url(kLandingURL);
679   pb_resource = expected.add_resources();
680   pb_resource->set_id(1);
681   pb_resource->set_parent_id(2);
682   pb_resource->set_url(kMalwareURL);
683   pb_resource = expected.add_resources();
684   pb_resource->set_id(2);
685   pb_resource->set_parent_id(3);
686   pb_resource->set_url(kSecondRedirectURL);
687   pb_resource = expected.add_resources();
688   pb_resource->set_id(3);
689   pb_resource->set_url(kFirstRedirectURL);
690
691   VerifyResults(actual, expected);
692 }