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

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

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

Powered by Google App Engine
This is Rietveld 408576698