Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / chromeos / drive / download_handler.cc
blob108aa80e502ea737f6ab49576c7d1ac5e908fa36
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.
5 #include "chrome/browser/chromeos/drive/download_handler.h"
7 #include "base/bind.h"
8 #include "base/files/file_util.h"
9 #include "base/supports_user_data.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "chrome/browser/chromeos/drive/drive.pb.h"
12 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
13 #include "chrome/browser/chromeos/drive/file_system_interface.h"
14 #include "chrome/browser/chromeos/drive/file_system_util.h"
15 #include "chrome/browser/chromeos/drive/write_on_cache_file.h"
16 #include "chrome/browser/download/download_history.h"
17 #include "chrome/browser/download/download_service.h"
18 #include "chrome/browser/download/download_service_factory.h"
19 #include "content/public/browser/browser_thread.h"
21 using content::BrowserThread;
22 using content::DownloadManager;
23 using content::DownloadItem;
25 namespace drive {
26 namespace {
28 // Key for base::SupportsUserData::Data.
29 const char kDrivePathKey[] = "DrivePath";
31 // User Data stored in DownloadItem for drive path.
32 class DriveUserData : public base::SupportsUserData::Data {
33 public:
34 explicit DriveUserData(const base::FilePath& path) : file_path_(path),
35 is_complete_(false) {}
36 ~DriveUserData() override {}
38 const base::FilePath& file_path() const { return file_path_; }
39 const base::FilePath& cache_file_path() const { return cache_file_path_; }
40 void set_cache_file_path(const base::FilePath& path) {
41 cache_file_path_ = path;
43 bool is_complete() const { return is_complete_; }
44 void set_complete() { is_complete_ = true; }
46 private:
47 const base::FilePath file_path_;
48 base::FilePath cache_file_path_;
49 bool is_complete_;
52 // Extracts DriveUserData* from |download|.
53 const DriveUserData* GetDriveUserData(const DownloadItem* download) {
54 return static_cast<const DriveUserData*>(
55 download->GetUserData(&kDrivePathKey));
58 DriveUserData* GetDriveUserData(DownloadItem* download) {
59 return static_cast<DriveUserData*>(download->GetUserData(&kDrivePathKey));
62 // Creates a temporary file |drive_tmp_download_path| in
63 // |drive_tmp_download_dir|. Must be called on a thread that allows file
64 // operations.
65 base::FilePath GetDriveTempDownloadPath(
66 const base::FilePath& drive_tmp_download_dir) {
67 bool created = base::CreateDirectory(drive_tmp_download_dir);
68 DCHECK(created) << "Can not create temp download directory at "
69 << drive_tmp_download_dir.value();
70 base::FilePath drive_tmp_download_path;
71 created = base::CreateTemporaryFileInDir(drive_tmp_download_dir,
72 &drive_tmp_download_path);
73 DCHECK(created) << "Temporary download file creation failed";
74 return drive_tmp_download_path;
77 // Moves downloaded file to Drive.
78 void MoveDownloadedFile(const base::FilePath& downloaded_file,
79 base::FilePath* cache_file_path,
80 FileError error,
81 const base::FilePath& dest_path) {
82 if (error != FILE_ERROR_OK ||
83 !base::Move(downloaded_file, dest_path))
84 return;
85 *cache_file_path = dest_path;
88 // Used to implement CheckForFileExistence().
89 void ContinueCheckingForFileExistence(
90 const content::CheckForFileExistenceCallback& callback,
91 FileError error,
92 scoped_ptr<ResourceEntry> entry) {
93 callback.Run(error == FILE_ERROR_OK);
96 // Returns true if |download| is a Drive download created from data persisted
97 // on the download history DB.
98 bool IsPersistedDriveDownload(const base::FilePath& drive_tmp_download_path,
99 DownloadItem* download) {
100 if (!drive_tmp_download_path.IsParent(download->GetTargetFilePath()))
101 return false;
103 DownloadService* download_service =
104 DownloadServiceFactory::GetForBrowserContext(
105 download->GetBrowserContext());
106 DownloadHistory* download_history = download_service->GetDownloadHistory();
108 return download_history && download_history->WasRestoredFromHistory(download);
111 } // namespace
113 DownloadHandler::DownloadHandler(FileSystemInterface* file_system)
114 : file_system_(file_system),
115 weak_ptr_factory_(this) {
118 DownloadHandler::~DownloadHandler() {
121 // static
122 DownloadHandler* DownloadHandler::GetForProfile(Profile* profile) {
123 DriveIntegrationService* service =
124 DriveIntegrationServiceFactory::FindForProfile(profile);
125 if (!service || !service->IsMounted())
126 return NULL;
127 return service->download_handler();
130 void DownloadHandler::Initialize(
131 DownloadManager* download_manager,
132 const base::FilePath& drive_tmp_download_path) {
133 DCHECK(!drive_tmp_download_path.empty());
135 drive_tmp_download_path_ = drive_tmp_download_path;
137 if (download_manager) {
138 notifier_.reset(new AllDownloadItemNotifier(download_manager, this));
139 // Remove any persisted Drive DownloadItem. crbug.com/171384
140 content::DownloadManager::DownloadVector downloads;
141 download_manager->GetAllDownloads(&downloads);
142 for (size_t i = 0; i < downloads.size(); ++i) {
143 if (IsPersistedDriveDownload(drive_tmp_download_path_, downloads[i]))
144 downloads[i]->Remove();
149 void DownloadHandler::ObserveIncognitoDownloadManager(
150 DownloadManager* download_manager) {
151 notifier_incognito_.reset(new AllDownloadItemNotifier(download_manager,
152 this));
155 void DownloadHandler::SubstituteDriveDownloadPath(
156 const base::FilePath& drive_path,
157 content::DownloadItem* download,
158 const SubstituteDriveDownloadPathCallback& callback) {
159 DVLOG(1) << "SubstituteDriveDownloadPath " << drive_path.value();
161 SetDownloadParams(drive_path, download);
163 if (util::IsUnderDriveMountPoint(drive_path)) {
164 // Prepare the destination directory.
165 const bool is_exclusive = false, is_recursive = true;
166 file_system_->CreateDirectory(
167 util::ExtractDrivePath(drive_path.DirName()),
168 is_exclusive, is_recursive,
169 base::Bind(&DownloadHandler::OnCreateDirectory,
170 weak_ptr_factory_.GetWeakPtr(),
171 callback));
172 } else {
173 callback.Run(drive_path);
177 void DownloadHandler::SetDownloadParams(const base::FilePath& drive_path,
178 DownloadItem* download) {
179 if (!download || (download->GetState() != DownloadItem::IN_PROGRESS))
180 return;
182 if (util::IsUnderDriveMountPoint(drive_path)) {
183 download->SetUserData(&kDrivePathKey, new DriveUserData(drive_path));
184 download->SetDisplayName(drive_path.BaseName());
185 } else if (IsDriveDownload(download)) {
186 // This may have been previously set if the default download folder is
187 // /drive, and the user has now changed the download target to a local
188 // folder.
189 download->SetUserData(&kDrivePathKey, NULL);
190 download->SetDisplayName(base::FilePath());
194 base::FilePath DownloadHandler::GetTargetPath(
195 const DownloadItem* download) {
196 const DriveUserData* data = GetDriveUserData(download);
197 // If data is NULL, we've somehow lost the drive path selected by the file
198 // picker.
199 DCHECK(data);
200 return data ? data->file_path() : base::FilePath();
203 base::FilePath DownloadHandler::GetCacheFilePath(const DownloadItem* download) {
204 const DriveUserData* data = GetDriveUserData(download);
205 return data ? data->cache_file_path() : base::FilePath();
208 bool DownloadHandler::IsDriveDownload(const DownloadItem* download) {
209 // We use the existence of the DriveUserData object in download as a
210 // signal that this is a download to Drive.
211 return GetDriveUserData(download) != NULL;
214 void DownloadHandler::CheckForFileExistence(
215 const DownloadItem* download,
216 const content::CheckForFileExistenceCallback& callback) {
217 file_system_->GetResourceEntry(
218 util::ExtractDrivePath(GetTargetPath(download)),
219 base::Bind(&ContinueCheckingForFileExistence,
220 callback));
223 void DownloadHandler::OnDownloadCreated(DownloadManager* manager,
224 DownloadItem* download) {
225 // Remove any persisted Drive DownloadItem. crbug.com/171384
226 if (IsPersistedDriveDownload(drive_tmp_download_path_, download)) {
227 // Remove download later, since doing it here results in a crash.
228 BrowserThread::PostTask(BrowserThread::UI,
229 FROM_HERE,
230 base::Bind(&DownloadHandler::RemoveDownload,
231 weak_ptr_factory_.GetWeakPtr(),
232 static_cast<void*>(manager),
233 download->GetId()));
237 void DownloadHandler::RemoveDownload(void* manager_id, int id) {
238 DownloadManager* manager = GetDownloadManager(manager_id);
239 if (!manager)
240 return;
241 DownloadItem* download = manager->GetDownload(id);
242 if (!download)
243 return;
244 download->Remove();
247 void DownloadHandler::OnDownloadUpdated(
248 DownloadManager* manager, DownloadItem* download) {
249 DCHECK_CURRENTLY_ON(BrowserThread::UI);
251 // Only accept downloads that have the Drive meta data associated with them.
252 DriveUserData* data = GetDriveUserData(download);
253 if (!drive_tmp_download_path_.IsParent(download->GetTargetFilePath()) ||
254 !data ||
255 data->is_complete())
256 return;
258 switch (download->GetState()) {
259 case DownloadItem::IN_PROGRESS:
260 break;
262 case DownloadItem::COMPLETE:
263 UploadDownloadItem(manager, download);
264 data->set_complete();
265 break;
267 case DownloadItem::CANCELLED:
268 download->SetUserData(&kDrivePathKey, NULL);
269 break;
271 case DownloadItem::INTERRUPTED:
272 // Interrupted downloads can be resumed. Keep the Drive user data around
273 // so that it can be used when the download resumes. The download is truly
274 // done when it's complete, is cancelled or is removed.
275 break;
277 default:
278 NOTREACHED();
282 void DownloadHandler::OnCreateDirectory(
283 const SubstituteDriveDownloadPathCallback& callback,
284 FileError error) {
285 DVLOG(1) << "OnCreateDirectory " << FileErrorToString(error);
286 if (error == FILE_ERROR_OK) {
287 base::PostTaskAndReplyWithResult(
288 BrowserThread::GetBlockingPool(),
289 FROM_HERE,
290 base::Bind(&GetDriveTempDownloadPath, drive_tmp_download_path_),
291 callback);
292 } else {
293 LOG(WARNING) << "Failed to create directory, error = "
294 << FileErrorToString(error);
295 callback.Run(base::FilePath());
299 void DownloadHandler::UploadDownloadItem(DownloadManager* manager,
300 DownloadItem* download) {
301 DCHECK_EQ(DownloadItem::COMPLETE, download->GetState());
302 base::FilePath* cache_file_path = new base::FilePath;
303 WriteOnCacheFileAndReply(
304 file_system_,
305 util::ExtractDrivePath(GetTargetPath(download)),
306 download->GetMimeType(),
307 base::Bind(&MoveDownloadedFile, download->GetTargetFilePath(),
308 cache_file_path),
309 base::Bind(&DownloadHandler::SetCacheFilePath,
310 weak_ptr_factory_.GetWeakPtr(),
311 static_cast<void*>(manager),
312 download->GetId(),
313 base::Owned(cache_file_path)));
316 void DownloadHandler::SetCacheFilePath(void* manager_id,
317 int id,
318 const base::FilePath* cache_file_path,
319 FileError error) {
320 if (error != FILE_ERROR_OK)
321 return;
322 DownloadManager* manager = GetDownloadManager(manager_id);
323 if (!manager)
324 return;
325 DownloadItem* download = manager->GetDownload(id);
326 if (!download)
327 return;
328 DriveUserData* data = GetDriveUserData(download);
329 if (!data)
330 return;
331 data->set_cache_file_path(*cache_file_path);
334 DownloadManager* DownloadHandler::GetDownloadManager(void* manager_id) {
335 if (manager_id == notifier_->GetManager())
336 return notifier_->GetManager();
337 if (notifier_incognito_ && manager_id == notifier_incognito_->GetManager())
338 return notifier_incognito_->GetManager();
339 return NULL;
342 } // namespace drive