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

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

Powered by Google App Engine
This is Rietveld 408576698