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

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

Powered by Google App Engine
This is Rietveld 408576698