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

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

Issue 149796: Bug fix for 10876, file extension handling refactoring (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 1 month 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
« no previous file with comments | « chrome/browser/download/download_manager.h ('k') | chrome/browser/download/download_shelf.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/download/download_manager.h ('k') | chrome/browser/download/download_shelf.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698