1 // Copyright 2013 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.
5 #include "chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h"
11 #include "chrome/browser/chromeos/drive/file_system_util.h"
12 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
13 #include "chrome/browser/chromeos/file_manager/mime_util.h"
14 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/filename_util.h"
18 #include "net/base/mime_sniffer.h"
19 #include "webkit/browser/fileapi/file_system_context.h"
20 #include "webkit/browser/fileapi/file_system_url.h"
22 using content::BrowserThread;
23 using extensions::app_file_handler_util::PathAndMimeTypeSet;
24 using fileapi::FileSystemURL;
26 namespace extensions {
30 const char kInvalidFileUrl[] = "Invalid file URL";
32 // Make a set of unique filename suffixes out of the list of file URLs.
33 std::set<std::string> GetUniqueSuffixes(
34 const std::vector<std::string>& file_url_list,
35 const fileapi::FileSystemContext* context) {
36 std::set<std::string> suffixes;
37 for (size_t i = 0; i < file_url_list.size(); ++i) {
38 const FileSystemURL url = context->CrackURL(GURL(file_url_list[i]));
39 if (!url.is_valid() || url.path().empty())
40 return std::set<std::string>();
41 // We'll skip empty suffixes.
42 if (!url.path().Extension().empty())
43 suffixes.insert(url.path().Extension());
48 // Make a set of unique MIME types out of the list of MIME types.
49 std::set<std::string> GetUniqueMimeTypes(
50 const std::vector<std::string>& mime_type_list) {
51 std::set<std::string> mime_types;
52 for (size_t i = 0; i < mime_type_list.size(); ++i) {
53 const std::string mime_type = mime_type_list[i];
54 // We'll skip empty MIME types and existing MIME types.
55 if (!mime_type.empty())
56 mime_types.insert(mime_type);
61 void SniffMimeType(PathAndMimeTypeSet* path_mime_set,
62 std::vector<GURL>* file_urls) {
63 PathAndMimeTypeSet sniffed_path_mime_set;
64 std::vector<char> content(net::kMaxBytesToSniff);
66 // For each files, sniff its MIME type if it is empty
67 for (PathAndMimeTypeSet::iterator it = path_mime_set->begin();
68 it != path_mime_set->end();
70 const base::FilePath& file_path = it->first;
71 std::string mime_type = it->second;
72 // Note: sniff MIME type only for local files.
73 if (mime_type.empty() && !drive::util::IsUnderDriveMountPoint(file_path)) {
74 int bytes_read = base::ReadFile(file_path, &content[0], content.size());
75 if (bytes_read >= 0) {
76 net::SniffMimeType(&content[0],
78 net::FilePathToFileURL(file_path),
79 std::string(), // type_hint (passes no hint)
83 sniffed_path_mime_set.insert(std::make_pair(file_path, mime_type));
85 path_mime_set->swap(sniffed_path_mime_set);
90 bool FileBrowserPrivateExecuteTaskFunction::RunAsync() {
91 using extensions::api::file_browser_private::ExecuteTask::Params;
92 using extensions::api::file_browser_private::ExecuteTask::Results::Create;
93 const scoped_ptr<Params> params(Params::Create(*args_));
94 EXTENSION_FUNCTION_VALIDATE(params);
96 file_manager::file_tasks::TaskDescriptor task;
97 if (!file_manager::file_tasks::ParseTaskID(params->task_id, &task)) {
98 LOG(WARNING) << "Invalid task " << params->task_id;
100 Create(extensions::api::file_browser_private::TASK_RESULT_FAILED);
104 if (params->file_urls.empty()) {
105 results_ = Create(extensions::api::file_browser_private::TASK_RESULT_EMPTY);
110 const scoped_refptr<fileapi::FileSystemContext> file_system_context =
111 file_manager::util::GetFileSystemContextForRenderViewHost(
112 GetProfile(), render_view_host());
114 std::vector<FileSystemURL> file_urls;
115 for (size_t i = 0; i < params->file_urls.size(); i++) {
116 const FileSystemURL url =
117 file_system_context->CrackURL(GURL(params->file_urls[i]));
118 if (!chromeos::FileSystemBackend::CanHandleURL(url)) {
119 SetError(kInvalidFileUrl);
121 Create(extensions::api::file_browser_private::TASK_RESULT_FAILED);
124 file_urls.push_back(url);
127 const bool result = file_manager::file_tasks::ExecuteFileTask(
132 base::Bind(&FileBrowserPrivateExecuteTaskFunction::OnTaskExecuted, this));
135 Create(extensions::api::file_browser_private::TASK_RESULT_FAILED);
140 void FileBrowserPrivateExecuteTaskFunction::OnTaskExecuted(
141 extensions::api::file_browser_private::TaskResult result) {
143 extensions::api::file_browser_private::ExecuteTask::Results::Create(
145 SendResponse(result !=
146 extensions::api::file_browser_private::TASK_RESULT_FAILED);
149 bool FileBrowserPrivateGetFileTasksFunction::RunAsync() {
150 using extensions::api::file_browser_private::GetFileTasks::Params;
151 const scoped_ptr<Params> params(Params::Create(*args_));
152 EXTENSION_FUNCTION_VALIDATE(params);
154 if (params->file_urls.empty())
157 // MIME types can either be empty, or there needs to be one for each file.
158 if (params->mime_types.size() != params->file_urls.size() &&
159 params->mime_types.size() != 0)
162 const scoped_refptr<fileapi::FileSystemContext> file_system_context =
163 file_manager::util::GetFileSystemContextForRenderViewHost(
164 GetProfile(), render_view_host());
166 // Collect all the URLs, convert them to GURLs, and crack all the urls into
168 scoped_ptr<PathAndMimeTypeSet> path_mime_set(new PathAndMimeTypeSet);
169 scoped_ptr<std::vector<GURL> > file_urls(new std::vector<GURL>);
170 for (size_t i = 0; i < params->file_urls.size(); ++i) {
171 std::string mime_type;
172 if (params->mime_types.size() != 0)
173 mime_type = params->mime_types[i];
175 const GURL file_url(params->file_urls[i]);
176 fileapi::FileSystemURL file_system_url(
177 file_system_context->CrackURL(file_url));
178 if (!chromeos::FileSystemBackend::CanHandleURL(file_system_url))
180 const base::FilePath file_path = file_system_url.path();
182 file_urls->push_back(file_url);
184 // If MIME type is not provided, guess it from the file path.
185 if (mime_type.empty())
186 mime_type = file_manager::util::GetMimeTypeForPath(file_path);
188 path_mime_set->insert(std::make_pair(file_path, mime_type));
191 // In case the MIME type of some files are empty,
192 // try to sniff their MIME type by their content.
193 PathAndMimeTypeSet* path_mime_set_ptr = path_mime_set.get();
194 std::vector<GURL>* file_urls_ptr = file_urls.get();
196 BrowserThread::PostBlockingPoolTaskAndReply(
198 base::Bind(&SniffMimeType, path_mime_set_ptr, file_urls_ptr),
200 &FileBrowserPrivateGetFileTasksFunction::OnSniffingMimeTypeCompleted,
202 base::Passed(&path_mime_set),
203 base::Passed(&file_urls)));
207 void FileBrowserPrivateGetFileTasksFunction::OnSniffingMimeTypeCompleted(
208 scoped_ptr<PathAndMimeTypeSet> path_mime_set,
209 scoped_ptr<std::vector<GURL> > file_urls) {
210 std::vector<file_manager::file_tasks::FullTaskDescriptor> tasks;
211 file_manager::file_tasks::FindAllTypesOfTasks(
213 drive::util::GetDriveAppRegistryByProfile(GetProfile()),
218 // Convert the tasks into JSON compatible objects.
219 using api::file_browser_private::FileTask;
220 std::vector<linked_ptr<FileTask> > results;
221 for (size_t i = 0; i < tasks.size(); ++i) {
222 const file_manager::file_tasks::FullTaskDescriptor& task = tasks[i];
223 const linked_ptr<FileTask> converted(new FileTask);
224 converted->task_id = file_manager::file_tasks::TaskDescriptorToId(
225 task.task_descriptor());
226 if (!task.icon_url().is_empty())
227 converted->icon_url = task.icon_url().spec();
228 converted->title = task.task_title();
229 converted->is_default = task.is_default();
230 results.push_back(converted);
232 results_ = extensions::api::file_browser_private::GetFileTasks::Results::
237 bool FileBrowserPrivateSetDefaultTaskFunction::RunSync() {
238 using extensions::api::file_browser_private::SetDefaultTask::Params;
239 const scoped_ptr<Params> params(Params::Create(*args_));
240 EXTENSION_FUNCTION_VALIDATE(params);
242 const scoped_refptr<fileapi::FileSystemContext> file_system_context =
243 file_manager::util::GetFileSystemContextForRenderViewHost(
244 GetProfile(), render_view_host());
246 const std::set<std::string> suffixes =
247 GetUniqueSuffixes(params->file_urls, file_system_context.get());
249 // MIME types are an optional parameter.
250 std::set<std::string> mime_types;
251 if (params->mime_types && !params->mime_types->empty()) {
252 if (params->mime_types->size() != params->file_urls.size())
254 mime_types = GetUniqueMimeTypes(*params->mime_types);
257 // If there weren't any mime_types, and all the suffixes were blank,
258 // then we "succeed", but don't actually associate with anything.
259 // Otherwise, any time we set the default on a file with no extension
260 // on the local drive, we'd fail.
261 // TODO(gspencer): Fix file manager so that it never tries to set default in
262 // cases where extensionless local files are part of the selection.
263 if (suffixes.empty() && mime_types.empty()) {
264 SetResult(new base::FundamentalValue(true));
268 file_manager::file_tasks::UpdateDefaultTask(
269 GetProfile()->GetPrefs(), params->task_id, suffixes, mime_types);
273 } // namespace extensions