OLD | NEW |
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 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/download_manager.h" | 5 #include "chrome/browser/download/download_manager.h" |
6 | 6 |
7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
519 // We use this to determine possibly dangerous downloads. | 519 // We use this to determine possibly dangerous downloads. |
520 download_util::InitializeExeTypes(&exe_types_); | 520 download_util::InitializeExeTypes(&exe_types_); |
521 | 521 |
522 // We store any file extension that should be opened automatically at | 522 // We store any file extension that should be opened automatically at |
523 // download completion in this pref. | 523 // download completion in this pref. |
524 std::wstring extensions_to_open = | 524 std::wstring extensions_to_open = |
525 prefs->GetString(prefs::kDownloadExtensionsToOpen); | 525 prefs->GetString(prefs::kDownloadExtensionsToOpen); |
526 std::vector<std::wstring> extensions; | 526 std::vector<std::wstring> extensions; |
527 SplitString(extensions_to_open, L':', &extensions); | 527 SplitString(extensions_to_open, L':', &extensions); |
528 for (size_t i = 0; i < extensions.size(); ++i) { | 528 for (size_t i = 0; i < extensions.size(); ++i) { |
529 if (!extensions[i].empty() && !IsExecutableFile( | 529 if (!extensions[i].empty() && !IsExecutable( |
530 FilePath::FromWStringHack(extensions[i]))) | 530 FilePath::FromWStringHack(extensions[i]).value())) |
531 auto_open_.insert(FilePath::FromWStringHack(extensions[i]).value()); | 531 auto_open_.insert(FilePath::FromWStringHack(extensions[i]).value()); |
532 } | 532 } |
533 | 533 |
534 return true; | 534 return true; |
535 } | 535 } |
536 | 536 |
537 void DownloadManager::QueryHistoryForDownloads() { | 537 void DownloadManager::QueryHistoryForDownloads() { |
538 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | 538 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
539 if (hs) { | 539 if (hs) { |
540 hs->QueryDownloads( | 540 hs->QueryDownloads( |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 const FilePath& full_path) { | 850 const FilePath& full_path) { |
851 } | 851 } |
852 | 852 |
853 void DownloadManager::ContinueDownloadFinished(DownloadItem* download) { | 853 void DownloadManager::ContinueDownloadFinished(DownloadItem* download) { |
854 // If this was a dangerous download, it has now been approved and must be | 854 // If this was a dangerous download, it has now been approved and must be |
855 // removed from dangerous_finished_ so it does not get deleted on shutdown. | 855 // removed from dangerous_finished_ so it does not get deleted on shutdown. |
856 DownloadMap::iterator it = dangerous_finished_.find(download->id()); | 856 DownloadMap::iterator it = dangerous_finished_.find(download->id()); |
857 if (it != dangerous_finished_.end()) | 857 if (it != dangerous_finished_.end()) |
858 dangerous_finished_.erase(it); | 858 dangerous_finished_.erase(it); |
859 | 859 |
| 860 // Open the download if the user or user prefs indicate it should be. |
| 861 FilePath::StringType extension = download->full_path().Extension(); |
| 862 // Drop the leading period. (The auto-open list is period-less.) |
| 863 if (extension.size() > 0) |
| 864 extension = extension.substr(1); |
| 865 |
860 // Handle chrome extensions explicitly and skip the shell execute. | 866 // Handle chrome extensions explicitly and skip the shell execute. |
861 if (IsExtensionInstall(download)) { | 867 if (IsExtensionInstall(download)) { |
862 OpenChromeExtension(download->full_path(), download->url(), | 868 OpenChromeExtension(download->full_path(), download->url(), |
863 download->referrer_url()); | 869 download->referrer_url()); |
864 download->set_auto_opened(true); | 870 download->set_auto_opened(true); |
865 } else if (download->open_when_complete() || | 871 } else if (download->open_when_complete() || |
866 ShouldOpenFileBasedOnExtension(download->full_path())) { | 872 ShouldOpenFileExtension(extension)) { |
867 OpenDownloadInShell(download, NULL); | 873 OpenDownloadInShell(download, NULL); |
868 download->set_auto_opened(true); | 874 download->set_auto_opened(true); |
869 } | 875 } |
870 | 876 |
871 // Notify our observers that we are complete (the call to Finished() set the | 877 // Notify our observers that we are complete (the call to Finished() set the |
872 // state to complete but did not notify). | 878 // state to complete but did not notify). |
873 download->UpdateObservers(); | 879 download->UpdateObservers(); |
874 } | 880 } |
875 | |
876 // Called on the file thread. Renames the downloaded file to its original name. | 881 // Called on the file thread. Renames the downloaded file to its original name. |
877 void DownloadManager::ProceedWithFinishedDangerousDownload( | 882 void DownloadManager::ProceedWithFinishedDangerousDownload( |
878 int64 download_handle, | 883 int64 download_handle, |
879 const FilePath& path, | 884 const FilePath& path, |
880 const FilePath& original_name) { | 885 const FilePath& original_name) { |
881 bool success = false; | 886 bool success = false; |
882 FilePath new_path; | 887 FilePath new_path; |
883 int uniquifier = 0; | 888 int uniquifier = 0; |
884 if (file_util::PathExists(path)) { | 889 if (file_util::PathExists(path)) { |
885 new_path = path.DirName().Append(original_name); | 890 new_path = path.DirName().Append(original_name); |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
992 // static | 997 // static |
993 void DownloadManager::OnPauseDownloadRequest(ResourceDispatcherHost* rdh, | 998 void DownloadManager::OnPauseDownloadRequest(ResourceDispatcherHost* rdh, |
994 int render_process_id, | 999 int render_process_id, |
995 int request_id, | 1000 int request_id, |
996 bool pause) { | 1001 bool pause) { |
997 rdh->PauseRequest(render_process_id, request_id, pause); | 1002 rdh->PauseRequest(render_process_id, request_id, pause); |
998 } | 1003 } |
999 | 1004 |
1000 bool DownloadManager::IsDangerous(const FilePath& file_name) { | 1005 bool DownloadManager::IsDangerous(const FilePath& file_name) { |
1001 // TODO(jcampan): Improve me. | 1006 // TODO(jcampan): Improve me. |
1002 return IsExecutableFile(file_name); | 1007 FilePath::StringType extension = file_name.Extension(); |
| 1008 // Drop the leading period. |
| 1009 if (extension.size() > 0) |
| 1010 extension = extension.substr(1); |
| 1011 return IsExecutable(extension); |
1003 } | 1012 } |
1004 | 1013 |
1005 void DownloadManager::RenameDownload(DownloadItem* download, | 1014 void DownloadManager::RenameDownload(DownloadItem* download, |
1006 const FilePath& new_path) { | 1015 const FilePath& new_path) { |
1007 download->Rename(new_path); | 1016 download->Rename(new_path); |
1008 | 1017 |
1009 // Update the history. | 1018 // Update the history. |
1010 | 1019 |
1011 // No update necessary if the download was initiated while in incognito mode. | 1020 // No update necessary if the download was initiated while in incognito mode. |
1012 if (download->db_handle() <= kUninitializedHandle) | 1021 if (download->db_handle() <= kUninitializedHandle) |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 | 1148 |
1140 std::string mime_type_from_extension; | 1149 std::string mime_type_from_extension; |
1141 net::GetMimeTypeFromFile(file_name, | 1150 net::GetMimeTypeFromFile(file_name, |
1142 &mime_type_from_extension); | 1151 &mime_type_from_extension); |
1143 if (mime_type == mime_type_from_extension) { | 1152 if (mime_type == mime_type_from_extension) { |
1144 // The hinted extension matches the mime type. It looks like a winner. | 1153 // The hinted extension matches the mime type. It looks like a winner. |
1145 generated_extension->swap(extension); | 1154 generated_extension->swap(extension); |
1146 return; | 1155 return; |
1147 } | 1156 } |
1148 | 1157 |
1149 if (IsExecutableExtension(extension) && !IsExecutableMimeType(mime_type)) { | 1158 if (IsExecutable(extension) && !IsExecutableMimeType(mime_type)) { |
1150 // We want to be careful about executable extensions. The worry here is | 1159 // We want to be careful about executable extensions. The worry here is |
1151 // that a trusted web site could be tricked into dropping an executable file | 1160 // that a trusted web site could be tricked into dropping an executable file |
1152 // on the user's filesystem. | 1161 // on the user's filesystem. |
1153 if (!net::GetPreferredExtensionForMimeType(mime_type, &extension)) { | 1162 if (!net::GetPreferredExtensionForMimeType(mime_type, &extension)) { |
1154 // We couldn't find a good extension for this content type. Use a dummy | 1163 // We couldn't find a good extension for this content type. Use a dummy |
1155 // extension instead. | 1164 // extension instead. |
1156 extension.assign(default_extension); | 1165 extension.assign(default_extension); |
1157 } | 1166 } |
1158 } | 1167 } |
1159 | 1168 |
1160 if (extension.empty()) { | 1169 if (extension.empty()) { |
1161 net::GetPreferredExtensionForMimeType(mime_type, &extension); | 1170 net::GetPreferredExtensionForMimeType(mime_type, &extension); |
1162 } else { | 1171 } else { |
1163 // Append extension generated from the mime type if: | 1172 // Append extension generated from the mime type if: |
1164 // 1. New extension is not ".txt" | 1173 // 1. New extension is not ".txt" |
1165 // 2. New extension is not the same as the already existing extension. | 1174 // 2. New extension is not the same as the already existing extension. |
1166 // 3. New extension is not executable. This action mitigates the case when | 1175 // 3. New extension is not executable. This action mitigates the case when |
1167 // an executable is hidden in a benign file extension; | 1176 // an executable is hidden in a benign file extension; |
1168 // E.g. my-cat.jpg becomes my-cat.jpg.js if content type is | 1177 // E.g. my-cat.jpg becomes my-cat.jpg.js if content type is |
1169 // application/x-javascript. | 1178 // application/x-javascript. |
1170 // 4. New extension is not ".tar" for .gz files. For misconfigured web | 1179 // 4. New extension is not ".tar" for .gz files. For misconfigured web |
1171 // servers, i.e. bug 5772. | 1180 // servers, i.e. bug 5772. |
1172 // 5. The original extension is not ".tgz" & the new extension is not "gz". | 1181 // 5. The original extension is not ".tgz" & the new extension is not "gz". |
1173 FilePath::StringType append_extension; | 1182 FilePath::StringType append_extension; |
1174 if (net::GetPreferredExtensionForMimeType(mime_type, &append_extension)) { | 1183 if (net::GetPreferredExtensionForMimeType(mime_type, &append_extension)) { |
1175 if (append_extension != FILE_PATH_LITERAL("txt") && | 1184 if (append_extension != FILE_PATH_LITERAL("txt") && |
1176 append_extension != extension && | 1185 append_extension != extension && |
1177 !IsExecutableExtension(append_extension) && | 1186 !IsExecutable(append_extension) && |
1178 !(append_extension == FILE_PATH_LITERAL("gz") && | 1187 !(append_extension == FILE_PATH_LITERAL("gz") && |
1179 extension == FILE_PATH_LITERAL("tgz")) && | 1188 extension == FILE_PATH_LITERAL("tgz")) && |
1180 (append_extension != FILE_PATH_LITERAL("tar") || | 1189 (append_extension != FILE_PATH_LITERAL("tar") || |
1181 extension != FILE_PATH_LITERAL("gz"))) { | 1190 extension != FILE_PATH_LITERAL("gz"))) { |
1182 extension += FILE_PATH_LITERAL("."); | 1191 extension += FILE_PATH_LITERAL("."); |
1183 extension += append_extension; | 1192 extension += append_extension; |
1184 } | 1193 } |
1185 } | 1194 } |
1186 } | 1195 } |
1187 | 1196 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1266 // Mac OS X requires opening downloads on the UI thread. | 1275 // Mac OS X requires opening downloads on the UI thread. |
1267 platform_util::OpenItem(download->full_path()); | 1276 platform_util::OpenItem(download->full_path()); |
1268 #else | 1277 #else |
1269 file_loop_->PostTask(FROM_HERE, | 1278 file_loop_->PostTask(FROM_HERE, |
1270 NewRunnableMethod(file_manager_, | 1279 NewRunnableMethod(file_manager_, |
1271 &DownloadFileManager::OnOpenDownloadInShell, | 1280 &DownloadFileManager::OnOpenDownloadInShell, |
1272 download->full_path(), download->url(), parent_window)); | 1281 download->full_path(), download->url(), parent_window)); |
1273 #endif | 1282 #endif |
1274 } | 1283 } |
1275 | 1284 |
1276 void DownloadManager::OpenFilesBasedOnExtension( | 1285 void DownloadManager::OpenFilesOfExtension( |
1277 const FilePath& path, bool open) { | 1286 const FilePath::StringType& extension, bool open) { |
1278 FilePath::StringType extension = path.Extension(); | 1287 if (open && !IsExecutable(extension)) |
1279 if (extension.empty()) | |
1280 return; | |
1281 DCHECK(extension[0] == FilePath::kExtensionSeparator); | |
1282 extension.erase(0, 1); | |
1283 if (open && !IsExecutableExtension(extension)) | |
1284 auto_open_.insert(extension); | 1288 auto_open_.insert(extension); |
1285 else | 1289 else |
1286 auto_open_.erase(extension); | 1290 auto_open_.erase(extension); |
1287 SaveAutoOpens(); | 1291 SaveAutoOpens(); |
1288 } | 1292 } |
1289 | 1293 |
1290 bool DownloadManager::ShouldOpenFileBasedOnExtension( | 1294 bool DownloadManager::ShouldOpenFileExtension( |
1291 const FilePath& path) const { | 1295 const FilePath::StringType& extension) { |
1292 // Special-case Chrome extensions as always-open. | 1296 // Special-case Chrome extensions as always-open. |
1293 FilePath::StringType extension = path.Extension(); | 1297 if (!IsExecutable(extension) && |
1294 if (extension.empty()) | 1298 (auto_open_.find(extension) != auto_open_.end() || |
1295 return false; | 1299 Extension::IsExtension(FilePath(extension)))) |
1296 if (IsExecutableExtension(extension)) | |
1297 return false; | |
1298 DCHECK(extension[0] == FilePath::kExtensionSeparator); | |
1299 extension.erase(0, 1); | |
1300 if (auto_open_.find(extension) != auto_open_.end() || | |
1301 Extension::IsExtension(path)) | |
1302 return true; | 1300 return true; |
1303 return false; | 1301 return false; |
1304 } | 1302 } |
1305 | 1303 |
1306 static const char* kExecutableWhiteList[] = { | 1304 static const char* kExecutableWhiteList[] = { |
1307 // JavaScript is just as powerful as EXE. | 1305 // JavaScript is just as powerful as EXE. |
1308 "text/javascript", | 1306 "text/javascript", |
1309 "text/javascript;version=*", | 1307 "text/javascript;version=*", |
1310 // Registry files can cause critical changes to the MS OS behavior. | 1308 // Registry files can cause critical changes to the MS OS behavior. |
1311 // Addition of this mimetype also addresses bug 7337. | 1309 // Addition of this mimetype also addresses bug 7337. |
(...skipping 16 matching lines...) Expand all Loading... |
1328 return true; | 1326 return true; |
1329 } | 1327 } |
1330 for (size_t i = 0; i < arraysize(kExecutableBlackList); ++i) { | 1328 for (size_t i = 0; i < arraysize(kExecutableBlackList); ++i) { |
1331 if (net::MatchesMimeType(kExecutableBlackList[i], mime_type)) | 1329 if (net::MatchesMimeType(kExecutableBlackList[i], mime_type)) |
1332 return false; | 1330 return false; |
1333 } | 1331 } |
1334 // We consider only other application types to be executable. | 1332 // We consider only other application types to be executable. |
1335 return net::MatchesMimeType("application/*", mime_type); | 1333 return net::MatchesMimeType("application/*", mime_type); |
1336 } | 1334 } |
1337 | 1335 |
1338 bool DownloadManager::IsExecutableFile(const FilePath& path) const { | 1336 bool DownloadManager::IsExecutable(const FilePath::StringType& extension) { |
1339 return IsExecutableExtension(path.Extension()); | |
1340 } | |
1341 | |
1342 bool DownloadManager::IsExecutableExtension( | |
1343 const FilePath::StringType& extension) const { | |
1344 if (extension.empty()) | |
1345 return false; | |
1346 if (!IsStringASCII(extension)) | 1337 if (!IsStringASCII(extension)) |
1347 return false; | 1338 return false; |
1348 #if defined(OS_WIN) | 1339 #if defined(OS_WIN) |
1349 std::string ascii_extension = WideToASCII(extension); | 1340 std::string ascii_extension = WideToASCII(extension); |
1350 #elif defined(OS_POSIX) | 1341 #elif defined(OS_POSIX) |
1351 std::string ascii_extension = extension; | 1342 std::string ascii_extension = extension; |
1352 #endif | 1343 #endif |
1353 StringToLowerASCII(&ascii_extension); | 1344 StringToLowerASCII(&ascii_extension); |
1354 | 1345 |
1355 // Strip out leading dot if it's still there | |
1356 if (ascii_extension[0] == FilePath::kExtensionSeparator) | |
1357 ascii_extension.erase(0, 1); | |
1358 | |
1359 return exe_types_.find(ascii_extension) != exe_types_.end(); | 1346 return exe_types_.find(ascii_extension) != exe_types_.end(); |
1360 } | 1347 } |
1361 | 1348 |
1362 void DownloadManager::ResetAutoOpenFiles() { | 1349 void DownloadManager::ResetAutoOpenFiles() { |
1363 auto_open_.clear(); | 1350 auto_open_.clear(); |
1364 SaveAutoOpens(); | 1351 SaveAutoOpens(); |
1365 } | 1352 } |
1366 | 1353 |
1367 bool DownloadManager::HasAutoOpenFileTypesRegistered() const { | 1354 bool DownloadManager::HasAutoOpenFileTypesRegistered() const { |
1368 return !auto_open_.empty(); | 1355 return !auto_open_.empty(); |
1369 } | 1356 } |
1370 | 1357 |
1371 void DownloadManager::SaveAutoOpens() { | 1358 void DownloadManager::SaveAutoOpens() { |
1372 PrefService* prefs = profile_->GetPrefs(); | 1359 PrefService* prefs = profile_->GetPrefs(); |
1373 if (prefs) { | 1360 if (prefs) { |
1374 FilePath::StringType extensions; | 1361 FilePath::StringType extensions; |
1375 for (AutoOpenSet::iterator it = auto_open_.begin(); | 1362 for (std::set<FilePath::StringType>::iterator it = auto_open_.begin(); |
1376 it != auto_open_.end(); ++it) { | 1363 it != auto_open_.end(); ++it) { |
1377 extensions += *it + FILE_PATH_LITERAL(":"); | 1364 extensions += *it + FILE_PATH_LITERAL(":"); |
1378 } | 1365 } |
1379 if (!extensions.empty()) | 1366 if (!extensions.empty()) |
1380 extensions.erase(extensions.size() - 1); | 1367 extensions.erase(extensions.size() - 1); |
1381 | 1368 |
1382 std::wstring extensions_w; | 1369 std::wstring extensions_w; |
1383 #if defined(OS_WIN) | 1370 #if defined(OS_WIN) |
1384 extensions_w = extensions; | 1371 extensions_w = extensions; |
1385 #elif defined(OS_POSIX) | 1372 #elif defined(OS_POSIX) |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1548 | 1535 |
1549 if (contents) | 1536 if (contents) |
1550 contents->OnStartDownload(download); | 1537 contents->OnStartDownload(download); |
1551 } | 1538 } |
1552 | 1539 |
1553 // Clears the last download path, used to initialize "save as" dialogs. | 1540 // Clears the last download path, used to initialize "save as" dialogs. |
1554 void DownloadManager::ClearLastDownloadPath() { | 1541 void DownloadManager::ClearLastDownloadPath() { |
1555 last_download_path_ = FilePath(); | 1542 last_download_path_ = FilePath(); |
1556 } | 1543 } |
1557 | 1544 |
OLD | NEW |