| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2013 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 "chrome/browser/safe_browsing/download_feedback_service.h" | 
|  | 6 | 
|  | 7 #include "base/command_line.h" | 
|  | 8 #include "base/file_util.h" | 
|  | 9 #include "base/files/scoped_temp_dir.h" | 
|  | 10 #include "base/run_loop.h" | 
|  | 11 #include "base/strings/string_number_conversions.h" | 
|  | 12 #include "chrome/browser/safe_browsing/download_feedback.h" | 
|  | 13 #include "chrome/common/chrome_switches.h" | 
|  | 14 #include "content/public/browser/browser_thread.h" | 
|  | 15 #include "content/public/test/mock_download_item.h" | 
|  | 16 #include "content/public/test/test_browser_thread_bundle.h" | 
|  | 17 #include "net/url_request/url_request_test_util.h" | 
|  | 18 #include "testing/gmock/include/gmock/gmock.h" | 
|  | 19 #include "testing/gtest/include/gtest/gtest.h" | 
|  | 20 | 
|  | 21 using ::testing::_; | 
|  | 22 using ::testing::Return; | 
|  | 23 using ::testing::SaveArg; | 
|  | 24 | 
|  | 25 namespace safe_browsing { | 
|  | 26 | 
|  | 27 namespace { | 
|  | 28 | 
|  | 29 class FakeDownloadFeedback : public DownloadFeedback { | 
|  | 30  public: | 
|  | 31   FakeDownloadFeedback(net::URLRequestContextGetter* request_context_getter, | 
|  | 32                        base::TaskRunner* file_task_runner, | 
|  | 33                        const base::FilePath& file_path, | 
|  | 34                        const std::string& ping_request, | 
|  | 35                        const std::string& ping_response, | 
|  | 36                        base::Closure deletion_callback) | 
|  | 37       : ping_request_(ping_request), | 
|  | 38         ping_response_(ping_response), | 
|  | 39         deletion_callback_(deletion_callback), | 
|  | 40         start_called_(false) { | 
|  | 41   } | 
|  | 42 | 
|  | 43   virtual ~FakeDownloadFeedback() { | 
|  | 44     deletion_callback_.Run(); | 
|  | 45   } | 
|  | 46 | 
|  | 47   virtual void Start(const base::Closure& finish_callback) OVERRIDE { | 
|  | 48     start_called_ = true; | 
|  | 49     finish_callback_ = finish_callback; | 
|  | 50   } | 
|  | 51 | 
|  | 52   virtual const std::string& GetPingRequestForTesting() const OVERRIDE { | 
|  | 53     return ping_request_; | 
|  | 54   } | 
|  | 55 | 
|  | 56   virtual const std::string& GetPingResponseForTesting() const OVERRIDE { | 
|  | 57     return ping_response_; | 
|  | 58   } | 
|  | 59 | 
|  | 60   base::Closure finish_callback() const { | 
|  | 61     return finish_callback_; | 
|  | 62   } | 
|  | 63 | 
|  | 64   bool start_called() const { | 
|  | 65     return start_called_; | 
|  | 66   } | 
|  | 67 | 
|  | 68  private: | 
|  | 69   scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | 
|  | 70   scoped_refptr<base::TaskRunner> file_task_runner_; | 
|  | 71   base::FilePath file_path_; | 
|  | 72   std::string ping_request_; | 
|  | 73   std::string ping_response_; | 
|  | 74 | 
|  | 75   base::Closure finish_callback_; | 
|  | 76   base::Closure deletion_callback_; | 
|  | 77   bool start_called_; | 
|  | 78 }; | 
|  | 79 | 
|  | 80 class FakeDownloadFeedbackFactory : public DownloadFeedbackFactory { | 
|  | 81  public: | 
|  | 82   virtual ~FakeDownloadFeedbackFactory() {} | 
|  | 83 | 
|  | 84   virtual DownloadFeedback* CreateDownloadFeedback( | 
|  | 85       net::URLRequestContextGetter* request_context_getter, | 
|  | 86       base::TaskRunner* file_task_runner, | 
|  | 87       const base::FilePath& file_path, | 
|  | 88       const std::string& ping_request, | 
|  | 89       const std::string& ping_response) OVERRIDE { | 
|  | 90     FakeDownloadFeedback* feedback = new FakeDownloadFeedback( | 
|  | 91         request_context_getter, | 
|  | 92         file_task_runner, | 
|  | 93         file_path, | 
|  | 94         ping_request, | 
|  | 95         ping_response, | 
|  | 96         base::Bind(&FakeDownloadFeedbackFactory::DownloadFeedbackDeleted, | 
|  | 97                    base::Unretained(this), | 
|  | 98                    feedbacks_.size())); | 
|  | 99     feedbacks_.push_back(feedback); | 
|  | 100     return feedback; | 
|  | 101   } | 
|  | 102 | 
|  | 103   void DownloadFeedbackDeleted(size_t n) { | 
|  | 104     feedbacks_[n] = NULL; | 
|  | 105   } | 
|  | 106 | 
|  | 107   FakeDownloadFeedback* feedback(size_t n) const { | 
|  | 108     return feedbacks_[n]; | 
|  | 109   } | 
|  | 110 | 
|  | 111   size_t num_feedbacks() const { | 
|  | 112     return feedbacks_.size(); | 
|  | 113   } | 
|  | 114 | 
|  | 115  private: | 
|  | 116   std::vector<FakeDownloadFeedback*> feedbacks_; | 
|  | 117 }; | 
|  | 118 | 
|  | 119 bool WillStorePings(DownloadProtectionService::DownloadCheckResult result, | 
|  | 120                      int64 size) { | 
|  | 121   content::MockDownloadItem item; | 
|  | 122   EXPECT_CALL(item, GetReceivedBytes()).WillRepeatedly(Return(size)); | 
|  | 123 | 
|  | 124   EXPECT_FALSE(DownloadFeedbackService::IsEnabledForDownload(item)); | 
|  | 125   DownloadFeedbackService::MaybeStorePingsForDownload(result, &item, "a", "b"); | 
|  | 126   return DownloadFeedbackService::IsEnabledForDownload(item); | 
|  | 127 } | 
|  | 128 | 
|  | 129 }  // namespace | 
|  | 130 | 
|  | 131 class DownloadFeedbackServiceTest : public testing::Test { | 
|  | 132  public: | 
|  | 133   DownloadFeedbackServiceTest() | 
|  | 134       : file_task_runner_(content::BrowserThread::GetMessageLoopProxyForThread( | 
|  | 135             content::BrowserThread::FILE)), | 
|  | 136         io_task_runner_(content::BrowserThread::GetMessageLoopProxyForThread( | 
|  | 137             content::BrowserThread::IO)), | 
|  | 138         request_context_getter_( | 
|  | 139             new net::TestURLRequestContextGetter(io_task_runner_)) { | 
|  | 140   } | 
|  | 141 | 
|  | 142   virtual void SetUp() OVERRIDE { | 
|  | 143     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 
|  | 144     CommandLine::ForCurrentProcess()->AppendSwitch( | 
|  | 145         switches::kSbEnableDownloadFeedback); | 
|  | 146     DownloadFeedback::RegisterFactory(&download_feedback_factory_); | 
|  | 147   } | 
|  | 148 | 
|  | 149   virtual void TearDown() OVERRIDE { | 
|  | 150     DownloadFeedback::RegisterFactory(NULL); | 
|  | 151   } | 
|  | 152 | 
|  | 153   base::FilePath CreateTestFile(int n) const { | 
|  | 154     base::FilePath upload_file_path( | 
|  | 155         temp_dir_.path().AppendASCII("test file " + base::IntToString(n))); | 
|  | 156     const std::string upload_file_data = "data"; | 
|  | 157     int wrote = file_util::WriteFile( | 
|  | 158         upload_file_path, upload_file_data.data(), upload_file_data.size()); | 
|  | 159     EXPECT_EQ(static_cast<int>(upload_file_data.size()), wrote); | 
|  | 160     return upload_file_path; | 
|  | 161   } | 
|  | 162 | 
|  | 163   FakeDownloadFeedback* feedback(size_t n) const { | 
|  | 164     return download_feedback_factory_.feedback(n); | 
|  | 165   } | 
|  | 166 | 
|  | 167   size_t num_feedbacks() const { | 
|  | 168     return download_feedback_factory_.num_feedbacks(); | 
|  | 169   } | 
|  | 170  protected: | 
|  | 171   base::ScopedTempDir temp_dir_; | 
|  | 172   content::TestBrowserThreadBundle thread_bundle_; | 
|  | 173   scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; | 
|  | 174   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | 
|  | 175   scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; | 
|  | 176   FakeDownloadFeedbackFactory download_feedback_factory_; | 
|  | 177 | 
|  | 178 }; | 
|  | 179 | 
|  | 180 TEST_F(DownloadFeedbackServiceTest, MaybeStorePingsForDownload) { | 
|  | 181   const int64 ok_size = DownloadFeedback::kMaxUploadSize; | 
|  | 182   const int64 bad_size = DownloadFeedback::kMaxUploadSize + 1; | 
|  | 183 | 
|  | 184   EXPECT_FALSE(WillStorePings(DownloadProtectionService::SAFE, ok_size)); | 
|  | 185   EXPECT_FALSE(WillStorePings(DownloadProtectionService::DANGEROUS, ok_size)); | 
|  | 186   EXPECT_TRUE(WillStorePings(DownloadProtectionService::UNCOMMON, ok_size)); | 
|  | 187   EXPECT_TRUE( | 
|  | 188       WillStorePings(DownloadProtectionService::DANGEROUS_HOST, ok_size)); | 
|  | 189 | 
|  | 190   EXPECT_FALSE(WillStorePings(DownloadProtectionService::SAFE, bad_size)); | 
|  | 191   EXPECT_FALSE(WillStorePings(DownloadProtectionService::DANGEROUS, bad_size)); | 
|  | 192   EXPECT_FALSE(WillStorePings(DownloadProtectionService::UNCOMMON, bad_size)); | 
|  | 193   EXPECT_FALSE( | 
|  | 194       WillStorePings(DownloadProtectionService::DANGEROUS_HOST, bad_size)); | 
|  | 195 } | 
|  | 196 | 
|  | 197 TEST_F(DownloadFeedbackServiceTest, SingleFeedbackComplete) { | 
|  | 198   const base::FilePath file_path(CreateTestFile(0)); | 
|  | 199   const std::string ping_request = "ping"; | 
|  | 200   const std::string ping_response = "resp"; | 
|  | 201 | 
|  | 202   content::DownloadItem::AcquireFileCallback download_discarded_callback; | 
|  | 203 | 
|  | 204   content::MockDownloadItem item; | 
|  | 205   EXPECT_CALL(item, GetDangerType()) | 
|  | 206       .WillRepeatedly(Return(content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT)); | 
|  | 207   EXPECT_CALL(item, GetReceivedBytes()).WillRepeatedly(Return(1000)); | 
|  | 208   EXPECT_CALL(item, StealDangerousDownload(_)) | 
|  | 209       .WillOnce(SaveArg<0>(&download_discarded_callback)); | 
|  | 210 | 
|  | 211   DownloadFeedbackService service(request_context_getter_, file_task_runner_); | 
|  | 212   service.MaybeStorePingsForDownload( | 
|  | 213       DownloadProtectionService::UNCOMMON, &item, ping_request, ping_response); | 
|  | 214   ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item)); | 
|  | 215   service.BeginFeedbackForDownload(&item); | 
|  | 216   ASSERT_FALSE(download_discarded_callback.is_null()); | 
|  | 217   EXPECT_EQ(0U, num_feedbacks()); | 
|  | 218 | 
|  | 219   download_discarded_callback.Run(file_path); | 
|  | 220   ASSERT_EQ(1U, num_feedbacks()); | 
|  | 221   ASSERT_TRUE(feedback(0)); | 
|  | 222   EXPECT_TRUE(feedback(0)->start_called()); | 
|  | 223   EXPECT_EQ(ping_request, feedback(0)->GetPingRequestForTesting()); | 
|  | 224   EXPECT_EQ(ping_response, feedback(0)->GetPingResponseForTesting()); | 
|  | 225 | 
|  | 226   feedback(0)->finish_callback().Run(); | 
|  | 227   EXPECT_FALSE(feedback(0)); | 
|  | 228 | 
|  | 229   // File should still exist since our FakeDownloadFeedback does not delete it. | 
|  | 230   base::RunLoop().RunUntilIdle(); | 
|  | 231   EXPECT_TRUE(file_util::PathExists(file_path)); | 
|  | 232 } | 
|  | 233 | 
|  | 234 TEST_F(DownloadFeedbackServiceTest, MultiplePendingFeedbackComplete) { | 
|  | 235   const std::string ping_request = "ping"; | 
|  | 236   const std::string ping_response = "resp"; | 
|  | 237   const size_t num_downloads = 3; | 
|  | 238 | 
|  | 239   content::DownloadItem::AcquireFileCallback | 
|  | 240       download_discarded_callback[num_downloads]; | 
|  | 241 | 
|  | 242   base::FilePath file_path[num_downloads]; | 
|  | 243   content::MockDownloadItem item[num_downloads]; | 
|  | 244   for (size_t i = 0; i < num_downloads; ++i) { | 
|  | 245     file_path[i] = CreateTestFile(i); | 
|  | 246     EXPECT_CALL(item[i], GetDangerType()) | 
|  | 247         .WillRepeatedly(Return(content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT)); | 
|  | 248     EXPECT_CALL(item[i], GetReceivedBytes()).WillRepeatedly(Return(1000)); | 
|  | 249     EXPECT_CALL(item[i], StealDangerousDownload(_)) | 
|  | 250         .WillOnce(SaveArg<0>(&download_discarded_callback[i])); | 
|  | 251     DownloadFeedbackService::MaybeStorePingsForDownload( | 
|  | 252         DownloadProtectionService::UNCOMMON, &item[i], ping_request, | 
|  | 253         ping_response); | 
|  | 254     ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item[i])); | 
|  | 255   } | 
|  | 256 | 
|  | 257   { | 
|  | 258     DownloadFeedbackService service(request_context_getter_, file_task_runner_); | 
|  | 259     for (size_t i = 0; i < num_downloads; ++i) { | 
|  | 260       SCOPED_TRACE(i); | 
|  | 261       service.BeginFeedbackForDownload(&item[i]); | 
|  | 262       ASSERT_FALSE(download_discarded_callback[i].is_null()); | 
|  | 263     } | 
|  | 264     EXPECT_EQ(0U, num_feedbacks()); | 
|  | 265 | 
|  | 266     for (size_t i = 0; i < num_downloads; ++i) { | 
|  | 267       download_discarded_callback[i].Run(file_path[i]); | 
|  | 268     } | 
|  | 269 | 
|  | 270     ASSERT_EQ(3U, num_feedbacks()); | 
|  | 271     EXPECT_TRUE(feedback(0)->start_called()); | 
|  | 272     EXPECT_FALSE(feedback(1)->start_called()); | 
|  | 273     EXPECT_FALSE(feedback(2)->start_called()); | 
|  | 274 | 
|  | 275     feedback(0)->finish_callback().Run(); | 
|  | 276 | 
|  | 277     EXPECT_FALSE(feedback(0)); | 
|  | 278     EXPECT_TRUE(feedback(1)->start_called()); | 
|  | 279     EXPECT_FALSE(feedback(2)->start_called()); | 
|  | 280 | 
|  | 281     feedback(1)->finish_callback().Run(); | 
|  | 282 | 
|  | 283     EXPECT_FALSE(feedback(0)); | 
|  | 284     EXPECT_FALSE(feedback(1)); | 
|  | 285     EXPECT_TRUE(feedback(2)->start_called()); | 
|  | 286 | 
|  | 287     feedback(2)->finish_callback().Run(); | 
|  | 288 | 
|  | 289     EXPECT_FALSE(feedback(0)); | 
|  | 290     EXPECT_FALSE(feedback(1)); | 
|  | 291     EXPECT_FALSE(feedback(2)); | 
|  | 292   } | 
|  | 293 | 
|  | 294   base::RunLoop().RunUntilIdle(); | 
|  | 295   // These files should still exist since the FakeDownloadFeedback does not | 
|  | 296   // delete them. | 
|  | 297   EXPECT_TRUE(file_util::PathExists(file_path[0])); | 
|  | 298   EXPECT_TRUE(file_util::PathExists(file_path[1])); | 
|  | 299   EXPECT_TRUE(file_util::PathExists(file_path[2])); | 
|  | 300 } | 
|  | 301 | 
|  | 302 TEST_F(DownloadFeedbackServiceTest, MultiFeedbackWithIncomplete) { | 
|  | 303   const std::string ping_request = "ping"; | 
|  | 304   const std::string ping_response = "resp"; | 
|  | 305   const size_t num_downloads = 3; | 
|  | 306 | 
|  | 307   content::DownloadItem::AcquireFileCallback | 
|  | 308       download_discarded_callback[num_downloads]; | 
|  | 309 | 
|  | 310   base::FilePath file_path[num_downloads]; | 
|  | 311   content::MockDownloadItem item[num_downloads]; | 
|  | 312   for (size_t i = 0; i < num_downloads; ++i) { | 
|  | 313     file_path[i] = CreateTestFile(i); | 
|  | 314     EXPECT_CALL(item[i], GetDangerType()) | 
|  | 315         .WillRepeatedly(Return(content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT)); | 
|  | 316     EXPECT_CALL(item[i], GetReceivedBytes()).WillRepeatedly(Return(1000)); | 
|  | 317     EXPECT_CALL(item[i], StealDangerousDownload(_)) | 
|  | 318         .WillOnce(SaveArg<0>(&download_discarded_callback[i])); | 
|  | 319     DownloadFeedbackService::MaybeStorePingsForDownload( | 
|  | 320         DownloadProtectionService::UNCOMMON, &item[i], ping_request, | 
|  | 321         ping_response); | 
|  | 322     ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item[i])); | 
|  | 323   } | 
|  | 324 | 
|  | 325   { | 
|  | 326     DownloadFeedbackService service(request_context_getter_, file_task_runner_); | 
|  | 327     for (size_t i = 0; i < num_downloads; ++i) { | 
|  | 328       SCOPED_TRACE(i); | 
|  | 329       service.BeginFeedbackForDownload(&item[i]); | 
|  | 330       ASSERT_FALSE(download_discarded_callback[i].is_null()); | 
|  | 331     } | 
|  | 332     EXPECT_EQ(0U, num_feedbacks()); | 
|  | 333 | 
|  | 334     download_discarded_callback[0].Run(file_path[0]); | 
|  | 335     ASSERT_EQ(1U, num_feedbacks()); | 
|  | 336     ASSERT_TRUE(feedback(0)); | 
|  | 337     EXPECT_TRUE(feedback(0)->start_called()); | 
|  | 338 | 
|  | 339     download_discarded_callback[1].Run(file_path[1]); | 
|  | 340     ASSERT_EQ(2U, num_feedbacks()); | 
|  | 341     ASSERT_TRUE(feedback(1)); | 
|  | 342     EXPECT_FALSE(feedback(1)->start_called()); | 
|  | 343 | 
|  | 344     feedback(0)->finish_callback().Run(); | 
|  | 345     EXPECT_FALSE(feedback(0)); | 
|  | 346     EXPECT_TRUE(feedback(1)->start_called()); | 
|  | 347   } | 
|  | 348 | 
|  | 349   EXPECT_EQ(2U, num_feedbacks()); | 
|  | 350   for (size_t i = 0; i < num_feedbacks(); ++i) { | 
|  | 351     SCOPED_TRACE(i); | 
|  | 352     EXPECT_FALSE(feedback(i)); | 
|  | 353   } | 
|  | 354 | 
|  | 355   // Running a download acquired callback after the DownloadFeedbackService is | 
|  | 356   // destroyed should delete the file. | 
|  | 357   download_discarded_callback[2].Run(file_path[2]); | 
|  | 358   EXPECT_EQ(2U, num_feedbacks()); | 
|  | 359 | 
|  | 360   // File should still exist since the FileUtilProxy task hasn't run yet. | 
|  | 361   EXPECT_TRUE(file_util::PathExists(file_path[2])); | 
|  | 362 | 
|  | 363   base::RunLoop().RunUntilIdle(); | 
|  | 364   // File should be deleted since the AcquireFileCallback ran after the service | 
|  | 365   // was deleted. | 
|  | 366   EXPECT_FALSE(file_util::PathExists(file_path[2])); | 
|  | 367 | 
|  | 368   // These files should still exist since the FakeDownloadFeedback does not | 
|  | 369   // delete them. | 
|  | 370   EXPECT_TRUE(file_util::PathExists(file_path[0])); | 
|  | 371   EXPECT_TRUE(file_util::PathExists(file_path[1])); | 
|  | 372 } | 
|  | 373 | 
|  | 374 }  // namespace safe_browsing | 
| OLD | NEW | 
|---|