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

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

Powered by Google App Engine
This is Rietveld 408576698