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