OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/safe_browsing/download_protection_service.h" | 5 #include "chrome/browser/safe_browsing/download_protection_service.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/callback.h" | 11 #include "base/callback.h" |
12 #include "base/file_path.h" | |
13 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
14 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
15 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
16 #include "chrome/common/safe_browsing/csd.pb.h" | 15 #include "chrome/common/safe_browsing/csd.pb.h" |
17 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | 16 #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
18 #include "content/browser/browser_thread.h" | 17 #include "content/browser/browser_thread.h" |
19 #include "content/browser/download/download_item.h" | |
20 #include "content/public/common/url_fetcher_delegate.h" | |
21 #include "content/test/test_url_fetcher_factory.h" | 18 #include "content/test/test_url_fetcher_factory.h" |
22 #include "googleurl/src/gurl.h" | 19 #include "googleurl/src/gurl.h" |
23 #include "testing/gmock/include/gmock/gmock.h" | 20 #include "testing/gmock/include/gmock/gmock.h" |
24 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
25 | 22 |
26 using ::testing::Return; | 23 using ::testing::Return; |
27 using ::testing::_; | 24 using ::testing::_; |
28 | 25 |
29 namespace safe_browsing { | 26 namespace safe_browsing { |
30 namespace { | 27 namespace { |
31 class MockSafeBrowsingService : public SafeBrowsingService { | 28 class MockSafeBrowsingService : public SafeBrowsingService { |
32 public: | 29 public: |
33 MockSafeBrowsingService() {} | 30 MockSafeBrowsingService() {} |
34 virtual ~MockSafeBrowsingService() {} | 31 virtual ~MockSafeBrowsingService() {} |
35 | 32 |
36 MOCK_METHOD1(MatchDownloadWhitelistUrl, bool(const GURL&)); | 33 MOCK_METHOD1(MatchDownloadWhitelistUrl, bool(const GURL&)); |
37 | 34 |
38 private: | 35 private: |
39 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingService); | 36 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingService); |
40 }; | 37 }; |
41 } // namespace | 38 } // namespace |
42 | 39 |
43 class DownloadProtectionServiceTest : public testing::Test { | 40 class DownloadProtectionServiceTest : public testing::Test { |
44 protected: | 41 protected: |
45 virtual void SetUp() { | 42 virtual void SetUp() { |
46 ui_thread_.reset(new BrowserThread(BrowserThread::UI, &msg_loop_)); | 43 ui_thread_.reset(new BrowserThread(BrowserThread::UI, &msg_loop_)); |
47 // Start real threads for the IO and File threads so that the DCHECKs | 44 io_thread_.reset(new BrowserThread(BrowserThread::IO, &msg_loop_)); |
48 // to test that we're on the correct thread work. | |
49 io_thread_.reset(new BrowserThread(BrowserThread::IO)); | |
50 ASSERT_TRUE(io_thread_->Start()); | |
51 file_thread_.reset(new BrowserThread(BrowserThread::FILE)); | |
52 ASSERT_TRUE(file_thread_->Start()); | |
53 sb_service_ = new MockSafeBrowsingService(); | 45 sb_service_ = new MockSafeBrowsingService(); |
54 download_service_ = sb_service_->download_protection_service(); | 46 download_service_ = new DownloadProtectionService(sb_service_.get(), |
| 47 NULL); |
55 download_service_->SetEnabled(true); | 48 download_service_->SetEnabled(true); |
56 msg_loop_.RunAllPending(); | 49 msg_loop_.RunAllPending(); |
57 } | 50 } |
58 | 51 |
59 virtual void TearDown() { | 52 virtual void TearDown() { |
60 // Flush all of the thread message loops to ensure that there are no | 53 msg_loop_.RunAllPending(); |
61 // tasks currently running. | 54 download_service_ = NULL; |
62 FlushThreadMessageLoops(); | |
63 sb_service_ = NULL; | 55 sb_service_ = NULL; |
64 io_thread_.reset(); | 56 io_thread_.reset(); |
65 file_thread_.reset(); | |
66 ui_thread_.reset(); | 57 ui_thread_.reset(); |
67 } | 58 } |
68 | 59 |
69 bool RequestContainsResource(const ClientDownloadRequest& request, | 60 bool RequestContainsResource(const ClientDownloadRequest& request, |
70 ClientDownloadRequest::ResourceType type, | 61 ClientDownloadRequest::ResourceType type, |
71 const std::string& url, | 62 const std::string& url, |
72 const std::string& referrer) { | 63 const std::string& referrer) { |
73 for (int i = 0; i < request.resources_size(); ++i) { | 64 for (int i = 0; i < request.resources_size(); ++i) { |
74 if (request.resources(i).url() == url && | 65 if (request.resources(i).url() == url && |
75 request.resources(i).type() == type && | 66 request.resources(i).type() == type && |
76 (referrer.empty() || request.resources(i).referrer() == referrer)) { | 67 (referrer.empty() || request.resources(i).referrer() == referrer)) { |
77 return true; | 68 return true; |
78 } | 69 } |
79 } | 70 } |
80 return false; | 71 return false; |
81 } | 72 } |
82 | 73 |
83 // Flushes any pending tasks in the message loops of all threads. | |
84 void FlushThreadMessageLoops() { | |
85 FlushMessageLoop(BrowserThread::FILE); | |
86 FlushMessageLoop(BrowserThread::IO); | |
87 msg_loop_.RunAllPending(); | |
88 } | |
89 | |
90 private: | |
91 // Helper functions for FlushThreadMessageLoops. | |
92 void RunAllPendingAndQuitUI() { | |
93 MessageLoop::current()->RunAllPending(); | |
94 BrowserThread::PostTask( | |
95 BrowserThread::UI, | |
96 FROM_HERE, | |
97 base::Bind(&DownloadProtectionServiceTest::QuitMessageLoop, | |
98 base::Unretained(this))); | |
99 } | |
100 | |
101 void QuitMessageLoop() { | |
102 MessageLoop::current()->Quit(); | |
103 } | |
104 | |
105 void PostRunMessageLoopTask(BrowserThread::ID thread) { | |
106 BrowserThread::PostTask( | |
107 thread, | |
108 FROM_HERE, | |
109 base::Bind(&DownloadProtectionServiceTest::RunAllPendingAndQuitUI, | |
110 base::Unretained(this))); | |
111 } | |
112 | |
113 void FlushMessageLoop(BrowserThread::ID thread) { | |
114 BrowserThread::PostTask( | |
115 BrowserThread::UI, | |
116 FROM_HERE, | |
117 base::Bind(&DownloadProtectionServiceTest::PostRunMessageLoopTask, | |
118 base::Unretained(this), thread)); | |
119 msg_loop_.Run(); | |
120 } | |
121 | |
122 public: | 74 public: |
123 void CheckDoneCallback( | 75 void CheckDoneCallback( |
124 DownloadProtectionService::DownloadCheckResult result) { | 76 DownloadProtectionService::DownloadCheckResult result) { |
125 result_ = result; | 77 result_ = result; |
126 msg_loop_.Quit(); | 78 msg_loop_.Quit(); |
127 } | 79 } |
128 | 80 |
129 void SendURLFetchComplete(TestURLFetcher* fetcher) { | |
130 fetcher->delegate()->OnURLFetchComplete(fetcher); | |
131 } | |
132 | |
133 protected: | 81 protected: |
134 scoped_refptr<MockSafeBrowsingService> sb_service_; | 82 scoped_refptr<MockSafeBrowsingService> sb_service_; |
135 DownloadProtectionService* download_service_; | 83 scoped_refptr<DownloadProtectionService> download_service_; |
136 MessageLoop msg_loop_; | 84 MessageLoop msg_loop_; |
137 DownloadProtectionService::DownloadCheckResult result_; | 85 DownloadProtectionService::DownloadCheckResult result_; |
138 scoped_ptr<BrowserThread> io_thread_; | 86 scoped_ptr<BrowserThread> io_thread_; |
139 scoped_ptr<BrowserThread> file_thread_; | |
140 scoped_ptr<BrowserThread> ui_thread_; | 87 scoped_ptr<BrowserThread> ui_thread_; |
141 }; | 88 }; |
142 | 89 |
143 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadInvalidUrl) { | 90 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadInvalidUrl) { |
144 DownloadProtectionService::DownloadInfo info; | 91 DownloadProtectionService::DownloadInfo info; |
145 download_service_->CheckClientDownload( | 92 EXPECT_TRUE(download_service_->CheckClientDownload( |
146 info, | 93 info, |
147 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 94 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
148 base::Unretained(this))); | 95 base::Unretained(this)))); |
149 msg_loop_.Run(); | |
150 EXPECT_EQ(DownloadProtectionService::SAFE, result_); | |
151 | |
152 // Only http is supported for now. | 96 // Only http is supported for now. |
153 info.local_file = FilePath(FILE_PATH_LITERAL("a.exe")); | |
154 info.download_url_chain.push_back(GURL("https://www.google.com/")); | 97 info.download_url_chain.push_back(GURL("https://www.google.com/")); |
155 download_service_->CheckClientDownload( | 98 EXPECT_TRUE(download_service_->CheckClientDownload( |
156 info, | 99 info, |
157 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 100 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
158 base::Unretained(this))); | 101 base::Unretained(this)))); |
159 msg_loop_.Run(); | |
160 EXPECT_EQ(DownloadProtectionService::SAFE, result_); | |
161 | |
162 info.download_url_chain[0] = GURL("ftp://www.google.com/"); | 102 info.download_url_chain[0] = GURL("ftp://www.google.com/"); |
163 download_service_->CheckClientDownload( | 103 EXPECT_TRUE(download_service_->CheckClientDownload( |
164 info, | 104 info, |
165 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 105 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
166 base::Unretained(this))); | 106 base::Unretained(this)))); |
167 msg_loop_.Run(); | |
168 EXPECT_EQ(DownloadProtectionService::SAFE, result_); | |
169 } | 107 } |
170 | 108 |
171 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadWhitelistedUrl) { | 109 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadWhitelistedUrl) { |
172 DownloadProtectionService::DownloadInfo info; | 110 DownloadProtectionService::DownloadInfo info; |
173 info.local_file = FilePath(FILE_PATH_LITERAL("a.exe")); | |
174 info.download_url_chain.push_back(GURL("http://www.evil.com/bla.exe")); | 111 info.download_url_chain.push_back(GURL("http://www.evil.com/bla.exe")); |
175 info.download_url_chain.push_back(GURL("http://www.google.com/a.exe")); | 112 info.download_url_chain.push_back(GURL("http://www.google.com/a.exe")); |
176 info.referrer_url = GURL("http://www.google.com/"); | 113 info.referrer_url = GURL("http://www.google.com/"); |
177 | 114 |
178 EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) | 115 EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) |
179 .WillRepeatedly(Return(false)); | 116 .WillRepeatedly(Return(false)); |
180 EXPECT_CALL(*sb_service_, | 117 EXPECT_CALL(*sb_service_, |
181 MatchDownloadWhitelistUrl(GURL("http://www.google.com/a.exe"))) | 118 MatchDownloadWhitelistUrl(GURL("http://www.google.com/a.exe"))) |
182 .WillRepeatedly(Return(true)); | 119 .WillRepeatedly(Return(true)); |
183 | 120 |
184 download_service_->CheckClientDownload( | 121 EXPECT_FALSE(download_service_->CheckClientDownload( |
185 info, | 122 info, |
186 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 123 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
187 base::Unretained(this))); | 124 base::Unretained(this)))); |
188 msg_loop_.Run(); | 125 msg_loop_.Run(); |
189 EXPECT_EQ(DownloadProtectionService::SAFE, result_); | 126 EXPECT_EQ(DownloadProtectionService::SAFE, result_); |
190 | 127 |
191 // Check that the referrer is matched against the whitelist. | 128 // Check that the referrer is matched against the whitelist. |
192 info.download_url_chain.pop_back(); | 129 info.download_url_chain.pop_back(); |
193 info.referrer_url = GURL("http://www.google.com/a.exe"); | 130 info.referrer_url = GURL("http://www.google.com/a.exe"); |
194 download_service_->CheckClientDownload( | 131 EXPECT_FALSE(download_service_->CheckClientDownload( |
195 info, | 132 info, |
196 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 133 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
197 base::Unretained(this))); | 134 base::Unretained(this)))); |
198 msg_loop_.Run(); | 135 msg_loop_.Run(); |
199 EXPECT_EQ(DownloadProtectionService::SAFE, result_); | 136 EXPECT_EQ(DownloadProtectionService::SAFE, result_); |
200 } | 137 } |
201 | 138 |
202 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadFetchFailed) { | 139 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadFetchFailed) { |
203 FakeURLFetcherFactory factory; | 140 FakeURLFetcherFactory factory; |
204 // HTTP request will fail. | 141 // HTTP request will fail. |
205 factory.SetFakeResponse( | 142 factory.SetFakeResponse( |
206 DownloadProtectionService::kDownloadRequestUrl, "", false); | 143 DownloadProtectionService::kDownloadRequestUrl, "", false); |
207 | 144 |
208 EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) | 145 EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) |
209 .WillRepeatedly(Return(false)); | 146 .WillRepeatedly(Return(false)); |
210 | 147 |
211 DownloadProtectionService::DownloadInfo info; | 148 DownloadProtectionService::DownloadInfo info; |
212 info.local_file = FilePath(FILE_PATH_LITERAL("a.exe")); | |
213 info.download_url_chain.push_back(GURL("http://www.evil.com/a.exe")); | 149 info.download_url_chain.push_back(GURL("http://www.evil.com/a.exe")); |
214 info.referrer_url = GURL("http://www.google.com/"); | 150 info.referrer_url = GURL("http://www.google.com/"); |
215 download_service_->CheckClientDownload( | 151 EXPECT_FALSE(download_service_->CheckClientDownload( |
216 info, | 152 info, |
217 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 153 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
218 base::Unretained(this))); | 154 base::Unretained(this)))); |
219 msg_loop_.Run(); | 155 msg_loop_.Run(); |
220 EXPECT_EQ(DownloadProtectionService::SAFE, result_); | 156 EXPECT_EQ(DownloadProtectionService::SAFE, result_); |
221 } | 157 } |
222 | 158 |
223 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadSuccess) { | 159 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadSuccess) { |
224 FakeURLFetcherFactory factory; | 160 FakeURLFetcherFactory factory; |
225 // Empty response means SAFE. | 161 // Empty response means SAFE. |
226 factory.SetFakeResponse( | 162 factory.SetFakeResponse( |
227 DownloadProtectionService::kDownloadRequestUrl, "", true); | 163 DownloadProtectionService::kDownloadRequestUrl, "", true); |
228 | 164 |
229 EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) | 165 EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) |
230 .WillRepeatedly(Return(false)); | 166 .WillRepeatedly(Return(false)); |
231 | 167 |
232 DownloadProtectionService::DownloadInfo info; | 168 DownloadProtectionService::DownloadInfo info; |
233 info.local_file = FilePath(FILE_PATH_LITERAL("a.exe")); | |
234 info.download_url_chain.push_back(GURL("http://www.evil.com/a.exe")); | 169 info.download_url_chain.push_back(GURL("http://www.evil.com/a.exe")); |
235 info.referrer_url = GURL("http://www.google.com/"); | 170 info.referrer_url = GURL("http://www.google.com/"); |
236 download_service_->CheckClientDownload( | 171 EXPECT_FALSE(download_service_->CheckClientDownload( |
237 info, | 172 info, |
238 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 173 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
239 base::Unretained(this))); | 174 base::Unretained(this)))); |
240 msg_loop_.Run(); | 175 msg_loop_.Run(); |
241 EXPECT_EQ(DownloadProtectionService::SAFE, result_); | 176 EXPECT_EQ(DownloadProtectionService::SAFE, result_); |
242 | 177 |
243 // Invalid response should be safe too. | 178 // Invalid response should be safe too. |
244 factory.SetFakeResponse( | 179 factory.SetFakeResponse( |
245 DownloadProtectionService::kDownloadRequestUrl, "bla", true); | 180 DownloadProtectionService::kDownloadRequestUrl, "bla", true); |
246 | 181 |
247 download_service_->CheckClientDownload( | 182 EXPECT_FALSE(download_service_->CheckClientDownload( |
248 info, | 183 info, |
249 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 184 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
250 base::Unretained(this))); | 185 base::Unretained(this)))); |
251 msg_loop_.Run(); | 186 msg_loop_.Run(); |
252 EXPECT_EQ(DownloadProtectionService::SAFE, result_); | 187 EXPECT_EQ(DownloadProtectionService::SAFE, result_); |
253 } | 188 } |
254 | 189 |
255 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadValidateRequest) { | 190 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadValidateRequest) { |
256 TestURLFetcherFactory factory; | 191 TestURLFetcherFactory factory; |
257 | 192 |
258 DownloadProtectionService::DownloadInfo info; | 193 DownloadProtectionService::DownloadInfo info; |
259 info.local_file = FilePath(FILE_PATH_LITERAL("bla.exe")); | |
260 info.download_url_chain.push_back(GURL("http://www.google.com/")); | 194 info.download_url_chain.push_back(GURL("http://www.google.com/")); |
261 info.download_url_chain.push_back(GURL("http://www.google.com/bla.exe")); | 195 info.download_url_chain.push_back(GURL("http://www.google.com/bla.exe")); |
262 info.referrer_url = GURL("http://www.google.com/"); | 196 info.referrer_url = GURL("http://www.google.com/"); |
263 info.sha256_hash = "hash"; | 197 info.sha256_hash = "hash"; |
264 info.total_bytes = 100; | 198 info.total_bytes = 100; |
265 info.user_initiated = false; | 199 info.user_initiated = false; |
266 | 200 |
267 EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) | 201 EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) |
268 .WillRepeatedly(Return(false)); | 202 .WillRepeatedly(Return(false)); |
269 download_service_->CheckClientDownload( | 203 EXPECT_FALSE(download_service_->CheckClientDownload( |
270 info, | 204 info, |
271 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, | 205 base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, |
272 base::Unretained(this))); | 206 base::Unretained(this)))); |
273 // Run the message loop(s) until SendRequest is called. | 207 msg_loop_.RunAllPending(); // Wait until StartCheckClientDownload is called. |
274 FlushThreadMessageLoops(); | |
275 | 208 |
276 TestURLFetcher* fetcher = factory.GetFetcherByID(0); | 209 ASSERT_TRUE(factory.GetFetcherByID(0)); |
277 ASSERT_TRUE(fetcher); | |
278 ClientDownloadRequest request; | 210 ClientDownloadRequest request; |
279 EXPECT_TRUE(request.ParseFromString(fetcher->upload_data())); | 211 EXPECT_TRUE(request.ParseFromString( |
| 212 factory.GetFetcherByID(0)->upload_data())); |
280 EXPECT_EQ("http://www.google.com/bla.exe", request.url()); | 213 EXPECT_EQ("http://www.google.com/bla.exe", request.url()); |
281 EXPECT_EQ(info.sha256_hash, request.digests().sha256()); | 214 EXPECT_EQ(info.sha256_hash, request.digests().sha256()); |
282 EXPECT_EQ(info.total_bytes, request.length()); | 215 EXPECT_EQ(info.total_bytes, request.length()); |
283 EXPECT_EQ(info.user_initiated, request.user_initiated()); | 216 EXPECT_EQ(info.user_initiated, request.user_initiated()); |
284 EXPECT_EQ(2, request.resources_size()); | 217 EXPECT_EQ(2, request.resources_size()); |
285 EXPECT_TRUE(RequestContainsResource(request, | 218 EXPECT_TRUE(RequestContainsResource(request, |
286 ClientDownloadRequest::DOWNLOAD_REDIRECT, | 219 ClientDownloadRequest::DOWNLOAD_REDIRECT, |
287 "http://www.google.com/", "")); | 220 "http://www.google.com/", "")); |
288 EXPECT_TRUE(RequestContainsResource(request, | 221 EXPECT_TRUE(RequestContainsResource(request, |
289 ClientDownloadRequest::DOWNLOAD_URL, | 222 ClientDownloadRequest::DOWNLOAD_URL, |
290 "http://www.google.com/bla.exe", | 223 "http://www.google.com/bla.exe", |
291 info.referrer_url.spec())); | 224 info.referrer_url.spec())); |
292 | |
293 // Simulate the request finishing. | |
294 MessageLoop::current()->PostTask( | |
295 FROM_HERE, | |
296 base::Bind(&DownloadProtectionServiceTest::SendURLFetchComplete, | |
297 base::Unretained(this), fetcher)); | |
298 msg_loop_.Run(); | |
299 } | 225 } |
300 } // namespace safe_browsing | 226 } // namespace safe_browsing |
OLD | NEW |