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

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

Powered by Google App Engine
This is Rietveld 408576698