1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/extensions/file_manager/file_tasks.h" 6 7 #include "apps/launcher.h" 8 #include "base/bind.h" 9 #include "base/strings/stringprintf.h" 10 #include "chrome/browser/chromeos/drive/file_task_executor.h" 11 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handlers.h" 12 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h" 13 #include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h" 14 #include "chrome/browser/chromeos/fileapi/file_system_backend.h" 15 #include "chrome/browser/extensions/extension_host.h" 16 #include "chrome/browser/extensions/extension_service.h" 17 #include "chrome/browser/extensions/extension_system.h" 18 #include "chrome/browser/extensions/extension_tab_util.h" 19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/common/pref_names.h" 21 #include "webkit/browser/fileapi/file_system_context.h" 22 #include "webkit/browser/fileapi/file_system_url.h" 23 24 using extensions::Extension; 25 using fileapi::FileSystemURL; 26 27 namespace file_manager { 28 namespace file_tasks { 29 30 // The values "file" and "app" are confusing, but cannot be changed easily as 31 // these are used in default task IDs stored in preferences. 32 // 33 // TODO(satorux): We should rename them to "file_browser_handler" and 34 // "file_handler" respectively when switching from preferences to 35 // chrome.storage crbug.com/267359 36 const char kFileBrowserHandlerTaskType[] = "file"; 37 const char kFileHandlerTaskType[] = "app"; 38 const char kDriveTaskType[] = "drive"; 39 40 namespace { 41 42 // Legacy Drive task extension prefix, used by CrackTaskID. 43 const char kDriveTaskExtensionPrefix[] = "drive-app:"; 44 const size_t kDriveTaskExtensionPrefixLength = 45 arraysize(kDriveTaskExtensionPrefix) - 1; 46 47 // Checks if the file browser extension has permissions for the files in its 48 // file system context. 49 bool FileBrowserHasAccessPermissionForFiles( 50 Profile* profile, 51 const GURL& source_url, 52 const std::string& file_browser_id, 53 const std::vector<FileSystemURL>& files) { 54 fileapi::ExternalFileSystemBackend* backend = 55 fileapi_util::GetFileSystemContextForExtensionId( 56 profile, file_browser_id)->external_backend(); 57 if (!backend) 58 return false; 59 60 for (size_t i = 0; i < files.size(); ++i) { 61 // Make sure this url really being used by the right caller extension. 62 if (source_url.GetOrigin() != files[i].origin()) 63 return false; 64 65 if (!chromeos::FileSystemBackend::CanHandleURL(files[i]) || 66 !backend->IsAccessAllowed(files[i])) { 67 return false; 68 } 69 } 70 71 return true; 72 } 73 74 } // namespace 75 76 void UpdateDefaultTask(Profile* profile, 77 const std::string& task_id, 78 const std::set<std::string>& suffixes, 79 const std::set<std::string>& mime_types) { 80 if (!profile || !profile->GetPrefs()) 81 return; 82 83 if (!mime_types.empty()) { 84 DictionaryPrefUpdate mime_type_pref(profile->GetPrefs(), 85 prefs::kDefaultTasksByMimeType); 86 for (std::set<std::string>::const_iterator iter = mime_types.begin(); 87 iter != mime_types.end(); ++iter) { 88 base::StringValue* value = new base::StringValue(task_id); 89 mime_type_pref->SetWithoutPathExpansion(*iter, value); 90 } 91 } 92 93 if (!suffixes.empty()) { 94 DictionaryPrefUpdate mime_type_pref(profile->GetPrefs(), 95 prefs::kDefaultTasksBySuffix); 96 for (std::set<std::string>::const_iterator iter = suffixes.begin(); 97 iter != suffixes.end(); ++iter) { 98 base::StringValue* value = new base::StringValue(task_id); 99 // Suffixes are case insensitive. 100 std::string lower_suffix = StringToLowerASCII(*iter); 101 mime_type_pref->SetWithoutPathExpansion(lower_suffix, value); 102 } 103 } 104 } 105 106 std::string GetDefaultTaskIdFromPrefs(Profile* profile, 107 const std::string& mime_type, 108 const std::string& suffix) { 109 VLOG(1) << "Looking for default for MIME type: " << mime_type 110 << " and suffix: " << suffix; 111 std::string task_id; 112 if (!mime_type.empty()) { 113 const DictionaryValue* mime_task_prefs = 114 profile->GetPrefs()->GetDictionary(prefs::kDefaultTasksByMimeType); 115 DCHECK(mime_task_prefs); 116 LOG_IF(ERROR, !mime_task_prefs) << "Unable to open MIME type prefs"; 117 if (mime_task_prefs && 118 mime_task_prefs->GetStringWithoutPathExpansion(mime_type, &task_id)) { 119 VLOG(1) << "Found MIME default handler: " << task_id; 120 return task_id; 121 } 122 } 123 124 const DictionaryValue* suffix_task_prefs = 125 profile->GetPrefs()->GetDictionary(prefs::kDefaultTasksBySuffix); 126 DCHECK(suffix_task_prefs); 127 LOG_IF(ERROR, !suffix_task_prefs) << "Unable to open suffix prefs"; 128 std::string lower_suffix = StringToLowerASCII(suffix); 129 if (suffix_task_prefs) 130 suffix_task_prefs->GetStringWithoutPathExpansion(lower_suffix, &task_id); 131 VLOG_IF(1, !task_id.empty()) << "Found suffix default handler: " << task_id; 132 return task_id; 133 } 134 135 std::string MakeTaskID(const std::string& extension_id, 136 const std::string& task_type, 137 const std::string& action_id) { 138 DCHECK(task_type == kFileBrowserHandlerTaskType || 139 task_type == kDriveTaskType || 140 task_type == kFileHandlerTaskType); 141 return base::StringPrintf("%s|%s|%s", 142 extension_id.c_str(), 143 task_type.c_str(), 144 action_id.c_str()); 145 } 146 147 std::string MakeDriveAppTaskId(const std::string& app_id) { 148 return MakeTaskID(app_id, kDriveTaskType, "open-with"); 149 } 150 151 bool ParseTaskID(const std::string& task_id, TaskDescriptor* task) { 152 DCHECK(task); 153 154 std::vector<std::string> result; 155 int count = Tokenize(task_id, std::string("|"), &result); 156 157 // Parse a legacy task ID that only contain two parts. Drive tasks are 158 // identified by a prefix "drive-app:" on the extension ID. The legacy task 159 // IDs can be stored in preferences. 160 // TODO(satorux): We should get rid of this code: crbug.com/267359. 161 if (count == 2) { 162 if (StartsWithASCII(result[0], kDriveTaskExtensionPrefix, true)) { 163 task->task_type = kDriveTaskType; 164 task->app_id = result[0].substr(kDriveTaskExtensionPrefixLength); 165 } else { 166 task->task_type = kFileBrowserHandlerTaskType; 167 task->app_id = result[0]; 168 } 169 170 task->action_id = result[1]; 171 172 return true; 173 } 174 175 if (count != 3) 176 return false; 177 178 task->app_id = result[0]; 179 task->task_type = result[1]; 180 DCHECK(task->task_type == kFileBrowserHandlerTaskType || 181 task->task_type == kDriveTaskType || 182 task->task_type == kFileHandlerTaskType); 183 task->action_id = result[2]; 184 185 return true; 186 } 187 188 bool ExecuteFileTask(Profile* profile, 189 const GURL& source_url, 190 const std::string& file_browser_id, 191 int32 tab_id, 192 const TaskDescriptor& task, 193 const std::vector<FileSystemURL>& file_urls, 194 const FileTaskFinishedCallback& done) { 195 if (!FileBrowserHasAccessPermissionForFiles(profile, source_url, 196 file_browser_id, file_urls)) 197 return false; 198 199 // drive::FileTaskExecutor is responsible to handle drive tasks. 200 if (task.task_type == kDriveTaskType) { 201 DCHECK_EQ("open-with", task.action_id); 202 drive::FileTaskExecutor* executor = 203 new drive::FileTaskExecutor(profile, task.app_id); 204 executor->Execute(file_urls, done); 205 return true; 206 } 207 208 // Get the extension. 209 ExtensionService* service = 210 extensions::ExtensionSystem::Get(profile)->extension_service(); 211 const Extension* extension = service ? 212 service->GetExtensionById(task.app_id, false) : NULL; 213 if (!extension) 214 return false; 215 216 // Execute the task. 217 if (task.task_type == kFileBrowserHandlerTaskType) { 218 return file_browser_handlers::ExecuteFileBrowserHandler( 219 profile, 220 extension, 221 tab_id, 222 task.action_id, 223 file_urls, 224 done); 225 } else if (task.task_type == kFileHandlerTaskType) { 226 for (size_t i = 0; i != file_urls.size(); ++i) { 227 apps::LaunchPlatformAppWithFileHandler( 228 profile, extension, task.action_id, file_urls[i].path()); 229 } 230 231 if (!done.is_null()) 232 done.Run(true); 233 return true; 234 } 235 NOTREACHED(); 236 return false; 237 } 238 239 } // namespace file_tasks 240 } // namespace file_manager 241