Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: chrome/browser/download/chrome_download_manager_delegate.cc

Issue 7640021: Move some Chrome-specific code paths out of DownloadManager and into the delegate. Getting rid of... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/download/chrome_download_manager_delegate.h" 5 #include "chrome/browser/download/chrome_download_manager_delegate.h"
6 6
7 #include "base/callback.h"
8 #include "base/file_util.h"
9 #include "base/path_service.h"
10 #include "base/rand_util.h"
11 #include "base/stringprintf.h"
12 #include "chrome/browser/download/download_extensions.h"
7 #include "chrome/browser/download/download_file_picker.h" 13 #include "chrome/browser/download/download_file_picker.h"
14 #include "chrome/browser/download/download_history.h"
15 #include "chrome/browser/download/download_item.h"
16 #include "chrome/browser/download/download_manager.h"
17 #include "chrome/browser/download/download_prefs.h"
18 #include "chrome/browser/download/download_safe_browsing_client.h"
19 #include "chrome/browser/download/download_util.h"
8 #include "chrome/browser/download/save_package_file_picker.h" 20 #include "chrome/browser/download/save_package_file_picker.h"
21 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/prefs/pref_member.h" 22 #include "chrome/browser/prefs/pref_member.h"
10 #include "chrome/browser/prefs/pref_service.h" 23 #include "chrome/browser/prefs/pref_service.h"
11 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h" 25 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_list.h" 26 #include "chrome/browser/ui/browser_list.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/extensions/user_script.h"
14 #include "chrome/common/pref_names.h" 29 #include "chrome/common/pref_names.h"
15 #include "content/browser/tab_contents/tab_contents.h" 30 #include "content/browser/tab_contents/tab_contents.h"
31 #include "grit/generated_resources.h"
32 #include "ui/base/l10n/l10n_util.h"
16 33
17 ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate() 34 ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate() {
18 : download_manager_(NULL) {
19 } 35 }
20 36
37 ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
38 }
39
40 bool ChromeDownloadManagerDelegate::ShouldStartDownload(int32 download_id) {
41 // We create a download item and store it in our download map, and inform the
42 // history system of a new download. Since this method can be called while the
43 // history service thread is still reading the persistent state, we do not
44 // insert the new DownloadItem into 'history_downloads_' or inform our
45 // observers at this point. OnCreateDownloadEntryComplete() handles that
46 // finalization of the the download creation as a callback from the history
47 // thread.
48 DownloadItem* download =
49 download_manager_->GetActiveDownloadItem(download_id);
50 if (!download)
51 return false;
52
53 #if defined(ENABLE_SAFE_BROWSING)
54 // Create a client to verify download URL with safebrowsing.
55 // It deletes itself after the callback.
56 scoped_refptr<DownloadSBClient> sb_client = new DownloadSBClient(
57 download_id, download->url_chain(), download->referrer_url(),
58 download_manager_->profile()->GetPrefs()->GetBoolean(
59 prefs::kSafeBrowsingEnabled));
60 sb_client->CheckDownloadUrl(
61 NewCallback(this, &ChromeDownloadManagerDelegate::CheckDownloadUrlDone));
62 #else
63 CheckDownloadUrlDone(download_id, false);
64 #endif
65 return false;
66 }
67
68 void ChromeDownloadManagerDelegate::ChooseDownloadPath(
69 TabContents* tab_contents,
70 const FilePath& suggested_path,
71 void* data) {
72 // Deletes itself.
73 new DownloadFilePicker(
74 download_manager_, tab_contents, suggested_path, data);
75 }
76
77 TabContents* ChromeDownloadManagerDelegate::
78 GetAlternativeTabContentsToNotifyForDownload() {
79 // Start the download in the last active browser. This is not ideal but better
80 // than fully hiding the download from the user.
81 Browser* last_active = BrowserList::GetLastActiveWithProfile(
82 download_manager_->profile());
83 return last_active ? last_active->GetSelectedTabContents() : NULL;
84 }
85
86
87 bool ChromeDownloadManagerDelegate::ShouldOpenFileBasedOnExtension(
88 const FilePath& path) {
89 FilePath::StringType extension = path.Extension();
90 if (extension.empty())
91 return false;
92 if (Extension::IsExtension(path))
93 return false;
94 DCHECK(extension[0] == FilePath::kExtensionSeparator);
95 extension.erase(0, 1);
96 return download_manager_->download_prefs()->
97 IsAutoOpenEnabledForExtension(extension);
98 }
99
100
21 void ChromeDownloadManagerDelegate::GetSaveDir(TabContents* tab_contents, 101 void ChromeDownloadManagerDelegate::GetSaveDir(TabContents* tab_contents,
22 FilePath* website_save_dir, 102 FilePath* website_save_dir,
23 FilePath* download_save_dir) { 103 FilePath* download_save_dir) {
24 Profile* profile = 104 Profile* profile =
25 Profile::FromBrowserContext(tab_contents->browser_context()); 105 Profile::FromBrowserContext(tab_contents->browser_context());
26 PrefService* prefs = profile->GetPrefs(); 106 PrefService* prefs = profile->GetPrefs();
27 107
28 // Check whether the preference has the preferred directory for saving file. 108 // Check whether the preference has the preferred directory for saving file.
29 // If not, initialize it with default directory. 109 // If not, initialize it with default directory.
30 if (!prefs->FindPreference(prefs::kSaveFileDefaultDirectory)) { 110 if (!prefs->FindPreference(prefs::kSaveFileDefaultDirectory)) {
(...skipping 14 matching lines...) Expand all
45 125
46 void ChromeDownloadManagerDelegate::ChooseSavePath( 126 void ChromeDownloadManagerDelegate::ChooseSavePath(
47 const base::WeakPtr<SavePackage>& save_package, 127 const base::WeakPtr<SavePackage>& save_package,
48 const FilePath& suggested_path, 128 const FilePath& suggested_path,
49 bool can_save_as_complete) { 129 bool can_save_as_complete) {
50 // Deletes itself. 130 // Deletes itself.
51 new SavePackageFilePicker( 131 new SavePackageFilePicker(
52 save_package, suggested_path, can_save_as_complete); 132 save_package, suggested_path, can_save_as_complete);
53 } 133 }
54 134
55 void ChromeDownloadManagerDelegate::ChooseDownloadPath( 135 void ChromeDownloadManagerDelegate::CheckDownloadUrlDone(
56 DownloadManager* download_manager, 136 int32 download_id, bool is_dangerous_url) {
57 TabContents* tab_contents, 137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
58 const FilePath& suggested_path, 138
59 void* data) { 139 DownloadItem* download =
60 // Deletes itself. 140 download_manager_->GetActiveDownloadItem(download_id);
61 new DownloadFilePicker( 141 if (!download)
62 download_manager, tab_contents, suggested_path, data); 142 return;
63 } 143
64 144 if (is_dangerous_url)
65 TabContents* 145 download->MarkUrlDangerous();
66 ChromeDownloadManagerDelegate::GetAlternativeTabContentsToNotifyForDownload( 146
67 DownloadManager* download_manager) { 147 download_manager_->download_history()->CheckVisitedReferrerBefore(
68 // Start the download in the last active browser. This is not ideal but better 148 download_id,
69 // than fully hiding the download from the user. 149 download->referrer_url(),
70 Browser* last_active = BrowserList::GetLastActiveWithProfile( 150 NewCallback(this,
71 download_manager->profile()); 151 &ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone));
72 return last_active ? last_active->GetSelectedTabContents() : NULL; 152 }
73 } 153
154 void ChromeDownloadManagerDelegate::CheckVisitedReferrerBeforeDone(
155 int32 download_id,
156 bool visited_referrer_before) {
157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
158
159 DownloadItem* download =
160 download_manager_->GetActiveDownloadItem(download_id);
161 if (!download)
162 return;
163
164 // Check whether this download is for an extension install or not.
165 // Allow extensions to be explicitly saved.
166 DownloadStateInfo state = download->state_info();
167 if (!state.prompt_user_for_save_location) {
168 if (UserScript::IsURLUserScript(download->GetURL(),
169 download->mime_type()) ||
170 (download->mime_type() == Extension::kMimeType)) {
171 state.is_extension_install = true;
172 }
173 }
174
175 if (state.force_file_name.empty()) {
176 FilePath generated_name;
177 download_util::GenerateFileNameFromRequest(*download,
178 &generated_name);
179
180 // Freeze the user's preference for showing a Save As dialog. We're going
181 // to bounce around a bunch of threads and we don't want to worry about race
182 // conditions where the user changes this pref out from under us.
183 if (download_manager_->download_prefs()->PromptForDownload()) {
184 // But ignore the user's preference for the following scenarios:
185 // 1) Extension installation. Note that we only care here about the case
186 // where an extension is installed, not when one is downloaded with
187 // "save as...".
188 // 2) Filetypes marked "always open." If the user just wants this file
189 // opened, don't bother asking where to keep it.
190 if (!state.is_extension_install &&
191 !ShouldOpenFileBasedOnExtension(generated_name))
192 state.prompt_user_for_save_location = true;
193 }
194 if (download_manager_->download_prefs()->IsDownloadPathManaged()) {
195 state.prompt_user_for_save_location = false;
196 }
197
198 // Determine the proper path for a download, by either one of the following:
199 // 1) using the default download directory.
200 // 2) prompting the user.
201 if (state.prompt_user_for_save_location &&
202 !download_manager_->last_download_path().empty()) {
203 state.suggested_path = download_manager_->last_download_path();
204 } else {
205 state.suggested_path =
206 download_manager_->download_prefs()->download_path();
207 }
208 state.suggested_path = state.suggested_path.Append(generated_name);
209 } else {
210 state.suggested_path = state.force_file_name;
211 }
212
213 if (!state.prompt_user_for_save_location && state.force_file_name.empty()) {
214 state.is_dangerous_file =
215 IsDangerousFile(*download, state, visited_referrer_before);
216 }
217
218 // We need to move over to the download thread because we don't want to stat
219 // the suggested path on the UI thread.
220 // We can only access preferences on the UI thread, so check the download path
221 // now and pass the value to the FILE thread.
222 BrowserThread::PostTask(
223 BrowserThread::FILE, FROM_HERE,
224 NewRunnableMethod(
225 this,
226 &ChromeDownloadManagerDelegate::CheckIfSuggestedPathExists,
227 download->id(),
228 state,
229 download_manager_->download_prefs()->download_path()));
230 }
231
232 void ChromeDownloadManagerDelegate::CheckIfSuggestedPathExists(
233 int32 download_id,
234 DownloadStateInfo state,
235 const FilePath& default_path) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
237
238 // Make sure the default download directory exists.
239 // TODO(phajdan.jr): only create the directory when we're sure the user
240 // is going to save there and not to another directory of his choice.
241 file_util::CreateDirectory(default_path);
242
243 // Check writability of the suggested path. If we can't write to it, default
244 // to the user's "My Documents" directory. We'll prompt them in this case.
245 FilePath dir = state.suggested_path.DirName();
246 FilePath filename = state.suggested_path.BaseName();
247 if (!file_util::PathIsWritable(dir)) {
248 VLOG(1) << "Unable to write to directory \"" << dir.value() << "\"";
249 state.prompt_user_for_save_location = true;
250 PathService::Get(chrome::DIR_USER_DOCUMENTS, &state.suggested_path);
251 state.suggested_path = state.suggested_path.Append(filename);
252 }
253
254 // If the download is deemed dangerous, we'll use a temporary name for it.
255 if (state.IsDangerous()) {
256 state.target_name = FilePath(state.suggested_path).BaseName();
257 // Create a temporary file to hold the file until the user approves its
258 // download.
259 FilePath::StringType file_name;
260 FilePath path;
261 #if defined(OS_WIN)
262 string16 unconfirmed_prefix =
263 l10n_util::GetStringUTF16(IDS_DOWNLOAD_UNCONFIRMED_PREFIX);
264 #else
265 std::string unconfirmed_prefix =
266 l10n_util::GetStringUTF8(IDS_DOWNLOAD_UNCONFIRMED_PREFIX);
267 #endif
268
269 while (path.empty()) {
270 base::SStringPrintf(
271 &file_name,
272 unconfirmed_prefix.append(
273 FILE_PATH_LITERAL(" %d.crdownload")).c_str(),
274 base::RandInt(0, 100000));
275 path = dir.Append(file_name);
276 if (file_util::PathExists(path))
277 path = FilePath();
278 }
279 state.suggested_path = path;
280 } else {
281 // Do not add the path uniquifier if we are saving to a specific path as in
282 // the drag-out case.
283 if (state.force_file_name.empty()) {
284 state.path_uniquifier = download_util::GetUniquePathNumberWithCrDownload(
285 state.suggested_path);
286 }
287 // We know the final path, build it if necessary.
288 if (state.path_uniquifier > 0) {
289 download_util::AppendNumberToPath(&(state.suggested_path),
290 state.path_uniquifier);
291 // Setting path_uniquifier to 0 to make sure we don't try to unique it
292 // later on.
293 state.path_uniquifier = 0;
294 } else if (state.path_uniquifier == -1) {
295 // We failed to find a unique path. We have to prompt the user.
296 VLOG(1) << "Unable to find a unique path for suggested path \""
297 << state.suggested_path.value() << "\"";
298 state.prompt_user_for_save_location = true;
299 }
300 }
301
302 // Create an empty file at the suggested path so that we don't allocate the
303 // same "non-existant" path to multiple downloads.
304 // See: http://code.google.com/p/chromium/issues/detail?id=3662
305 if (!state.prompt_user_for_save_location &&
306 state.force_file_name.empty()) {
307 if (state.IsDangerous())
308 file_util::WriteFile(state.suggested_path, "", 0);
309 else
310 file_util::WriteFile(download_util::GetCrDownloadPath(
311 state.suggested_path), "", 0);
312 }
313
314 BrowserThread::PostTask(
315 BrowserThread::UI, FROM_HERE,
316 NewRunnableMethod(
317 this,
318 &ChromeDownloadManagerDelegate::OnPathExistenceAvailable,
319 download_id,
320 state));
321 }
322
323 void ChromeDownloadManagerDelegate::OnPathExistenceAvailable(
324 int32 download_id,
325 const DownloadStateInfo& new_state) {
326 DownloadItem* download =
327 download_manager_->GetActiveDownloadItem(download_id);
328 if (!download)
329 return;
330 download->SetFileCheckResults(new_state);
331 download_manager_->RestartDownload(download_id);
332 }
333
334 // TODO(phajdan.jr): This is apparently not being exercised in tests.
335 bool ChromeDownloadManagerDelegate::IsDangerousFile(
336 const DownloadItem& download,
337 const DownloadStateInfo& state,
338 bool visited_referrer_before) {
339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
340
341 bool auto_open = ShouldOpenFileBasedOnExtension(state.suggested_path);
342 download_util::DownloadDangerLevel danger_level =
343 download_util::GetFileDangerLevel(state.suggested_path.BaseName());
344
345 if (danger_level == download_util::Dangerous)
346 return !(auto_open && state.has_user_gesture);
347
348 if (danger_level == download_util::AllowOnUserGesture &&
349 (!state.has_user_gesture || !visited_referrer_before))
350 return true;
351
352 if (state.is_extension_install) {
353 // Extensions that are not from the gallery are considered dangerous.
354 ExtensionService* service =
355 download_manager_->profile()->GetExtensionService();
356 if (!service || !service->IsDownloadFromGallery(download.GetURL(),
357 download.referrer_url()))
358 return true;
359 }
360 return false;
361 }
OLDNEW
« no previous file with comments | « chrome/browser/download/chrome_download_manager_delegate.h ('k') | chrome/browser/download/download_item.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698