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
WriteHeaders(disk_cache::Entry * entry,const std::string & headers)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
WriteData(disk_cache::Entry * entry,const std::string & data)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
WriteToEntry(disk_cache::Backend * cache,const std::string & key,const std::string & headers,const std::string & data)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
FillCache(net::URLRequestContextGetter * context_getter)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:
MalwareDetailsWrap(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const SafeBrowsingUIManager::UnsafeResource & unsafe_resource,net::URLRequestContextGetter * request_context_getter)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:
~MalwareDetailsWrap()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.
MockSafeBrowsingUIManager()146 MockSafeBrowsingUIManager()
147 : SafeBrowsingUIManager(NULL), run_loop_(NULL) {}
148
149 // When the MalwareDetails is done, this is called.
SendSerializedMalwareDetails(const std::string & serialized)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.
SetRunLoopToQuit(base::RunLoop * run_loop)162 void SetRunLoopToQuit(base::RunLoop* run_loop) {
163 DCHECK(run_loop_ == NULL);
164 run_loop_ = run_loop;
165 }
166
GetSerialized()167 const std::string& GetSerialized() {
168 return serialized_;
169 }
170
171 private:
~MockSafeBrowsingUIManager()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
MalwareDetailsTest()184 MalwareDetailsTest()
185 : ui_manager_(new MockSafeBrowsingUIManager()) {
186 }
187
SetUp()188 virtual void SetUp() OVERRIDE {
189 ChromeRenderViewHostTestHarness::SetUp();
190 ASSERT_TRUE(profile()->CreateHistoryService(
191 true /* delete_file */, false /* no_db */));
192 }
193
TearDown()194 virtual void TearDown() OVERRIDE {
195 profile()->DestroyHistoryService();
196 ChromeRenderViewHostTestHarness::TearDown();
197 }
198
ResourceLessThan(const ClientMalwareReportRequest::Resource * lhs,const ClientMalwareReportRequest::Resource * rhs)199 static bool ResourceLessThan(
200 const ClientMalwareReportRequest::Resource* lhs,
201 const ClientMalwareReportRequest::Resource* rhs) {
202 return lhs->id() < rhs->id();
203 }
204
WaitForSerializedReport(MalwareDetails * report)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
history_service()218 HistoryService* history_service() {
219 return HistoryServiceFactory::GetForProfile(profile(),
220 Profile::EXPLICIT_ACCESS);
221 }
222
223 protected:
InitResource(UnsafeResource * resource,bool is_subresource,const GURL & url)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
VerifyResults(const ClientMalwareReportRequest & report_pb,const ClientMalwareReportRequest & expected_pb)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
VerifyResource(const ClientMalwareReportRequest::Resource * resource,const ClientMalwareReportRequest::Resource * expected)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.
AddPageToHistory(const GURL & url,history::RedirectList * redirects)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.
TEST_F(MalwareDetailsTest,MalwareSubResource)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.
TEST_F(MalwareDetailsTest,MalwareSubResourceWithOriginalUrl)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.
TEST_F(MalwareDetailsTest,MalwareDOMDetails)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.
TEST_F(MalwareDetailsTest,NotPublicUrl)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
TEST_F(MalwareDetailsTest,MalwareWithRedirectUrl)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.
TEST_F(MalwareDetailsTest,HTTPCache)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).
TEST_F(MalwareDetailsTest,HTTPCacheNoEntries)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.
TEST_F(MalwareDetailsTest,HistoryServiceUrls)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