Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / extensions / file_manager / private_api_tasks.cc
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.
4
5 #include "chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h"
6
7 #include <set>
8 #include <string>
9 #include <vector>
10
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"
21
22 using content::BrowserThread;
23 using extensions::app_file_handler_util::PathAndMimeTypeSet;
24 using fileapi::FileSystemURL;
25
26 namespace extensions {
27 namespace {
28
29 // Error messages.
30 const char kInvalidFileUrl[] = "Invalid file URL";
31
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());
44   }
45   return suffixes;
46 }
47
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);
57   }
58   return mime_types;
59 }
60
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);
65
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();
69        ++it) {
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],
77                            bytes_read,
78                            net::FilePathToFileURL(file_path),
79                            std::string(),  // type_hint (passes no hint)
80                            &mime_type);
81       }
82     }
83     sniffed_path_mime_set.insert(std::make_pair(file_path, mime_type));
84   }
85   path_mime_set->swap(sniffed_path_mime_set);
86 }
87
88 }  // namespace
89
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);
95
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;
99     results_ =
100         Create(extensions::api::file_browser_private::TASK_RESULT_FAILED);
101     return false;
102   }
103
104   if (params->file_urls.empty()) {
105     results_ = Create(extensions::api::file_browser_private::TASK_RESULT_EMPTY);
106     SendResponse(true);
107     return true;
108   }
109
110   const scoped_refptr<fileapi::FileSystemContext> file_system_context =
111       file_manager::util::GetFileSystemContextForRenderViewHost(
112           GetProfile(), render_view_host());
113
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);
120       results_ =
121           Create(extensions::api::file_browser_private::TASK_RESULT_FAILED);
122       return false;
123     }
124     file_urls.push_back(url);
125   }
126
127   const bool result = file_manager::file_tasks::ExecuteFileTask(
128       GetProfile(),
129       source_url(),
130       task,
131       file_urls,
132       base::Bind(&FileBrowserPrivateExecuteTaskFunction::OnTaskExecuted, this));
133   if (!result) {
134     results_ =
135         Create(extensions::api::file_browser_private::TASK_RESULT_FAILED);
136   }
137   return result;
138 }
139
140 void FileBrowserPrivateExecuteTaskFunction::OnTaskExecuted(
141     extensions::api::file_browser_private::TaskResult result) {
142   results_ =
143       extensions::api::file_browser_private::ExecuteTask::Results::Create(
144           result);
145   SendResponse(result !=
146                extensions::api::file_browser_private::TASK_RESULT_FAILED);
147 }
148
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);
153
154   if (params->file_urls.empty())
155     return false;
156
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)
160     return false;
161
162   const scoped_refptr<fileapi::FileSystemContext> file_system_context =
163       file_manager::util::GetFileSystemContextForRenderViewHost(
164           GetProfile(), render_view_host());
165
166   // Collect all the URLs, convert them to GURLs, and crack all the urls into
167   // file paths.
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];
174
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))
179       continue;
180     const base::FilePath file_path = file_system_url.path();
181
182     file_urls->push_back(file_url);
183
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);
187
188     path_mime_set->insert(std::make_pair(file_path, mime_type));
189   }
190
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();
195
196   BrowserThread::PostBlockingPoolTaskAndReply(
197       FROM_HERE,
198       base::Bind(&SniffMimeType, path_mime_set_ptr, file_urls_ptr),
199       base::Bind(
200           &FileBrowserPrivateGetFileTasksFunction::OnSniffingMimeTypeCompleted,
201           this,
202           base::Passed(&path_mime_set),
203           base::Passed(&file_urls)));
204   return true;
205 }
206
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(
212       GetProfile(),
213       drive::util::GetDriveAppRegistryByProfile(GetProfile()),
214       *path_mime_set,
215       *file_urls,
216       &tasks);
217
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);
231   }
232   results_ = extensions::api::file_browser_private::GetFileTasks::Results::
233       Create(results);
234   SendResponse(true);
235 }
236
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);
241
242   const scoped_refptr<fileapi::FileSystemContext> file_system_context =
243       file_manager::util::GetFileSystemContextForRenderViewHost(
244           GetProfile(), render_view_host());
245
246   const std::set<std::string> suffixes =
247       GetUniqueSuffixes(params->file_urls, file_system_context.get());
248
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())
253       return false;
254     mime_types = GetUniqueMimeTypes(*params->mime_types);
255   }
256
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));
265     return true;
266   }
267
268   file_manager::file_tasks::UpdateDefaultTask(
269       GetProfile()->GetPrefs(), params->task_id, suffixes, mime_types);
270   return true;
271 }
272
273 }  // namespace extensions