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

Side by Side Diff: chrome/browser/extensions/extension_file_browser_private_api.cc

Issue 6749021: Added new fileBrowserPrivate and fileHandler extension APIs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 8 months 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/extensions/extension_file_browser_private_api.h" 5 #include "chrome/browser/extensions/extension_file_browser_private_api.h"
6 6
7 #include "base/base64.h"
8 #include "base/command_line.h"
7 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
8 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/singleton.h"
12 #include "base/stringprintf.h"
13 #include "base/string_util.h"
9 #include "base/task.h" 14 #include "base/task.h"
10 #include "base/values.h" 15 #include "base/values.h"
11 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/extensions/extension_event_router.h"
18 #include "chrome/browser/extensions/extension_function_dispatcher.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/ui/webui/extension_icon_source.h"
21 #include "chrome/common/chrome_switches.h"
12 #include "chrome/common/extensions/extension.h" 22 #include "chrome/common/extensions/extension.h"
23 #include "chrome/common/extensions/file_browser_action.h"
13 #include "content/browser/browser_thread.h" 24 #include "content/browser/browser_thread.h"
25 #include "content/browser/child_process_security_policy.h"
26 #include "content/browser/renderer_host/render_process_host.h"
27 #include "content/browser/renderer_host/render_view_host.h"
14 #include "content/browser/tab_contents/tab_contents.h" 28 #include "content/browser/tab_contents/tab_contents.h"
15 #include "grit/generated_resources.h" 29 #include "grit/generated_resources.h"
16 #include "webkit/fileapi/file_system_context.h" 30 #include "webkit/fileapi/file_system_context.h"
31 #include "webkit/fileapi/file_system_mount_point_provider.h"
17 #include "webkit/fileapi/file_system_operation.h" 32 #include "webkit/fileapi/file_system_operation.h"
18 #include "webkit/fileapi/file_system_path_manager.h" 33 #include "webkit/fileapi/file_system_path_manager.h"
19 #include "webkit/fileapi/file_system_types.h" 34 #include "webkit/fileapi/file_system_types.h"
35 #include "webkit/fileapi/file_system_util.h"
20 #include "ui/base/l10n/l10n_util.h" 36 #include "ui/base/l10n/l10n_util.h"
21 37
38 // Error messages.
39 const char kFileError[] = "File error %d";
40 const char kInvalidFileUrl[] = "Invalid file URL";
41
42 const int kReadOnlyFilePermissions = base::PLATFORM_FILE_OPEN |
43 base::PLATFORM_FILE_READ |
44 base::PLATFORM_FILE_EXCLUSIVE_READ |
45 base::PLATFORM_FILE_ASYNC;
46
47 const int kReadWriteFilePermissions = base::PLATFORM_FILE_OPEN |
48 base::PLATFORM_FILE_CREATE |
49 base::PLATFORM_FILE_OPEN_ALWAYS |
50 base::PLATFORM_FILE_CREATE_ALWAYS |
51 base::PLATFORM_FILE_READ |
52 base::PLATFORM_FILE_WRITE |
53 base::PLATFORM_FILE_EXCLUSIVE_READ |
54 base::PLATFORM_FILE_EXCLUSIVE_WRITE |
55 base::PLATFORM_FILE_ASYNC |
56 base::PLATFORM_FILE_TRUNCATE |
57 base::PLATFORM_FILE_WRITE_ATTRIBUTES;
58
59 typedef std::vector<
60 std::pair<std::string, const FileBrowserAction* > >
61 NamedActionList;
62
63 typedef std::vector<const FileBrowserAction*> ActionList;
64
65 bool GetFileBrowserActions(Profile* profile,
66 const GURL& selected_file_url,
67 ActionList* results) {
68 ExtensionService* service = profile->GetExtensionService();
69 if (!service)
70 return false; // In unit-tests, we may not have an ExtensionService.
71
72 for (ExtensionList::const_iterator iter = service->extensions()->begin();
73 iter != service->extensions()->end();
74 ++iter) {
75 const Extension* extension = iter->get();
76 if (!extension->file_browser_actions())
77 continue;
78
79 for (Extension::FileBrowserActionList::const_iterator action_iter =
80 extension->file_browser_actions()->begin();
81 action_iter != extension->file_browser_actions()->end();
82 ++action_iter) {
83 const FileBrowserAction* action = action_iter->get();
84 if (!action->MatchesURL(selected_file_url))
85 continue;
86
87 results->push_back(action_iter->get());
88 }
89 }
90 return true;
91 }
92
93 // Given the list of selected files, returns array of context menu tasks
94 // that are shared
95 bool FindCommonTasks(Profile* profile,
96 ListValue* files_list,
97 NamedActionList* named_action_list) {
98 named_action_list->clear();
99 ActionList common_tasks;
100 for (size_t i = 0; i < files_list->GetSize(); ++i) {
101 std::string file_url;
102 if (!files_list->GetString(i, &file_url))
103 return false;
104
105 ActionList file_actions;
106 if (!GetFileBrowserActions(profile, GURL(file_url), &file_actions))
107 return false;
108 // If there is nothing to do for one file, the intersection of tasks for all
109 // files will be empty at the end.
110 if (!file_actions.size()) {
111 common_tasks.clear();
112 return true;
113 }
114 // For the very first file, just copy elements.
115 if (i == 0) {
116 common_tasks.insert(common_tasks.begin(),
117 file_actions.begin(),
118 file_actions.end());
119 std::sort(common_tasks.begin(), common_tasks.end());
120 } else if (common_tasks.size()) {
121 // For all additional files, find intersection between the accumulated
122 // and file specific set.
123 std::sort(file_actions.begin(), file_actions.end());
124 ActionList intersection(common_tasks.size());
125 ActionList::iterator intersection_end =
126 std::set_intersection(common_tasks.begin(),
127 common_tasks.end(),
128 file_actions.begin(),
129 file_actions.end(),
130 intersection.begin());
131 common_tasks.clear();
132 common_tasks.insert(common_tasks.begin(),
133 intersection.begin(),
134 intersection_end);
135 std::sort(common_tasks.begin(), common_tasks.end());
136 }
137 }
138
139 // At the end, sort the results by task title.
140 // TODO(zelidrag): Wire this with ICU to make this sort I18N happy.
141 for (ActionList::const_iterator iter = common_tasks.begin();
142 iter != common_tasks.end(); ++iter) {
143 named_action_list->push_back(
144 std::pair<std::string, const FileBrowserAction* >(
145 (*iter)->title(), *iter));
146 }
147 std::sort(named_action_list->begin(), named_action_list->end());
148 return true;
149 }
150
151 // Breaks down task_id that is used between getFileTasks() and executeTask() on
152 // its building blocks. task_id field the following structure:
153 // <task-type>:<extension-id>/<task-action-id>
154 // Currently, the only supported task-type is of 'context'.
155 bool CrackTaskIdentifier(const std::string& task_id,
156 std::string* target_extension_id,
157 std::string* action_id) {
158 std::vector<std::string> result;
159 int count = Tokenize(task_id, std::string("|"), &result);
160 if (count != 2)
161 return false;
162 *target_extension_id = result[0];
163 *action_id = result[1];
164 return true;
165 }
166
167 std::string MakeTaskID(const char* extension_id,
168 const char* action_id) {
169 return base::StringPrintf("%s|%s", extension_id, action_id);
170 }
22 171
23 class LocalFileSystemCallbackDispatcher 172 class LocalFileSystemCallbackDispatcher
24 : public fileapi::FileSystemCallbackDispatcher { 173 : public fileapi::FileSystemCallbackDispatcher {
25 public: 174 public:
26 explicit LocalFileSystemCallbackDispatcher( 175 explicit LocalFileSystemCallbackDispatcher(
27 RequestLocalFileSystemFunction* function) : function_(function) { 176 RequestLocalFileSystemFunction* function,
177 Profile* profile,
178 int child_id,
179 scoped_refptr<const Extension> extension)
180 : function_(function),
181 profile_(profile),
182 child_id_(child_id),
183 extension_(extension) {
28 DCHECK(function_); 184 DCHECK(function_);
29 } 185 }
186
30 // fileapi::FileSystemCallbackDispatcher overrides. 187 // fileapi::FileSystemCallbackDispatcher overrides.
31 virtual void DidSucceed() OVERRIDE { 188 virtual void DidSucceed() OVERRIDE {
32 NOTREACHED(); 189 NOTREACHED();
33 } 190 }
191
34 virtual void DidReadMetadata(const base::PlatformFileInfo& info, 192 virtual void DidReadMetadata(const base::PlatformFileInfo& info,
35 const FilePath& unused) OVERRIDE { 193 const FilePath& unused) OVERRIDE {
36 NOTREACHED(); 194 NOTREACHED();
37 } 195 }
196
38 virtual void DidReadDirectory( 197 virtual void DidReadDirectory(
39 const std::vector<base::FileUtilProxy::Entry>& entries, 198 const std::vector<base::FileUtilProxy::Entry>& entries,
40 bool has_more) OVERRIDE { 199 bool has_more) OVERRIDE {
41 NOTREACHED(); 200 NOTREACHED();
42 } 201 }
202
43 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE { 203 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE {
44 NOTREACHED(); 204 NOTREACHED();
45 } 205 }
206
46 virtual void DidOpenFileSystem(const std::string& name, 207 virtual void DidOpenFileSystem(const std::string& name,
47 const FilePath& path) OVERRIDE { 208 const FilePath& root_path) OVERRIDE {
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
210 // Set up file permission access.
211 if (!SetupFileSystemAccessPermissions()) {
212 DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
213 return;
214 }
215
48 BrowserThread::PostTask( 216 BrowserThread::PostTask(
49 BrowserThread::UI, FROM_HERE, 217 BrowserThread::UI, FROM_HERE,
50 NewRunnableMethod(function_, 218 NewRunnableMethod(function_,
51 &RequestLocalFileSystemFunction::RespondSuccessOnUIThread, 219 &RequestLocalFileSystemFunction::RespondSuccessOnUIThread,
52 name, 220 name,
53 path)); 221 root_path));
54 } 222 }
223
55 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE { 224 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE {
56 BrowserThread::PostTask( 225 BrowserThread::PostTask(
57 BrowserThread::UI, FROM_HERE, 226 BrowserThread::UI, FROM_HERE,
58 NewRunnableMethod(function_, 227 NewRunnableMethod(function_,
59 &RequestLocalFileSystemFunction::RespondFailedOnUIThread, 228 &RequestLocalFileSystemFunction::RespondFailedOnUIThread,
60 error_code)); 229 error_code));
61 } 230 }
231
62 private: 232 private:
233
234 // Grants file system access permissions to file browser component.
235 bool SetupFileSystemAccessPermissions() {
236 if (!extension_.get())
237 return false;
238
239 // Make sure that only component extension can access the entire
240 // local file system.
241 if (extension_->location() != Extension::COMPONENT
242 #ifndef NDEBUG
243 && !CommandLine::ForCurrentProcess()->HasSwitch(
244 switches::kExposePrivateExtensionApi)
245 #endif
246 ) {
247 NOTREACHED() << "Private method access by non-component extension "
248 << extension_->id();
249 return false;
250 }
251
252 fileapi::FileSystemPathManager* path_manager =
253 profile_->GetFileSystemContext()->path_manager();
254 fileapi::FileSystemMountPointProvider* provider =
255 path_manager->local_provider();
256 if (!provider)
257 return false;
258
259 // Grant R/W file permissions to the renderer hosting component
260 // extension for all paths exposed by our local file system provider.
261 std::vector<FilePath> root_dirs = provider->GetRootDirectories();
262 for (std::vector<FilePath>::iterator iter = root_dirs.begin();
263 iter != root_dirs.end();
264 ++iter) {
265 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
266 child_id_, *iter, kReadWriteFilePermissions);
267 }
268 return true;
269 }
270
63 RequestLocalFileSystemFunction* function_; 271 RequestLocalFileSystemFunction* function_;
272 Profile* profile_;
273 // Renderer process id.
274 int child_id_;
275 // Extension source URL.
276 scoped_refptr<const Extension> extension_;
64 DISALLOW_COPY_AND_ASSIGN(LocalFileSystemCallbackDispatcher); 277 DISALLOW_COPY_AND_ASSIGN(LocalFileSystemCallbackDispatcher);
65 }; 278 };
66 279
67 RequestLocalFileSystemFunction::RequestLocalFileSystemFunction() { 280 void RequestLocalFileSystemFunction::RequestOnFileThread(
68 } 281 const GURL& source_url) {
69 282 fileapi::FileSystemOperation* operation =
70 RequestLocalFileSystemFunction::~RequestLocalFileSystemFunction() { 283 new fileapi::FileSystemOperation(
284 new LocalFileSystemCallbackDispatcher(
285 this,
286 profile(),
287 dispatcher()->render_view_host()->process()->id(),
288 GetExtension()),
289 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
290 profile()->GetFileSystemContext(),
291 NULL);
292 GURL origin_url = source_url.GetOrigin();
293 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeLocal,
294 false); // create
71 } 295 }
72 296
73 bool RequestLocalFileSystemFunction::RunImpl() { 297 bool RequestLocalFileSystemFunction::RunImpl() {
74 fileapi::FileSystemOperation* operation = 298 BrowserThread::PostTask(
75 new fileapi::FileSystemOperation( 299 BrowserThread::FILE, FROM_HERE,
76 new LocalFileSystemCallbackDispatcher(this), 300 NewRunnableMethod(this,
77 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 301 &RequestLocalFileSystemFunction::RequestOnFileThread,
78 profile()->GetFileSystemContext(), 302 source_url_));
79 NULL);
80 GURL origin_url = source_url().GetOrigin();
81 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeLocal,
82 false); // create
83 // Will finish asynchronously. 303 // Will finish asynchronously.
84 return true; 304 return true;
85 } 305 }
86 306
87 void RequestLocalFileSystemFunction::RespondSuccessOnUIThread( 307 void RequestLocalFileSystemFunction::RespondSuccessOnUIThread(
88 const std::string& name, const FilePath& path) { 308 const std::string& name, const FilePath& root_path) {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90 result_.reset(new DictionaryValue()); 310 result_.reset(new DictionaryValue());
91 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get()); 311 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get());
92 dict->SetString("name", name); 312 dict->SetString("name", name);
93 dict->SetString("path", path.value()); 313 dict->SetString("path", root_path.value());
94 dict->SetInteger("error", base::PLATFORM_FILE_OK); 314 dict->SetInteger("error", base::PLATFORM_FILE_OK);
95 SendResponse(true); 315 SendResponse(true);
96 } 316 }
97 317
98 void RequestLocalFileSystemFunction::RespondFailedOnUIThread( 318 void RequestLocalFileSystemFunction::RespondFailedOnUIThread(
99 base::PlatformFileError error_code) { 319 base::PlatformFileError error_code) {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101 result_.reset(new DictionaryValue()); 321 error_ = base::StringPrintf(kFileError, static_cast<int>(error_code));
102 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get()); 322 SendResponse(false);
103 dict->SetInteger("error", static_cast<int>(error_code)); 323 }
324
325 bool GetFileTasksFileBrowserFunction::RunImpl() {
326 ListValue* files_list = NULL;
327 if (!args_->GetList(0, &files_list))
328 return false;
329
330 ListValue* result_list = new ListValue();
331 result_.reset(result_list);
332
333 NamedActionList common_tasks;
334 if (!FindCommonTasks(profile_, files_list, &common_tasks))
335 return false;
336
337 ExtensionService* service = profile_->GetExtensionService();
338 for (NamedActionList::iterator iter = common_tasks.begin();
339 iter != common_tasks.end();
340 ++iter) {
341 const std::string extension_id = iter->second->extension_id();
342 const Extension* extension = service->GetExtensionById(extension_id, false);
343 CHECK(extension);
344 DictionaryValue* task = new DictionaryValue();
345 task->SetString("taskId", MakeTaskID(extension_id.data(),
346 iter->second->id().data()));
347 task->SetString("title", iter->second->title());
348 // TODO(zelidrag): Figure out how to expose icon URL that task defined in
349 // manifest instead of the default extension icon.
350 GURL icon =
351 ExtensionIconSource::GetIconURL(extension,
352 Extension::EXTENSION_ICON_SMALLISH,
353 ExtensionIconSet::MATCH_BIGGER,
354 false); // grayscale
355 task->SetString("iconUrl", icon.spec());
356 result_list->Append(task);
357 }
358
359 // TODO(zelidrag, serya): Add intent content tasks to result_list once we
360 // implement that API.
104 SendResponse(true); 361 SendResponse(true);
362 return true;
363 }
364
365 class ExecuteTasksFileSystemCallbackDispatcher
366 : public fileapi::FileSystemCallbackDispatcher {
367 public:
368 explicit ExecuteTasksFileSystemCallbackDispatcher(
369 ExecuteTasksFileBrowserFunction* function,
370 Profile* profile,
371 int child_id,
372 const GURL& source_url,
373 scoped_refptr<const Extension> extension,
374 const std::string task_id,
375 const std::vector<FilePath>& origin_file_paths)
376 : function_(function),
377 profile_(profile),
378 child_id_(child_id),
379 source_url_(source_url),
380 extension_(extension),
381 task_id_(task_id),
382 origin_file_paths_(origin_file_paths) {
383 DCHECK(function_);
384 }
385
386 // fileapi::FileSystemCallbackDispatcher overrides.
387 virtual void DidSucceed() OVERRIDE {
388 NOTREACHED();
389 }
390
391 virtual void DidReadMetadata(const base::PlatformFileInfo& info,
392 const FilePath& unused) OVERRIDE {
393 NOTREACHED();
394 }
395
396 virtual void DidReadDirectory(
397 const std::vector<base::FileUtilProxy::Entry>& entries,
398 bool has_more) OVERRIDE {
399 NOTREACHED();
400 }
401
402 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE {
403 NOTREACHED();
404 }
405
406 virtual void DidOpenFileSystem(const std::string& file_system_name,
407 const FilePath& file_system_root) OVERRIDE {
408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
409 ExecuteTasksFileBrowserFunction::FileDefinitionList file_list;
410 for (std::vector<FilePath>::iterator iter = origin_file_paths_.begin();
411 iter != origin_file_paths_.end();
412 ++iter) {
413 // Set up file permission access.
414 ExecuteTasksFileBrowserFunction::FileDefinition file;
415 if (!SetupFileAccessPermissions(*iter, &file.target_file_url,
416 &file.virtual_path, &file.is_directory)) {
417 continue;
418 }
419 file_list.push_back(file);
420 }
421 if (file_list.empty())
422 return;
423
424 BrowserThread::PostTask(
425 BrowserThread::UI, FROM_HERE,
426 NewRunnableMethod(function_,
427 &ExecuteTasksFileBrowserFunction::ExecuteFileActionsOnUIThread,
428 task_id_,
429 file_system_name,
430 file_system_root,
431 file_list));
432 }
433
434 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE {
435 LOG(WARNING) << "Local file system cant be resolved";
436 }
437
438 private:
439 // Checks legitimacy of file url and grants file RO access permissions from
440 // handler (target) extension and its renderer process.
441 bool SetupFileAccessPermissions(const FilePath& origin_file_path,
442 GURL* target_file_url, FilePath* file_path, bool* is_directory) {
443
444 if (!extension_.get())
445 return false;
446
447 GURL file_origin_url;
448 FilePath virtual_path;
449 fileapi::FileSystemType type;
450 fileapi::FileSystemPathManager* path_manager =
451 profile_->GetFileSystemContext()->path_manager();
452 if (!path_manager->CrackFileSystemPath(origin_file_path, &file_origin_url,
453 &type, &virtual_path)) {
454 return false;
455 }
456
457 if (type != fileapi::kFileSystemTypeLocal)
458 return false;
459
460 // Make sure this url really being used by the right caller extension.
461 if (source_url_.GetOrigin() != file_origin_url) {
462 DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
463 return false;
464 }
465
466 FilePath root_path = path_manager->GetFileSystemRootPathOnFileThread(
467 file_origin_url,
468 fileapi::kFileSystemTypeLocal,
469 virtual_path,
470 false); // create
471 FilePath finalFilePath = root_path.Append(virtual_path);
472
473 // TODO(zelidrag): Add explicit R/W + R/O permissions for non-component
474 // extensions.
475
476 // Grant R/O access permission to non-component extension and R/W to
477 // component extensions.
478 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
479 child_id_, finalFilePath,
480 extension_->location() != Extension::COMPONENT ?
481 kReadOnlyFilePermissions : kReadWriteFilePermissions);
482
483 // Get task details.
484 std::string target_extension_id;
485 std::string action_id;
486 if (!CrackTaskIdentifier(task_id_, &target_extension_id,
487 &action_id)) {
488 return false;
489 }
490
491 // Grant access to this particular file to target extension. This will
492 // ensure that the target extension can access only this FS entry and
493 // prevent from traversing FS hierarchy upward.
494 GURL target_origin_url(Extension::GetBaseURLFromExtensionId(
495 target_extension_id));
496 fileapi::FileSystemMountPointProvider* local_provider =
497 path_manager->local_provider();
498 if (!local_provider)
499 return false;
500 local_provider->GrantAccess(target_origin_url, virtual_path);
501
502 // Output values.
503 GURL base_url = fileapi::GetFileSystemRootURI(target_origin_url,
504 fileapi::kFileSystemTypeLocal);
505 *target_file_url = GURL(base_url.spec() + virtual_path.value());
506 *file_path = virtual_path;
507 // TODO(zelidrag): Prevent directory passing for now, add support for it
508 // later.
509 is_directory = false;
510 return true;
511 }
512
513 ExecuteTasksFileBrowserFunction* function_;
514 Profile* profile_;
515 // Renderer process id.
516 int child_id_;
517 // Extension source URL.
518 GURL source_url_;
519 scoped_refptr<const Extension> extension_;
520 std::string task_id_;
521 std::vector<FilePath> origin_file_paths_;
522 DISALLOW_COPY_AND_ASSIGN(ExecuteTasksFileSystemCallbackDispatcher);
523 };
524
525 bool ExecuteTasksFileBrowserFunction::RunImpl() {
526 // First param is task id that was to the extension with getFileTasks call.
527 std::string task_id;
528 if (!args_->GetString(0, &task_id) || !task_id.size())
529 return false;
530
531 // The second param is the list of files that need to be executed with this
532 // task.
533 ListValue* files_list = NULL;
534 if (!args_->GetList(1, &files_list))
535 return false;
536
537 if (!files_list->GetSize())
538 return true;
539
540 InitiateFileTaskExecution(task_id, files_list);
541 SendResponse(true);
542 return true;
543 }
544
545 bool ExecuteTasksFileBrowserFunction::InitiateFileTaskExecution(
546 const std::string& task_id, ListValue* files_list) {
547 std::vector<FilePath> file_paths;
548 for (size_t i = 0; i < files_list->GetSize(); i++) {
549 std::string origin_file_url;
550 if (!files_list->GetString(i, &origin_file_url)) {
551 error_ = kInvalidFileUrl;
552 SendResponse(false);
553 return false;
554 }
555 file_paths.push_back(FilePath(origin_file_url));
556 }
557 // Get local file system instance on file thread.
558 BrowserThread::PostTask(
559 BrowserThread::FILE, FROM_HERE,
560 NewRunnableMethod(this,
561 &ExecuteTasksFileBrowserFunction::RequestFileEntryOnFileThread,
562 source_url_,
563 task_id,
564 file_paths));
565 result_.reset(new FundamentalValue(true));
566 return true;
567 }
568
569 void ExecuteTasksFileBrowserFunction::RequestFileEntryOnFileThread(
570 const GURL& source_url, const std::string& task_id,
571 const std::vector<FilePath>& file_urls) {
572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
573 fileapi::FileSystemOperation* operation =
574 new fileapi::FileSystemOperation(
575 new ExecuteTasksFileSystemCallbackDispatcher(
576 this,
577 profile(),
578 dispatcher()->render_view_host()->process()->id(),
579 source_url,
580 GetExtension(),
581 task_id,
582 file_urls),
583 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
584 profile()->GetFileSystemContext(),
585 NULL);
586 GURL origin_url = source_url.GetOrigin();
587 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeLocal,
588 false); // create
589 }
590
591 void ExecuteTasksFileBrowserFunction::ExecuteFileActionsOnUIThread(
592 const std::string& task_id,
593 const std::string& file_system_name,
594 const FilePath& file_system_root,
595 const FileDefinitionList& file_list) {
596 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
597 ExtensionService* service = profile_->GetExtensionService();
598 if (!service)
599 return;
600 // Get task details.
601 std::string handler_extension_id;
602 std::string action_id;
603 if (!CrackTaskIdentifier(task_id, &handler_extension_id,
604 &action_id)) {
605 LOG(WARNING) << "Invalid task " << task_id;
606 return;
607 }
608
609 const Extension* extension = service->GetExtensionById(handler_extension_id,
610 false);
611 if (!extension)
612 return;
613
614 ExtensionEventRouter* event_router = profile_->GetExtensionEventRouter();
615 if (!event_router)
616 return;
617
618 scoped_ptr<ListValue> event_args(new ListValue());
619 ListValue* files_urls = new ListValue();
620 event_args->Append(Value::CreateStringValue(action_id));
621 event_args->Append(files_urls);
622 for (FileDefinitionList::const_iterator iter = file_list.begin();
623 iter != file_list.end();
624 ++iter) {
625 DictionaryValue* file_def = new DictionaryValue();
626 files_urls->Append(file_def);
627 file_def->SetString("fileSystemName", file_system_name);
628 file_def->SetString("fileSystemRoot", file_system_root.value());
629 file_def->SetString("fileFullPath", iter->virtual_path.value());
630 file_def->SetBoolean("fileIsDirectory", iter->is_directory);
631 }
632 std::string json_args;
633 base::JSONWriter::Write(event_args.get(), false, &json_args);
634 std::string event_name = "contextMenus";
635 event_router->DispatchEventToExtension(
636 handler_extension_id, std::string("fileBrowserHandler.onExecuteAction"),
637 json_args, profile_,
638 GURL());
105 } 639 }
106 640
107 FileDialogFunction::FileDialogFunction() { 641 FileDialogFunction::FileDialogFunction() {
108 } 642 }
109 643
110 FileDialogFunction::~FileDialogFunction() { 644 FileDialogFunction::~FileDialogFunction() {
111 } 645 }
112 646
113 // static 647 // static
114 FileDialogFunction::ListenerMap FileDialogFunction::listener_map_; 648 FileDialogFunction::ListenerMap FileDialogFunction::listener_map_;
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 SET_STRING(IDS_FILE_BROWSER, COMPUTING_SELECTION); 823 SET_STRING(IDS_FILE_BROWSER, COMPUTING_SELECTION);
290 SET_STRING(IDS_FILE_BROWSER, NOTHING_SELECTED); 824 SET_STRING(IDS_FILE_BROWSER, NOTHING_SELECTED);
291 SET_STRING(IDS_FILE_BROWSER, ONE_FILE_SELECTED); 825 SET_STRING(IDS_FILE_BROWSER, ONE_FILE_SELECTED);
292 SET_STRING(IDS_FILE_BROWSER, MANY_FILES_SELECTED); 826 SET_STRING(IDS_FILE_BROWSER, MANY_FILES_SELECTED);
293 827
294 #undef SET_STRING 828 #undef SET_STRING
295 829
296 SendResponse(true); 830 SendResponse(true);
297 return true; 831 return true;
298 } 832 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698