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