| 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 |