Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / drive / download_handler.cc
blobb5ffb263f5848371f1f84e7e655ef0a153a68b59
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/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 "content/public/browser/browser_thread.h"
18 using content::BrowserThread;
19 using content::DownloadManager;
20 using content::DownloadItem;
22 namespace drive {
23 namespace {
25 // Key for base::SupportsUserData::Data.
26 const char kDrivePathKey[] = "DrivePath";
28 // User Data stored in DownloadItem for drive path.
29 class DriveUserData : public base::SupportsUserData::Data {
30 public:
31 explicit DriveUserData(const base::FilePath& path) : file_path_(path),
32 is_complete_(false) {}
33 virtual ~DriveUserData() {}
35 const base::FilePath& file_path() const { return file_path_; }
36 const base::FilePath& cache_file_path() const { return cache_file_path_; }
37 void set_cache_file_path(const base::FilePath& path) {
38 cache_file_path_ = path;
40 bool is_complete() const { return is_complete_; }
41 void set_complete() { is_complete_ = true; }
43 private:
44 const base::FilePath file_path_;
45 base::FilePath cache_file_path_;
46 bool is_complete_;
49 // Extracts DriveUserData* from |download|.
50 const DriveUserData* GetDriveUserData(const DownloadItem* download) {
51 return static_cast<const DriveUserData*>(
52 download->GetUserData(&kDrivePathKey));
55 DriveUserData* GetDriveUserData(DownloadItem* download) {
56 return static_cast<DriveUserData*>(download->GetUserData(&kDrivePathKey));
59 // Creates a temporary file |drive_tmp_download_path| in
60 // |drive_tmp_download_dir|. Must be called on a thread that allows file
61 // operations.
62 base::FilePath GetDriveTempDownloadPath(
63 const base::FilePath& drive_tmp_download_dir) {
64 bool created = base::CreateDirectory(drive_tmp_download_dir);
65 DCHECK(created) << "Can not create temp download directory at "
66 << drive_tmp_download_dir.value();
67 base::FilePath drive_tmp_download_path;
68 created = base::CreateTemporaryFileInDir(drive_tmp_download_dir,
69 &drive_tmp_download_path);
70 DCHECK(created) << "Temporary download file creation failed";
71 return drive_tmp_download_path;
74 // Moves downloaded file to Drive.
75 void MoveDownloadedFile(const base::FilePath& downloaded_file,
76 base::FilePath* cache_file_path,
77 FileError error,
78 const base::FilePath& dest_path) {
79 if (error != FILE_ERROR_OK ||
80 !base::Move(downloaded_file, dest_path))
81 return;
82 *cache_file_path = dest_path;
85 // Used to implement CheckForFileExistence().
86 void ContinueCheckingForFileExistence(
87 const content::CheckForFileExistenceCallback& callback,
88 FileError error,
89 scoped_ptr<ResourceEntry> entry) {
90 callback.Run(error == FILE_ERROR_OK);
93 // Returns true if |download| is a Drive download created from data persisted
94 // on the download history DB.
95 bool IsPersistedDriveDownload(const base::FilePath& drive_tmp_download_path,
96 DownloadItem* download) {
97 // Persisted downloads are not in IN_PROGRESS state when created, while newly
98 // created downloads are.
99 return drive_tmp_download_path.IsParent(download->GetTargetFilePath()) &&
100 download->GetState() != DownloadItem::IN_PROGRESS;
103 } // namespace
105 DownloadHandler::DownloadHandler(FileSystemInterface* file_system)
106 : file_system_(file_system),
107 weak_ptr_factory_(this) {
110 DownloadHandler::~DownloadHandler() {
113 // static
114 DownloadHandler* DownloadHandler::GetForProfile(Profile* profile) {
115 DriveIntegrationService* service =
116 DriveIntegrationServiceFactory::FindForProfile(profile);
117 if (!service || !service->IsMounted())
118 return NULL;
119 return service->download_handler();
122 void DownloadHandler::Initialize(
123 DownloadManager* download_manager,
124 const base::FilePath& drive_tmp_download_path) {
125 DCHECK(!drive_tmp_download_path.empty());
127 drive_tmp_download_path_ = drive_tmp_download_path;
129 if (download_manager) {
130 notifier_.reset(new AllDownloadItemNotifier(download_manager, this));
131 // Remove any persisted Drive DownloadItem. crbug.com/171384
132 content::DownloadManager::DownloadVector downloads;
133 download_manager->GetAllDownloads(&downloads);
134 for (size_t i = 0; i < downloads.size(); ++i) {
135 if (IsPersistedDriveDownload(drive_tmp_download_path_, downloads[i]))
136 RemoveDownload(downloads[i]->GetId());
141 void DownloadHandler::SubstituteDriveDownloadPath(
142 const base::FilePath& drive_path,
143 content::DownloadItem* download,
144 const SubstituteDriveDownloadPathCallback& callback) {
145 DVLOG(1) << "SubstituteDriveDownloadPath " << drive_path.value();
147 SetDownloadParams(drive_path, download);
149 if (util::IsUnderDriveMountPoint(drive_path)) {
150 // Prepare the destination directory.
151 const bool is_exclusive = false, is_recursive = true;
152 file_system_->CreateDirectory(
153 util::ExtractDrivePath(drive_path.DirName()),
154 is_exclusive, is_recursive,
155 base::Bind(&DownloadHandler::OnCreateDirectory,
156 weak_ptr_factory_.GetWeakPtr(),
157 callback));
158 } else {
159 callback.Run(drive_path);
163 void DownloadHandler::SetDownloadParams(const base::FilePath& drive_path,
164 DownloadItem* download) {
165 if (!download || (download->GetState() != DownloadItem::IN_PROGRESS))
166 return;
168 if (util::IsUnderDriveMountPoint(drive_path)) {
169 download->SetUserData(&kDrivePathKey, new DriveUserData(drive_path));
170 download->SetDisplayName(drive_path.BaseName());
171 } else if (IsDriveDownload(download)) {
172 // This may have been previously set if the default download folder is
173 // /drive, and the user has now changed the download target to a local
174 // folder.
175 download->SetUserData(&kDrivePathKey, NULL);
176 download->SetDisplayName(base::FilePath());
180 base::FilePath DownloadHandler::GetTargetPath(
181 const DownloadItem* download) {
182 const DriveUserData* data = GetDriveUserData(download);
183 // If data is NULL, we've somehow lost the drive path selected by the file
184 // picker.
185 DCHECK(data);
186 return data ? data->file_path() : base::FilePath();
189 base::FilePath DownloadHandler::GetCacheFilePath(const DownloadItem* download) {
190 const DriveUserData* data = GetDriveUserData(download);
191 return data ? data->cache_file_path() : base::FilePath();
194 bool DownloadHandler::IsDriveDownload(const DownloadItem* download) {
195 // We use the existence of the DriveUserData object in download as a
196 // signal that this is a download to Drive.
197 return GetDriveUserData(download) != NULL;
200 void DownloadHandler::CheckForFileExistence(
201 const DownloadItem* download,
202 const content::CheckForFileExistenceCallback& callback) {
203 file_system_->GetResourceEntry(
204 util::ExtractDrivePath(GetTargetPath(download)),
205 base::Bind(&ContinueCheckingForFileExistence,
206 callback));
209 void DownloadHandler::OnDownloadCreated(DownloadManager* manager,
210 DownloadItem* download) {
211 // Remove any persisted Drive DownloadItem. crbug.com/171384
212 if (IsPersistedDriveDownload(drive_tmp_download_path_, download)) {
213 // Remove download later, since doing it here results in a crash.
214 BrowserThread::PostTask(BrowserThread::UI,
215 FROM_HERE,
216 base::Bind(&DownloadHandler::RemoveDownload,
217 weak_ptr_factory_.GetWeakPtr(),
218 download->GetId()));
222 void DownloadHandler::RemoveDownload(int id) {
223 DownloadManager* manager = notifier_->GetManager();
224 if (!manager)
225 return;
226 DownloadItem* download = manager->GetDownload(id);
227 if (!download)
228 return;
229 download->Remove();
232 void DownloadHandler::OnDownloadUpdated(
233 DownloadManager* manager, DownloadItem* download) {
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
236 // Only accept downloads that have the Drive meta data associated with them.
237 DriveUserData* data = GetDriveUserData(download);
238 if (!drive_tmp_download_path_.IsParent(download->GetTargetFilePath()) ||
239 !data ||
240 data->is_complete())
241 return;
243 switch (download->GetState()) {
244 case DownloadItem::IN_PROGRESS:
245 break;
247 case DownloadItem::COMPLETE:
248 UploadDownloadItem(download);
249 data->set_complete();
250 break;
252 case DownloadItem::CANCELLED:
253 download->SetUserData(&kDrivePathKey, NULL);
254 break;
256 case DownloadItem::INTERRUPTED:
257 // Interrupted downloads can be resumed. Keep the Drive user data around
258 // so that it can be used when the download resumes. The download is truly
259 // done when it's complete, is cancelled or is removed.
260 break;
262 default:
263 NOTREACHED();
267 void DownloadHandler::OnCreateDirectory(
268 const SubstituteDriveDownloadPathCallback& callback,
269 FileError error) {
270 DVLOG(1) << "OnCreateDirectory " << FileErrorToString(error);
271 if (error == FILE_ERROR_OK) {
272 base::PostTaskAndReplyWithResult(
273 BrowserThread::GetBlockingPool(),
274 FROM_HERE,
275 base::Bind(&GetDriveTempDownloadPath, drive_tmp_download_path_),
276 callback);
277 } else {
278 LOG(WARNING) << "Failed to create directory, error = "
279 << FileErrorToString(error);
280 callback.Run(base::FilePath());
284 void DownloadHandler::UploadDownloadItem(DownloadItem* download) {
285 DCHECK_EQ(DownloadItem::COMPLETE, download->GetState());
286 base::FilePath* cache_file_path = new base::FilePath;
287 WriteOnCacheFileAndReply(
288 file_system_,
289 util::ExtractDrivePath(GetTargetPath(download)),
290 download->GetMimeType(),
291 base::Bind(&MoveDownloadedFile, download->GetTargetFilePath(),
292 cache_file_path),
293 base::Bind(&DownloadHandler::SetCacheFilePath,
294 weak_ptr_factory_.GetWeakPtr(),
295 download->GetId(),
296 base::Owned(cache_file_path)));
299 void DownloadHandler::SetCacheFilePath(int id,
300 const base::FilePath* cache_file_path,
301 FileError error) {
302 if (error != FILE_ERROR_OK)
303 return;
304 DownloadManager* manager = notifier_->GetManager();
305 if (!manager)
306 return;
307 DownloadItem* download = manager->GetDownload(id);
308 if (!download)
309 return;
310 DriveUserData* data = GetDriveUserData(download);
311 if (!data)
312 return;
313 data->set_cache_file_path(*cache_file_path);
317 } // namespace drive