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

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"
9 #include "base/task.h" 13 #include "base/task.h"
10 #include "base/values.h" 14 #include "base/values.h"
11 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/extensions/extension_function_dispatcher.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/tab_contents/context_menu_utils.h"
19 #include "chrome/browser/ui/webui/extension_icon_source.h"
20 #include "chrome/common/chrome_switches.h"
12 #include "chrome/common/extensions/extension.h" 21 #include "chrome/common/extensions/extension.h"
13 #include "content/browser/browser_thread.h" 22 #include "content/browser/browser_thread.h"
23 #include "content/browser/child_process_security_policy.h"
24 #include "content/browser/renderer_host/render_process_host.h"
25 #include "content/browser/renderer_host/render_view_host.h"
26 #include "content/browser/tab_contents/tab_contents.h"
27 #include "webkit/fileapi/file_system_context.h"
28 #include "webkit/fileapi/file_system_mount_point_provider.h"
14 #include "content/browser/tab_contents/tab_contents.h" 29 #include "content/browser/tab_contents/tab_contents.h"
15 #include "grit/generated_resources.h" 30 #include "grit/generated_resources.h"
16 #include "webkit/fileapi/file_system_context.h" 31 #include "webkit/fileapi/file_system_context.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"
36 #include "webkit/glue/context_menu.h"
20 #include "ui/base/l10n/l10n_util.h" 37 #include "ui/base/l10n/l10n_util.h"
21 38
39 const char kContextTaskIdSchema[] = "context-task";
40
41 // Error messages.
42 const char kFileError[] = "File error %d";
43 const char kInvalidFileUrl[] = "Invalid file URL";
44
45 const int kReadOnlyFilePermissions = base::PLATFORM_FILE_OPEN |
46 base::PLATFORM_FILE_READ |
47 base::PLATFORM_FILE_EXCLUSIVE_READ |
48 base::PLATFORM_FILE_ASYNC;
49
50 const int kReadWriteFilePermissions = base::PLATFORM_FILE_OPEN |
51 base::PLATFORM_FILE_CREATE |
52 base::PLATFORM_FILE_OPEN_ALWAYS |
53 base::PLATFORM_FILE_CREATE_ALWAYS |
54 base::PLATFORM_FILE_READ |
55 base::PLATFORM_FILE_WRITE |
56 base::PLATFORM_FILE_EXCLUSIVE_READ |
57 base::PLATFORM_FILE_EXCLUSIVE_WRITE |
58 base::PLATFORM_FILE_ASYNC |
59 base::PLATFORM_FILE_TRUNCATE |
60 base::PLATFORM_FILE_WRITE_ATTRIBUTES;
61
62 bool GetContextMenuItems(Profile* profile,
63 const ContextMenuParams& params,
64 ExtensionMenuItem::List* results) {
65 ExtensionService* service = profile->GetExtensionService();
66 if (!service)
67 return false; // In unit-tests, we may not have an ExtensionService.
68
69 // Get a list of extension id's that have context menu items, and sort it by
70 // the extension's name.
asargent_no_longer_on_chrome 2011/04/08 18:52:33 I seem to remember we do something just like this
zel 2011/04/08 19:35:01 Done.
71 ExtensionMenuManager* menu_manager = service->menu_manager();
72 std::set<std::string> ids = menu_manager->ExtensionIds();
73 std::vector<std::pair<std::string, std::string> > sorted_ids;
74 for (std::set<std::string>::iterator i = ids.begin(); i != ids.end(); ++i) {
75 const Extension* extension = service->GetExtensionById(*i, false);
76 if (extension)
77 sorted_ids.push_back(
78 std::pair<std::string, std::string>(extension->name(), *i));
79 }
80
81 if (sorted_ids.empty())
82 return true;
83
asargent_no_longer_on_chrome 2011/04/08 18:52:33 It looks like you don't ever actually do any sorti
zel 2011/04/08 19:35:01 Done.
84 std::vector<std::pair<std::string, std::string> >::const_iterator i;
85 for (i = sorted_ids.begin(); i != sorted_ids.end(); ++i) {
86 const std::string& extension_id = i->second;
87 const Extension* extension = service->GetExtensionById(extension_id, false);
88 bool can_cross_incognito = service->CanCrossIncognito(extension);
89 const ExtensionMenuItem::List* all_items =
90 menu_manager->MenuItems(extension_id);
91 ExtensionMenuItem::List relevant_items =
92 ContextMenuUtils::GetRelevantExtensionItems(*all_items,
93 params,
94 profile,
95 can_cross_incognito);
96 results->insert(results->end(), relevant_items.begin(),
97 relevant_items.end());
98 }
99 return true;
100 }
101
102 void CreateContextMenuParams(const GURL& source_url,
103 const std::string& file_url,
104 ContextMenuParams* params) {
105 DCHECK(params);
106 params->is_image_blocked = false;
107 params->spellcheck_enabled = false;
108 params->is_editable = false;
109 params->media_flags = 0;
110 params->edit_flags = 0;
111 params->media_type = WebKit::WebContextMenuData::MediaTypeFile;
112 params->src_url = GURL(file_url);
113 params->page_url = source_url;
114 }
115
116 // Given the list of selected files, returns array of context menu tasks
117 // that are sahred
asargent_no_longer_on_chrome 2011/04/08 18:52:33 typo "sahred"
zel 2011/04/08 19:35:01 Done.
118 bool FindCommonTasks(Profile* profile,
119 const GURL& source_url,
120 ListValue* files_list,
121 ExtensionMenuItem::List* common_tasks) {
122 common_tasks->clear();
123 for (size_t i = 0; i < files_list->GetSize(); ++i) {
124 std::string file_url;
125 if (!files_list->GetString(i, &file_url))
126 return false;
127
128 ContextMenuParams params;
129 CreateContextMenuParams(source_url, file_url, &params);
130
131 ExtensionMenuItem::List file_actions;
132 if (!GetContextMenuItems(profile, params, &file_actions))
133 return false;
134 // If there is nothing to do for one file, the intersection of tasks for all
135 // files will be empty at the end.
136 if (!file_actions.size()) {
137 common_tasks->clear();
138 return true;
139 }
140 // For the very first file, just copy elements.
141 if (i == 0) {
142 common_tasks->insert(common_tasks->begin(),
143 file_actions.begin(),
144 file_actions.end());
145 std::sort(common_tasks->begin(), common_tasks->end());
146 } else if (common_tasks->size()) {
147 // For all additional files, find intersection between the accumulated
148 // and file specific set.
149 std::sort(file_actions.begin(), file_actions.end());
150 ExtensionMenuItem::List intersection(common_tasks->size());
151 ExtensionMenuItem::List::iterator intersection_end =
152 std::set_intersection(common_tasks->begin(),
153 common_tasks->end(),
154 file_actions.begin(),
155 file_actions.end(),
156 intersection.begin());
157 common_tasks->clear();
158 common_tasks->insert(common_tasks->begin(),
159 intersection.begin(),
160 intersection_end);
161 std::sort(common_tasks->begin(), common_tasks->end());
162 }
163 }
164 return true;
165 }
166
167 // Breaks down task_id that is used between getFileTasks() and executeTask() on
168 // its building blocks. task_id field the following structure:
169 // <task-type>:<extension-id>/<task-action-id>
170 // Currently, the only supported task-type is of 'context'.
171 bool CrackTaskIdentifier(const std::string& task_id,
172 std::string* task_type,
173 std::string* target_extension_id,
174 std::string* action_id) {
175 std::string::size_type pos_col = task_id.find(':');
176 if (pos_col == std::string::npos)
177 return false;
178 *task_type = task_id.substr(0, pos_col);
179 std::string::size_type pos_slash = task_id.find('/');
180 if (pos_slash == std::string::npos)
181 return false;
182 *target_extension_id = task_id.substr(pos_col + 1, pos_slash - pos_col - 1);
183 *action_id = task_id.substr(pos_slash + 1);
asargent_no_longer_on_chrome 2011/04/08 18:52:33 This might be made clearer with a little use of To
zel 2011/04/08 19:35:01 Done.
184 return true;
185 }
186
187 std::string MakeTaskID(const char* task_schema,
188 const char* extension_id,
189 int action_id) {
190 return base::StringPrintf("%s:%s/%d", task_schema, extension_id, action_id);
191 }
22 192
23 class LocalFileSystemCallbackDispatcher 193 class LocalFileSystemCallbackDispatcher
24 : public fileapi::FileSystemCallbackDispatcher { 194 : public fileapi::FileSystemCallbackDispatcher {
25 public: 195 public:
26 explicit LocalFileSystemCallbackDispatcher( 196 explicit LocalFileSystemCallbackDispatcher(
27 RequestLocalFileSystemFunction* function) : function_(function) { 197 RequestLocalFileSystemFunctionBase* function,
198 Profile* profile,
199 int child_id,
200 const GURL& source_url,
201 const GURL& file_url)
202 : function_(function),
203 profile_(profile),
204 child_id_(child_id),
205 source_url_(source_url),
206 file_url_(file_url) {
28 DCHECK(function_); 207 DCHECK(function_);
29 } 208 }
30 // fileapi::FileSystemCallbackDispatcher overrides. 209 // fileapi::FileSystemCallbackDispatcher overrides.
31 virtual void DidSucceed() OVERRIDE { 210 virtual void DidSucceed() OVERRIDE {
32 NOTREACHED(); 211 NOTREACHED();
33 } 212 }
34 virtual void DidReadMetadata(const base::PlatformFileInfo& info, 213 virtual void DidReadMetadata(const base::PlatformFileInfo& info,
35 const FilePath& unused) OVERRIDE { 214 const FilePath& unused) OVERRIDE {
36 NOTREACHED(); 215 NOTREACHED();
37 } 216 }
38 virtual void DidReadDirectory( 217 virtual void DidReadDirectory(
39 const std::vector<base::FileUtilProxy::Entry>& entries, 218 const std::vector<base::FileUtilProxy::Entry>& entries,
40 bool has_more) OVERRIDE { 219 bool has_more) OVERRIDE {
41 NOTREACHED(); 220 NOTREACHED();
42 } 221 }
43 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE { 222 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE {
44 NOTREACHED(); 223 NOTREACHED();
45 } 224 }
46 virtual void DidOpenFileSystem(const std::string& name, 225 virtual void DidOpenFileSystem(const std::string& name,
47 const FilePath& path) OVERRIDE { 226 const FilePath& path) OVERRIDE {
227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
228 // Set up file permission access.
229 if (!file_url_.is_empty()) {
230 if (!SetupFileAccessPermissions()) {
231 DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
232 return;
233 }
234 } else if (!SetupFileSystemAccessPermissions()) {
235 DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
236 return;
237 }
238
48 BrowserThread::PostTask( 239 BrowserThread::PostTask(
49 BrowserThread::UI, FROM_HERE, 240 BrowserThread::UI, FROM_HERE,
50 NewRunnableMethod(function_, 241 NewRunnableMethod(function_,
51 &RequestLocalFileSystemFunction::RespondSuccessOnUIThread, 242 &RequestLocalFileSystemFunctionBase::RespondSuccessOnUIThread,
52 name, 243 name,
53 path)); 244 path,
245 file_url_));
54 } 246 }
55 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE { 247 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE {
56 BrowserThread::PostTask( 248 BrowserThread::PostTask(
57 BrowserThread::UI, FROM_HERE, 249 BrowserThread::UI, FROM_HERE,
58 NewRunnableMethod(function_, 250 NewRunnableMethod(function_,
59 &RequestLocalFileSystemFunction::RespondFailedOnUIThread, 251 &RequestLocalFileSystemFunctionBase::RespondFailedOnUIThread,
60 error_code)); 252 error_code));
61 } 253 }
62 private: 254 private:
63 RequestLocalFileSystemFunction* function_; 255
256 const Extension* GetExtension() {
257 std::string extension_id = source_url_.GetOrigin().host();
258 ExtensionService* service = profile_->GetExtensionService();
259 if (!service)
260 return NULL;
261 return service->GetExtensionById(extension_id,
262 false); // include_disabled
263 }
264
265 // Checks legitimacy of file url and grants RO access permissions for that
266 // file to the target renderer process.
267 bool SetupFileAccessPermissions() {
268 GURL file_origin_url;
269 FilePath virtual_path;
270 fileapi::FileSystemType type;
271 fileapi::FileSystemPathManager* path_manager =
272 profile_->GetFileSystemContext()->path_manager();
273
274 const Extension* extension = GetExtension();
275 if (!extension)
276 return false;
277
278 if (!path_manager->CrackFileSystemPath(FilePath(file_url_.spec()),
279 &file_origin_url,
280 &type,
281 &virtual_path)) {
282 return false;
283 }
284
285 if (type != fileapi::kFileSystemTypeLocal)
286 return false;
287
288 // Make sure this url really being used by the right caller extension.
289 if (source_url_.GetOrigin() != file_origin_url) {
290 DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
291 return false;
292 }
293 FilePath root_path = path_manager->GetFileSystemRootPathOnFileThread(
asargent_no_longer_on_chrome 2011/04/08 18:52:33 Is this method (SetupFileAccessPermissions) runnin
zel 2011/04/08 19:35:01 It's called from DidOpenFileSystem(), I have file
294 file_origin_url,
295 fileapi::kFileSystemTypeLocal,
296 virtual_path,
297 false); // create
298 FilePath finalFilePath = root_path.Append(virtual_path);
299
300 // TODO(zelidrag): Add explicit R/W + R/O permissions for non-component
301 // extensions.
302
303 // Grant R/O access permission to non-component extension and R/W to
304 // component extensions.
305 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
306 child_id_, finalFilePath,
307 extension->location() != Extension::COMPONENT ?
308 kReadOnlyFilePermissions : kReadWriteFilePermissions);
309 return true;
310 }
311
312 // Grants file system access permissions to file browser component.
313 bool SetupFileSystemAccessPermissions() {
314 const Extension* extension = GetExtension();
315 if (!extension)
316 return false;
317
318 // Make sure that only component extension can access the entire
319 // local file system.
320 if (extension->location() != Extension::COMPONENT
321 #ifndef NDEBUG
322 && !CommandLine::ForCurrentProcess()->HasSwitch(
323 switches::kExposePrivateExtensionApi)
324 #endif
325 ) {
326 NOTREACHED() << "Private method access by non-component extension "
327 << extension->id();
328 return false;
329 }
330
331 fileapi::FileSystemPathManager* path_manager =
332 profile_->GetFileSystemContext()->path_manager();
333 fileapi::FileSystemMountPointProvider* provider =
334 path_manager->local_provider();
335 if (!provider)
336 return false;
337
338 // Grant R/W file permissions to the renderer hosting component
339 // extension for all paths exposed by our local file system provider.
340 std::vector<FilePath> root_dirs = provider->GetRootDirectories();
341 for (std::vector<FilePath>::iterator iter = root_dirs.begin();
342 iter != root_dirs.end();
343 ++iter) {
344 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
345 child_id_, *iter, kReadWriteFilePermissions);
346 }
347 return true;
348 }
349
350 RequestLocalFileSystemFunctionBase* function_;
351 Profile* profile_;
352 // Renderer process id.
353 int child_id_;
354 // Extension source URL.
355 GURL source_url_;
356 GURL file_url_;
64 DISALLOW_COPY_AND_ASSIGN(LocalFileSystemCallbackDispatcher); 357 DISALLOW_COPY_AND_ASSIGN(LocalFileSystemCallbackDispatcher);
65 }; 358 };
66 359
67 RequestLocalFileSystemFunction::RequestLocalFileSystemFunction() { 360 void RequestLocalFileSystemFunctionBase::RequestOnFileThread(
68 } 361 const GURL& source_url, const GURL& file_url) {
69
70 RequestLocalFileSystemFunction::~RequestLocalFileSystemFunction() {
71 }
72
73 bool RequestLocalFileSystemFunction::RunImpl() {
74 fileapi::FileSystemOperation* operation = 362 fileapi::FileSystemOperation* operation =
75 new fileapi::FileSystemOperation( 363 new fileapi::FileSystemOperation(
76 new LocalFileSystemCallbackDispatcher(this), 364 new LocalFileSystemCallbackDispatcher(
365 this,
366 profile(),
367 dispatcher()->render_view_host()->process()->id(),
368 source_url,
369 file_url),
77 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 370 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
78 profile()->GetFileSystemContext(), 371 profile()->GetFileSystemContext(),
79 NULL); 372 NULL);
80 GURL origin_url = source_url().GetOrigin(); 373 GURL origin_url = source_url.GetOrigin();
81 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeLocal, 374 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeLocal,
82 false); // create 375 false); // create
376 }
377
378 bool RequestLocalFileSystemFunctionBase::RunImpl() {
379 std::string file_url;
380 if (args_->GetSize())
381 args_->GetString(0, &file_url);
382 BrowserThread::PostTask(
383 BrowserThread::FILE, FROM_HERE,
384 NewRunnableMethod(this,
385 &RequestLocalFileSystemFunctionBase::RequestOnFileThread,
386 source_url_,
387 GURL(file_url)));
83 // Will finish asynchronously. 388 // Will finish asynchronously.
84 return true; 389 return true;
85 } 390 }
86 391
87 void RequestLocalFileSystemFunction::RespondSuccessOnUIThread( 392 void RequestLocalFileSystemFunctionBase::RespondSuccessOnUIThread(
88 const std::string& name, const FilePath& path) { 393 const std::string& name, const FilePath& path,
394 const GURL& file_url) {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90 result_.reset(new DictionaryValue()); 396 result_.reset(new DictionaryValue());
91 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get()); 397 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get());
92 dict->SetString("name", name); 398 dict->SetString("name", name);
93 dict->SetString("path", path.value()); 399 dict->SetString("path", path.value());
94 dict->SetInteger("error", base::PLATFORM_FILE_OK); 400 dict->SetInteger("error", base::PLATFORM_FILE_OK);
401 if (!file_url.is_empty() && file_url.is_valid())
402 dict->SetString("fileUrl", file_url.spec());
95 SendResponse(true); 403 SendResponse(true);
96 } 404 }
97 405
98 void RequestLocalFileSystemFunction::RespondFailedOnUIThread( 406 void RequestLocalFileSystemFunctionBase::RespondFailedOnUIThread(
99 base::PlatformFileError error_code) { 407 base::PlatformFileError error_code) {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101 result_.reset(new DictionaryValue()); 409 error_ = base::StringPrintf(kFileError, static_cast<int>(error_code));
102 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get()); 410 SendResponse(false);
103 dict->SetInteger("error", static_cast<int>(error_code)); 411 }
412
413 bool GetFileTasksFileBrowserFunction::RunImpl() {
414 ListValue* files_list = NULL;
415 if (!args_->GetList(0, &files_list))
416 return false;
417
418 result_.reset(new ListValue());
419 ListValue* result_list = reinterpret_cast<ListValue*>(result_.get());
420
421 ExtensionMenuItem::List common_tasks;
422 if (!FindCommonTasks(profile_, source_url_, files_list, &common_tasks))
423 return false;
424
425 ExtensionService* service = profile_->GetExtensionService();
426 for (ExtensionMenuItem::List::iterator iter = common_tasks.begin();
427 iter != common_tasks.end();
428 ++iter) {
429 if ((*iter)->type() != ExtensionMenuItem::NORMAL)
430 continue;
431 const std::string extension_id = (*iter)->extension_id();
432 const Extension* extension = service->GetExtensionById(extension_id, false);
433 if (!extension) {
434 LOG(WARNING) << "Disabled extension" << extension_id;
435 continue;
436 }
437 DictionaryValue* task = new DictionaryValue();
438 task->SetString("taskId", MakeTaskID(kContextTaskIdSchema,
439 extension_id.c_str(),
440 (*iter)->id().uid));
441 task->SetString("title", (*iter)->title());
442 GURL icon =
443 ExtensionIconSource::GetIconURL(extension,
444 Extension::EXTENSION_ICON_SMALLISH,
445 ExtensionIconSet::MATCH_BIGGER,
446 false); // grayscale
447 task->SetString("iconUrl", icon.spec());
448 result_list->Append(task);
449 }
450
451 // TODO(zelidrag, serya): Add intent content tasks to result_list once we
452 // implement that API.
104 SendResponse(true); 453 SendResponse(true);
454 return true;
455 }
456
457 bool ExecuteTasksFileBrowserFunction::RunImpl() {
458 // First param is task id that was to the extension with getFileTasks call.
459 std::string task_id;
460 if (!args_->GetString(0, &task_id) || !task_id.size())
461 return false;
462
463 // The second param is the list of files that need to be executed with this
464 // task.
465 ListValue* files_list = NULL;
466 if (!args_->GetList(1, &files_list))
467 return false;
468
469 if (!files_list->GetSize())
470 return true;
471
472 std::string task_type;
473 std::string target_extension_id;
474 std::string action_id;
475 if (!CrackTaskIdentifier(task_id, &task_type, &target_extension_id,
476 &action_id)) {
477 return false;
478 }
479
480 if (task_type == kContextTaskIdSchema) {
481 ExecuteContextMenuTasks(target_extension_id, action_id, files_list);
482 } else {
483 LOG(WARNING) << "Unsupported task type of: " << task_type;
484 // TODO(zelidrag, serya): Add intent content tasks here once we implement
485 // that API.
486 return false;
487 }
488 SendResponse(true);
489 return true;
490 }
491
492 bool ExecuteTasksFileBrowserFunction::GrantLocalFileSystemAccess(
493 const GURL& origin_file_url,
494 const std::string& extension_id,
495 GURL* target_file_url) {
496 GURL file_origin_url;
497 FilePath virtual_path;
498 fileapi::FileSystemType type;
499 fileapi::FileSystemPathManager* path_manager =
500 profile_->GetFileSystemContext()->path_manager();
501 // Breakdown file URL.
502 if (!path_manager->CrackFileSystemPath(FilePath(origin_file_url.spec()),
503 &file_origin_url,
504 &type,
505 &virtual_path)) {
506 return false;
507 }
508 // Grant access to this particular file to target extension.
509 GURL target_origin_url(Extension::GetBaseURLFromExtensionId(extension_id));
510 fileapi::FileSystemMountPointProvider* provider =
511 path_manager->local_provider();
512 if (!provider)
513 return false;
514 provider->GrantAccess(target_origin_url, virtual_path);
515 GURL base_url = fileapi::GetFileSystemRootURI(target_origin_url,
516 fileapi::kFileSystemTypeLocal);
517 *target_file_url = GURL(base_url.spec() + virtual_path.value());
518 return true;
519 }
520
521 bool ExecuteTasksFileBrowserFunction::ExecuteContextMenuTasks(
522 const std::string& handler_extension_id, const std::string& action_id,
523 ListValue* files_list) {
524 ExtensionMenuManager* manager =
525 profile_->GetExtensionService()->menu_manager();
526 for (size_t i = 0; i < files_list->GetSize(); i++) {
527 std::string origin_file_url;
528 if (!files_list->GetString(i, &origin_file_url)) {
529 error_ = kInvalidFileUrl;
530 SendResponse(false);
531 return false;
532 }
533 GURL handler_file_url;
534 if (!GrantLocalFileSystemAccess(GURL(origin_file_url),
535 handler_extension_id,
536 &handler_file_url)) {
537 error_ = kInvalidFileUrl;
538 SendResponse(false);
539 return false;
540 }
541 ContextMenuParams params;
542 CreateContextMenuParams(source_url_, handler_file_url.spec(), &params);
543 ExtensionMenuItem::Id menuItemId(profile_, handler_extension_id,
544 atoi(action_id.c_str()));
545 manager->ExecuteCommand(profile_,
546 NULL, // tab_contents, not needed in args.
547 params,
548 menuItemId);
549 }
550 result_.reset(new FundamentalValue(true));
551 SendResponse(true);
552 return true;
105 } 553 }
106 554
107 FileDialogFunction::FileDialogFunction() { 555 FileDialogFunction::FileDialogFunction() {
108 } 556 }
109 557
110 FileDialogFunction::~FileDialogFunction() { 558 FileDialogFunction::~FileDialogFunction() {
111 } 559 }
112 560
113 // static 561 // static
114 FileDialogFunction::ListenerMap FileDialogFunction::listener_map_; 562 FileDialogFunction::ListenerMap FileDialogFunction::listener_map_;
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 dict->SetString("NOTHING_SELECTED", 755 dict->SetString("NOTHING_SELECTED",
308 l10n_util::GetStringUTF16(IDS_FILE_BROWSER_NOTHING_SELECTED)); 756 l10n_util::GetStringUTF16(IDS_FILE_BROWSER_NOTHING_SELECTED));
309 dict->SetString("ONE_FILE_SELECTED", 757 dict->SetString("ONE_FILE_SELECTED",
310 l10n_util::GetStringUTF16(IDS_FILE_BROWSER_ONE_FILE_SELECTED)); 758 l10n_util::GetStringUTF16(IDS_FILE_BROWSER_ONE_FILE_SELECTED));
311 dict->SetString("MANY_FILES_SELECTED", 759 dict->SetString("MANY_FILES_SELECTED",
312 l10n_util::GetStringUTF16(IDS_FILE_BROWSER_MANY_FILES_SELECTED)); 760 l10n_util::GetStringUTF16(IDS_FILE_BROWSER_MANY_FILES_SELECTED));
313 761
314 SendResponse(true); 762 SendResponse(true);
315 return true; 763 return true;
316 } 764 }
765
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698