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