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

Side by Side Diff: chrome/browser/chromeos/extensions/file_handler_util.cc

Issue 13929003: chromeos: Move chrome/browser/chromeos/extensions/file_handler_util.* to a sub-directory (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/extensions/file_handler_util.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/i18n/case_conversion.h"
10 #include "base/json/json_writer.h"
11 #include "base/string_util.h"
12 #include "base/stringprintf.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/chromeos/drive/drive_file_system_util.h"
15 #include "chrome/browser/chromeos/drive/drive_task_executor.h"
16 #include "chrome/browser/chromeos/extensions/file_browser_handler.h"
17 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
18 #include "chrome/browser/extensions/event_router.h"
19 #include "chrome/browser/extensions/extension_host.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_system.h"
22 #include "chrome/browser/extensions/extension_tab_util.h"
23 #include "chrome/browser/extensions/lazy_background_task_queue.h"
24 #include "chrome/browser/extensions/platform_app_launcher.h"
25 #include "chrome/browser/prefs/scoped_user_pref_update.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/profiles/profile_manager.h"
28 #include "chrome/browser/ui/browser.h"
29 #include "chrome/browser/ui/browser_finder.h"
30 #include "chrome/browser/ui/browser_tabstrip.h"
31 #include "chrome/browser/ui/host_desktop.h"
32 #include "chrome/common/extensions/background_info.h"
33 #include "chrome/common/pref_names.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/child_process_security_policy.h"
36 #include "content/public/browser/render_process_host.h"
37 #include "content/public/browser/site_instance.h"
38 #include "content/public/browser/storage_partition.h"
39 #include "content/public/browser/web_contents.h"
40 #include "net/base/escape.h"
41 #include "webkit/chromeos/fileapi/cros_mount_point_provider.h"
42 #include "webkit/fileapi/file_system_context.h"
43 #include "webkit/fileapi/file_system_url.h"
44 #include "webkit/fileapi/file_system_util.h"
45 #include "webkit/fileapi/isolated_context.h"
46
47 using content::BrowserContext;
48 using content::BrowserThread;
49 using content::ChildProcessSecurityPolicy;
50 using content::SiteInstance;
51 using content::WebContents;
52 using extensions::Extension;
53 using fileapi::FileSystemURL;
54
55 namespace file_handler_util {
56
57 const char kTaskFile[] = "file";
58 const char kTaskDrive[] = "drive";
59 const char kTaskApp[] = "app";
60
61 namespace {
62
63 // Legacy Drive task extension prefix, used by CrackTaskID.
64 const char kDriveTaskExtensionPrefix[] = "drive-app:";
65 const size_t kDriveTaskExtensionPrefixLength =
66 arraysize(kDriveTaskExtensionPrefix) - 1;
67
68 typedef std::set<const FileBrowserHandler*> FileBrowserHandlerSet;
69
70 const int kReadWriteFilePermissions = base::PLATFORM_FILE_OPEN |
71 base::PLATFORM_FILE_CREATE |
72 base::PLATFORM_FILE_OPEN_ALWAYS |
73 base::PLATFORM_FILE_CREATE_ALWAYS |
74 base::PLATFORM_FILE_OPEN_TRUNCATED |
75 base::PLATFORM_FILE_READ |
76 base::PLATFORM_FILE_WRITE |
77 base::PLATFORM_FILE_EXCLUSIVE_READ |
78 base::PLATFORM_FILE_EXCLUSIVE_WRITE |
79 base::PLATFORM_FILE_ASYNC |
80 base::PLATFORM_FILE_WRITE_ATTRIBUTES;
81
82 const int kReadOnlyFilePermissions = base::PLATFORM_FILE_OPEN |
83 base::PLATFORM_FILE_READ |
84 base::PLATFORM_FILE_EXCLUSIVE_READ |
85 base::PLATFORM_FILE_ASYNC;
86
87 const char kFileBrowserExtensionId[] = "hhaomjibdihmijegdhdafkllkbggdgoj";
88
89 // Returns process id of the process the extension is running in.
90 int ExtractProcessFromExtensionId(Profile* profile,
91 const std::string& extension_id) {
92 GURL extension_url =
93 Extension::GetBaseURLFromExtensionId(extension_id);
94 ExtensionProcessManager* manager =
95 extensions::ExtensionSystem::Get(profile)->process_manager();
96
97 SiteInstance* site_instance = manager->GetSiteInstanceForURL(extension_url);
98 if (!site_instance || !site_instance->HasProcess())
99 return -1;
100 content::RenderProcessHost* process = site_instance->GetProcess();
101
102 return process->GetID();
103 }
104
105 bool IsBuiltinTask(const FileBrowserHandler* task) {
106 return (task->extension_id() == kFileBrowserExtensionId ||
107 task->extension_id() ==
108 extension_misc::kQuickOfficeComponentExtensionId ||
109 task->extension_id() == extension_misc::kQuickOfficeDevExtensionId ||
110 task->extension_id() == extension_misc::kQuickOfficeExtensionId);
111 }
112
113 bool MatchesAllURLs(const FileBrowserHandler* handler) {
114 const std::set<URLPattern>& patterns =
115 handler->file_url_patterns().patterns();
116 for (std::set<URLPattern>::const_iterator it = patterns.begin();
117 it != patterns.end();
118 ++it) {
119 if (it->match_all_urls())
120 return true;
121 }
122 return false;
123 }
124
125 const FileBrowserHandler* FindFileBrowserHandler(const Extension* extension,
126 const std::string& action_id) {
127 FileBrowserHandler::List* handler_list =
128 FileBrowserHandler::GetHandlers(extension);
129 for (FileBrowserHandler::List::const_iterator action_iter =
130 handler_list->begin();
131 action_iter != handler_list->end();
132 ++action_iter) {
133 if (action_iter->get()->id() == action_id)
134 return action_iter->get();
135 }
136 return NULL;
137 }
138
139 unsigned int GetAccessPermissionsForFileBrowserHandler(
140 const Extension* extension,
141 const std::string& action_id) {
142 const FileBrowserHandler* action =
143 FindFileBrowserHandler(extension, action_id);
144 if (!action)
145 return 0;
146 unsigned int result = 0;
147 if (action->CanRead())
148 result |= kReadOnlyFilePermissions;
149 if (action->CanWrite())
150 result |= kReadWriteFilePermissions;
151 // TODO(tbarzic): We don't handle Create yet.
152 return result;
153 }
154
155 std::string EscapedUtf8ToLower(const std::string& str) {
156 string16 utf16 = UTF8ToUTF16(
157 net::UnescapeURLComponent(str, net::UnescapeRule::NORMAL));
158 return net::EscapeUrlEncodedData(
159 UTF16ToUTF8(base::i18n::ToLower(utf16)),
160 false /* do not replace space with plus */);
161 }
162
163 bool GetFileBrowserHandlers(Profile* profile,
164 const GURL& selected_file_url,
165 FileBrowserHandlerSet* results) {
166 ExtensionService* service =
167 extensions::ExtensionSystem::Get(profile)->extension_service();
168 if (!service)
169 return false; // In unit-tests, we may not have an ExtensionService.
170
171 // We need case-insensitive matching, and pattern in the handler is already
172 // in lower case.
173 const GURL lowercase_url(EscapedUtf8ToLower(selected_file_url.spec()));
174
175 for (ExtensionSet::const_iterator iter = service->extensions()->begin();
176 iter != service->extensions()->end();
177 ++iter) {
178 const Extension* extension = *iter;
179 if (profile->IsOffTheRecord() &&
180 !service->IsIncognitoEnabled(extension->id()))
181 continue;
182
183 FileBrowserHandler::List* handler_list =
184 FileBrowserHandler::GetHandlers(extension);
185 if (!handler_list)
186 continue;
187 for (FileBrowserHandler::List::const_iterator action_iter =
188 handler_list->begin();
189 action_iter != handler_list->end();
190 ++action_iter) {
191 const FileBrowserHandler* action = action_iter->get();
192 if (!action->MatchesURL(lowercase_url))
193 continue;
194
195 results->insert(action_iter->get());
196 }
197 }
198 return true;
199 }
200
201 } // namespace
202
203 void UpdateDefaultTask(Profile* profile,
204 const std::string& task_id,
205 const std::set<std::string>& suffixes,
206 const std::set<std::string>& mime_types) {
207 if (!profile || !profile->GetPrefs())
208 return;
209
210 if (!mime_types.empty()) {
211 DictionaryPrefUpdate mime_type_pref(profile->GetPrefs(),
212 prefs::kDefaultTasksByMimeType);
213 for (std::set<std::string>::const_iterator iter = mime_types.begin();
214 iter != mime_types.end(); ++iter) {
215 base::StringValue* value = new base::StringValue(task_id);
216 mime_type_pref->SetWithoutPathExpansion(*iter, value);
217 }
218 }
219
220 if (!suffixes.empty()) {
221 DictionaryPrefUpdate mime_type_pref(profile->GetPrefs(),
222 prefs::kDefaultTasksBySuffix);
223 for (std::set<std::string>::const_iterator iter = suffixes.begin();
224 iter != suffixes.end(); ++iter) {
225 base::StringValue* value = new base::StringValue(task_id);
226 // Suffixes are case insensitive.
227 std::string lower_suffix = StringToLowerASCII(*iter);
228 mime_type_pref->SetWithoutPathExpansion(lower_suffix, value);
229 }
230 }
231 }
232
233 std::string GetDefaultTaskIdFromPrefs(Profile* profile,
234 const std::string& mime_type,
235 const std::string& suffix) {
236 VLOG(1) << "Looking for default for MIME type: " << mime_type
237 << " and suffix: " << suffix;
238 std::string task_id;
239 if (!mime_type.empty()) {
240 const DictionaryValue* mime_task_prefs =
241 profile->GetPrefs()->GetDictionary(prefs::kDefaultTasksByMimeType);
242 DCHECK(mime_task_prefs);
243 LOG_IF(ERROR, !mime_task_prefs) << "Unable to open MIME type prefs";
244 if (mime_task_prefs &&
245 mime_task_prefs->GetStringWithoutPathExpansion(mime_type, &task_id)) {
246 VLOG(1) << "Found MIME default handler: " << task_id;
247 return task_id;
248 }
249 }
250
251 const DictionaryValue* suffix_task_prefs =
252 profile->GetPrefs()->GetDictionary(prefs::kDefaultTasksBySuffix);
253 DCHECK(suffix_task_prefs);
254 LOG_IF(ERROR, !suffix_task_prefs) << "Unable to open suffix prefs";
255 std::string lower_suffix = StringToLowerASCII(suffix);
256 if (suffix_task_prefs)
257 suffix_task_prefs->GetStringWithoutPathExpansion(lower_suffix, &task_id);
258 VLOG_IF(1, !task_id.empty()) << "Found suffix default handler: " << task_id;
259 return task_id;
260 }
261
262 int GetReadWritePermissions() {
263 return kReadWriteFilePermissions;
264 }
265
266 int GetReadOnlyPermissions() {
267 return kReadOnlyFilePermissions;
268 }
269
270 std::string MakeTaskID(const std::string& extension_id,
271 const std::string& task_type,
272 const std::string& action_id) {
273 DCHECK(task_type == kTaskFile ||
274 task_type == kTaskDrive ||
275 task_type == kTaskApp);
276 return base::StringPrintf("%s|%s|%s",
277 extension_id.c_str(),
278 task_type.c_str(),
279 action_id.c_str());
280 }
281
282 // Breaks down task_id that is used between getFileTasks() and executeTask() on
283 // its building blocks. task_id field the following structure:
284 // <extension-id>|<task-type>|<task-action-id>
285 bool CrackTaskID(const std::string& task_id,
286 std::string* extension_id,
287 std::string* task_type,
288 std::string* action_id) {
289 std::vector<std::string> result;
290 int count = Tokenize(task_id, std::string("|"), &result);
291
292 // Parse historic task_id parameters that only contain two parts. Drive tasks
293 // are identified by a prefix "drive-app:" on the extension ID.
294 if (count == 2) {
295 if (StartsWithASCII(result[0], kDriveTaskExtensionPrefix, true)) {
296 if (task_type)
297 *task_type = kTaskDrive;
298
299 if (extension_id)
300 *extension_id = result[0].substr(kDriveTaskExtensionPrefixLength);
301 } else {
302 if (task_type)
303 *task_type = kTaskFile;
304
305 if (extension_id)
306 *extension_id = result[0];
307 }
308
309 if (action_id)
310 *action_id = result[1];
311
312 return true;
313 }
314
315 if (count != 3)
316 return false;
317
318 if (extension_id)
319 *extension_id = result[0];
320
321 if (task_type) {
322 *task_type = result[1];
323 DCHECK(*task_type == kTaskFile ||
324 *task_type == kTaskDrive ||
325 *task_type == kTaskApp);
326 }
327
328 if (action_id)
329 *action_id = result[2];
330
331 return true;
332 }
333
334 // Find a specific handler in the handler list.
335 FileBrowserHandlerSet::iterator FindHandler(
336 FileBrowserHandlerSet* handler_set,
337 const std::string& extension_id,
338 const std::string& id) {
339 FileBrowserHandlerSet::iterator iter = handler_set->begin();
340 while (iter != handler_set->end() &&
341 !((*iter)->extension_id() == extension_id &&
342 (*iter)->id() == id)) {
343 iter++;
344 }
345 return iter;
346 }
347
348 // Given the list of selected files, returns array of file action tasks
349 // that are shared between them.
350 void FindDefaultTasks(Profile* profile,
351 const std::vector<base::FilePath>& files_list,
352 const FileBrowserHandlerSet& common_tasks,
353 FileBrowserHandlerSet* default_tasks) {
354 DCHECK(default_tasks);
355 default_tasks->clear();
356
357 std::set<std::string> default_ids;
358 for (std::vector<base::FilePath>::const_iterator it = files_list.begin();
359 it != files_list.end(); ++it) {
360 std::string task_id = file_handler_util::GetDefaultTaskIdFromPrefs(
361 profile, "", it->Extension());
362 if (!task_id.empty())
363 default_ids.insert(task_id);
364 }
365
366 const FileBrowserHandler* builtin_task = NULL;
367 // Convert the default task IDs collected above to one of the handler pointers
368 // from common_tasks.
369 for (FileBrowserHandlerSet::const_iterator task_iter = common_tasks.begin();
370 task_iter != common_tasks.end(); ++task_iter) {
371 std::string task_id = MakeTaskID((*task_iter)->extension_id(), kTaskFile,
372 (*task_iter)->id());
373 std::set<std::string>::iterator default_iter = default_ids.find(task_id);
374 if (default_iter != default_ids.end()) {
375 default_tasks->insert(*task_iter);
376 continue;
377 }
378
379 // If it's a built in task, remember it. If there are no default tasks among
380 // common tasks, builtin task will be used as a fallback.
381 // Note that builtin tasks are not overlapping, so there can be at most one
382 // builtin tasks for each set of files.
383 if (IsBuiltinTask(*task_iter))
384 builtin_task = *task_iter;
385 }
386
387 // If there are no default tasks found, use builtin task (if found) as a
388 // default.
389 if (builtin_task && default_tasks->empty())
390 default_tasks->insert(builtin_task);
391 }
392
393 // Given the list of selected files, returns array of context menu tasks
394 // that are shared
395 bool FindCommonTasks(Profile* profile,
396 const std::vector<GURL>& files_list,
397 FileBrowserHandlerSet* common_tasks) {
398 DCHECK(common_tasks);
399 common_tasks->clear();
400
401 FileBrowserHandlerSet common_task_set;
402 std::set<std::string> default_task_ids;
403 for (std::vector<GURL>::const_iterator it = files_list.begin();
404 it != files_list.end(); ++it) {
405 FileBrowserHandlerSet file_actions;
406 if (!GetFileBrowserHandlers(profile, *it, &file_actions))
407 return false;
408 // If there is nothing to do for one file, the intersection of tasks for all
409 // files will be empty at the end, and so will the default tasks.
410 if (file_actions.empty())
411 return true;
412
413 // For the very first file, just copy all the elements.
414 if (it == files_list.begin()) {
415 common_task_set = file_actions;
416 } else {
417 // For all additional files, find intersection between the accumulated and
418 // file specific set.
419 FileBrowserHandlerSet intersection;
420 std::set_intersection(common_task_set.begin(), common_task_set.end(),
421 file_actions.begin(), file_actions.end(),
422 std::inserter(intersection,
423 intersection.begin()));
424 common_task_set = intersection;
425 if (common_task_set.empty())
426 return true;
427 }
428 }
429
430 FileBrowserHandlerSet::iterator watch_iter = FindHandler(
431 &common_task_set, kFileBrowserDomain, kFileBrowserWatchTaskId);
432 FileBrowserHandlerSet::iterator gallery_iter = FindHandler(
433 &common_task_set, kFileBrowserDomain, kFileBrowserGalleryTaskId);
434 if (watch_iter != common_task_set.end() &&
435 gallery_iter != common_task_set.end()) {
436 // Both "watch" and "gallery" actions are applicable which means that the
437 // selection is all videos. Showing them both is confusing, so we only keep
438 // the one that makes more sense ("watch" for single selection, "gallery"
439 // for multiple selection).
440 if (files_list.size() == 1)
441 common_task_set.erase(gallery_iter);
442 else
443 common_task_set.erase(watch_iter);
444 }
445
446 common_tasks->swap(common_task_set);
447 return true;
448 }
449
450 bool GetTaskForURLAndPath(Profile* profile,
451 const GURL& url,
452 const base::FilePath& file_path,
453 const FileBrowserHandler** handler) {
454 std::vector<GURL> file_urls;
455 file_urls.push_back(url);
456
457 FileBrowserHandlerSet default_tasks;
458 FileBrowserHandlerSet common_tasks;
459 if (!FindCommonTasks(profile, file_urls, &common_tasks))
460 return false;
461
462 if (common_tasks.empty())
463 return false;
464
465 std::vector<base::FilePath> file_paths;
466 file_paths.push_back(file_path);
467
468 FindDefaultTasks(profile, file_paths, common_tasks, &default_tasks);
469
470 // If there's none, or more than one, then we don't have a canonical default.
471 if (!default_tasks.empty()) {
472 // There should not be multiple default tasks for a single URL.
473 DCHECK_EQ(1u, default_tasks.size());
474
475 *handler = *default_tasks.begin();
476 return true;
477 }
478
479 // If there are no default tasks, use first task in the list (file manager
480 // does the same in this situation).
481 // TODO(tbarzic): This is so not optimal behaviour.
482 *handler = *common_tasks.begin();
483 return true;
484 }
485
486 class ExtensionTaskExecutor : public FileTaskExecutor {
487 public:
488 // FileTaskExecutor overrides.
489 virtual bool ExecuteAndNotify(const std::vector<FileSystemURL>& file_urls,
490 const FileTaskFinishedCallback& done) OVERRIDE;
491
492 private:
493 // FileTaskExecutor is the only class allowed to create one.
494 friend class FileTaskExecutor;
495
496 ExtensionTaskExecutor(Profile* profile,
497 const GURL& source_url,
498 const std::string& file_browser_id,
499 int32 tab_id,
500 const std::string& extension_id,
501 const std::string& action_id);
502 virtual ~ExtensionTaskExecutor();
503
504 struct FileDefinition {
505 FileDefinition();
506 ~FileDefinition();
507
508 base::FilePath virtual_path;
509 base::FilePath absolute_path;
510 bool is_directory;
511 };
512
513 typedef std::vector<FileDefinition> FileDefinitionList;
514 class ExecuteTasksFileSystemCallbackDispatcher;
515 void RequestFileEntryOnFileThread(
516 scoped_refptr<fileapi::FileSystemContext> file_system_context_handler,
517 const GURL& handler_base_url,
518 const scoped_refptr<const extensions::Extension>& handler,
519 int handler_pid,
520 const std::vector<FileSystemURL>& file_urls);
521
522 void ExecuteDoneOnUIThread(bool success);
523 void ExecuteFileActionsOnUIThread(const std::string& file_system_name,
524 const GURL& file_system_root,
525 const FileDefinitionList& file_list,
526 int handler_pid);
527 void SetupPermissionsAndDispatchEvent(const std::string& file_system_name,
528 const GURL& file_system_root,
529 const FileDefinitionList& file_list,
530 int handler_pid_in,
531 extensions::ExtensionHost* host);
532
533 // Registers file permissions from |handler_host_permissions_| with
534 // ChildProcessSecurityPolicy for process with id |handler_pid|.
535 void SetupHandlerHostFileAccessPermissions(
536 const FileDefinitionList& file_list,
537 const Extension* extension,
538 int handler_pid);
539
540 int32 tab_id_;
541 const std::string action_id_;
542 FileTaskFinishedCallback done_;
543 };
544
545 class AppTaskExecutor : public FileTaskExecutor {
546 public:
547 // FileTaskExecutor overrides.
548 virtual bool ExecuteAndNotify(const std::vector<FileSystemURL>& file_urls,
549 const FileTaskFinishedCallback& done) OVERRIDE;
550
551 private:
552 // FileTaskExecutor is the only class allowed to create one.
553 friend class FileTaskExecutor;
554
555 AppTaskExecutor(Profile* profile,
556 const GURL& source_url,
557 const std::string& file_browser_id,
558 const std::string& extension_id,
559 const std::string& action_id);
560 virtual ~AppTaskExecutor();
561
562 const std::string extension_id_;
563 const std::string action_id_;
564 };
565
566 // static
567 FileTaskExecutor* FileTaskExecutor::Create(Profile* profile,
568 const GURL& source_url,
569 const std::string& file_browser_id,
570 int32 tab_id,
571 const std::string& extension_id,
572 const std::string& task_type,
573 const std::string& action_id) {
574 if (task_type == kTaskFile)
575 return new ExtensionTaskExecutor(profile,
576 source_url,
577 file_browser_id,
578 tab_id,
579 extension_id,
580 action_id);
581
582 if (task_type == kTaskDrive)
583 return new drive::DriveTaskExecutor(profile,
584 extension_id, // really app_id
585 action_id);
586
587 if (task_type == kTaskApp)
588 return new AppTaskExecutor(profile,
589 source_url,
590 file_browser_id,
591 extension_id,
592 action_id);
593
594 NOTREACHED();
595 return NULL;
596 }
597
598 FileTaskExecutor::FileTaskExecutor(Profile* profile,
599 const GURL& source_url,
600 const std::string& file_browser_id,
601 const std::string& extension_id)
602 : profile_(profile),
603 source_url_(source_url),
604 file_browser_id_(file_browser_id),
605 extension_id_(extension_id) {
606 }
607
608 FileTaskExecutor::~FileTaskExecutor() {
609 }
610
611 bool FileTaskExecutor::Execute(const std::vector<FileSystemURL>& file_urls) {
612 return ExecuteAndNotify(file_urls, FileTaskFinishedCallback());
613 }
614
615 bool FileTaskExecutor::FileBrowserHasAccessPermissionForFiles(
616 const std::vector<FileSystemURL>& files) {
617 // Check if the file browser extension has permissions for the files in its
618 // file system context.
619 GURL site = extensions::ExtensionSystem::Get(profile())->extension_service()->
620 GetSiteForExtensionId(file_browser_id_);
621 fileapi::ExternalFileSystemMountPointProvider* external_provider =
622 BrowserContext::GetStoragePartitionForSite(profile(), site)->
623 GetFileSystemContext()->external_provider();
624
625 if (!external_provider)
626 return false;
627
628 for (size_t i = 0; i < files.size(); ++i) {
629 // Make sure this url really being used by the right caller extension.
630 if (source_url_.GetOrigin() != files[i].origin())
631 return false;
632
633 if (!chromeos::CrosMountPointProvider::CanHandleURL(files[i]) ||
634 !external_provider->IsAccessAllowed(files[i])) {
635 return false;
636 }
637 }
638
639 return true;
640 }
641
642 // TODO(kaznacheev): Remove this method and inline its implementation at the
643 // only place where it is used (DriveTaskExecutor::OnAppAuthorized)
644 Browser* FileTaskExecutor::GetBrowser() const {
645 return chrome::FindOrCreateTabbedBrowser(
646 profile_ ? profile_ : ProfileManager::GetDefaultProfileOrOffTheRecord(),
647 chrome::HOST_DESKTOP_TYPE_ASH);
648 }
649
650 const Extension* FileTaskExecutor::GetExtension() {
651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
652
653 ExtensionService* service =
654 extensions::ExtensionSystem::Get(profile())->extension_service();
655 return service ? service->GetExtensionById(extension_id_, false) :
656 NULL;
657 }
658
659 ExtensionTaskExecutor::FileDefinition::FileDefinition() : is_directory(false) {
660 }
661
662 ExtensionTaskExecutor::FileDefinition::~FileDefinition() {
663 }
664
665 class ExtensionTaskExecutor::ExecuteTasksFileSystemCallbackDispatcher {
666 public:
667 static fileapi::FileSystemContext::OpenFileSystemCallback CreateCallback(
668 ExtensionTaskExecutor* executor,
669 scoped_refptr<fileapi::FileSystemContext> file_system_context_handler,
670 scoped_refptr<const Extension> handler_extension,
671 int handler_pid,
672 const std::string& action_id,
673 const std::vector<FileSystemURL>& file_urls) {
674 return base::Bind(
675 &ExecuteTasksFileSystemCallbackDispatcher::DidOpenFileSystem,
676 base::Owned(new ExecuteTasksFileSystemCallbackDispatcher(
677 executor, file_system_context_handler, handler_extension,
678 handler_pid, action_id, file_urls)));
679 }
680
681 void DidOpenFileSystem(base::PlatformFileError result,
682 const std::string& file_system_name,
683 const GURL& file_system_root) {
684 if (result != base::PLATFORM_FILE_OK) {
685 DidFail(result);
686 return;
687 }
688 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
689 ExtensionTaskExecutor::FileDefinitionList file_list;
690 for (std::vector<FileSystemURL>::iterator iter = urls_.begin();
691 iter != urls_.end();
692 ++iter) {
693 // Set up file permission access.
694 ExtensionTaskExecutor::FileDefinition file;
695 if (!SetupFileAccessPermissions(*iter, &file))
696 continue;
697 file_list.push_back(file);
698 }
699 if (file_list.empty()) {
700 BrowserThread::PostTask(
701 BrowserThread::UI, FROM_HERE,
702 base::Bind(
703 &ExtensionTaskExecutor::ExecuteDoneOnUIThread,
704 executor_,
705 false));
706 return;
707 }
708
709 BrowserThread::PostTask(
710 BrowserThread::UI, FROM_HERE,
711 base::Bind(
712 &ExtensionTaskExecutor::ExecuteFileActionsOnUIThread,
713 executor_,
714 file_system_name,
715 file_system_root,
716 file_list,
717 handler_pid_));
718 }
719
720 void DidFail(base::PlatformFileError error_code) {
721 BrowserThread::PostTask(
722 BrowserThread::UI, FROM_HERE,
723 base::Bind(
724 &ExtensionTaskExecutor::ExecuteDoneOnUIThread,
725 executor_,
726 false));
727 }
728
729 private:
730 ExecuteTasksFileSystemCallbackDispatcher(
731 ExtensionTaskExecutor* executor,
732 scoped_refptr<fileapi::FileSystemContext> file_system_context_handler,
733 const scoped_refptr<const Extension>& handler_extension,
734 int handler_pid,
735 const std::string& action_id,
736 const std::vector<FileSystemURL>& file_urls)
737 : executor_(executor),
738 file_system_context_handler_(file_system_context_handler),
739 handler_extension_(handler_extension),
740 handler_pid_(handler_pid),
741 action_id_(action_id),
742 urls_(file_urls) {
743 DCHECK(executor_);
744 }
745
746 // Checks legitimacy of file url and grants file RO access permissions from
747 // handler (target) extension and its renderer process.
748 bool SetupFileAccessPermissions(const FileSystemURL& url,
749 FileDefinition* file) {
750 if (!handler_extension_.get())
751 return false;
752
753 if (handler_pid_ == 0)
754 return false;
755
756 fileapi::ExternalFileSystemMountPointProvider* external_provider_handler =
757 file_system_context_handler_->external_provider();
758
759 // Check if this file system entry exists first.
760 base::PlatformFileInfo file_info;
761
762 base::FilePath local_path = url.path();
763 base::FilePath virtual_path = url.virtual_path();
764
765 bool is_drive_file = url.type() == fileapi::kFileSystemTypeDrive;
766 DCHECK(!is_drive_file || drive::util::IsUnderDriveMountPoint(local_path));
767
768 // If the file is under gdata mount point, there is no actual file to be
769 // found on the url.path().
770 if (!is_drive_file) {
771 if (!file_util::PathExists(local_path) ||
772 file_util::IsLink(local_path) ||
773 !file_util::GetFileInfo(local_path, &file_info)) {
774 return false;
775 }
776 }
777
778 // Grant access to this particular file to target extension. This will
779 // ensure that the target extension can access only this FS entry and
780 // prevent from traversing FS hierarchy upward.
781 external_provider_handler->GrantFileAccessToExtension(
782 handler_extension_->id(), virtual_path);
783
784 // Output values.
785 file->virtual_path = virtual_path;
786 file->is_directory = file_info.is_directory;
787 file->absolute_path = local_path;
788 return true;
789 }
790
791 ExtensionTaskExecutor* executor_;
792 scoped_refptr<fileapi::FileSystemContext> file_system_context_handler_;
793 scoped_refptr<const Extension> handler_extension_;
794 int handler_pid_;
795 std::string action_id_;
796 std::vector<FileSystemURL> urls_;
797 DISALLOW_COPY_AND_ASSIGN(ExecuteTasksFileSystemCallbackDispatcher);
798 };
799
800 ExtensionTaskExecutor::ExtensionTaskExecutor(
801 Profile* profile,
802 const GURL& source_url,
803 const std::string& file_browser_id,
804 int tab_id,
805 const std::string& extension_id,
806 const std::string& action_id)
807 : FileTaskExecutor(profile, source_url, file_browser_id, extension_id),
808 tab_id_(tab_id),
809 action_id_(action_id) {
810 }
811
812 ExtensionTaskExecutor::~ExtensionTaskExecutor() {}
813
814 bool ExtensionTaskExecutor::ExecuteAndNotify(
815 const std::vector<FileSystemURL>& file_urls,
816 const FileTaskFinishedCallback& done) {
817 if (!FileBrowserHasAccessPermissionForFiles(file_urls))
818 return false;
819
820 scoped_refptr<const Extension> handler = GetExtension();
821 if (!handler.get())
822 return false;
823
824 int handler_pid = ExtractProcessFromExtensionId(profile(), handler->id());
825 if (handler_pid <= 0) {
826 if (!extensions::BackgroundInfo::HasLazyBackgroundPage(handler))
827 return false;
828 }
829
830 done_ = done;
831
832 // Get file system context for the extension to which onExecute event will be
833 // send. The file access permissions will be granted to the extension in the
834 // file system context for the files in |file_urls|.
835 GURL site = extensions::ExtensionSystem::Get(profile())->extension_service()->
836 GetSiteForExtensionId(handler->id());
837 scoped_refptr<fileapi::FileSystemContext> file_system_context_handler =
838 BrowserContext::GetStoragePartitionForSite(profile(), site)->
839 GetFileSystemContext();
840
841 BrowserThread::PostTask(
842 BrowserThread::FILE, FROM_HERE,
843 base::Bind(
844 &ExtensionTaskExecutor::RequestFileEntryOnFileThread,
845 this,
846 file_system_context_handler,
847 Extension::GetBaseURLFromExtensionId(handler->id()),
848 handler,
849 handler_pid,
850 file_urls));
851 return true;
852 }
853
854 void ExtensionTaskExecutor::RequestFileEntryOnFileThread(
855 scoped_refptr<fileapi::FileSystemContext> file_system_context_handler,
856 const GURL& handler_base_url,
857 const scoped_refptr<const Extension>& handler,
858 int handler_pid,
859 const std::vector<FileSystemURL>& file_urls) {
860 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
861 GURL origin_url = handler_base_url.GetOrigin();
862 file_system_context_handler->OpenFileSystem(
863 origin_url, fileapi::kFileSystemTypeExternal, false, // create
864 ExecuteTasksFileSystemCallbackDispatcher::CreateCallback(
865 this,
866 file_system_context_handler,
867 handler,
868 handler_pid,
869 action_id_,
870 file_urls));
871 }
872
873 void ExtensionTaskExecutor::ExecuteDoneOnUIThread(bool success) {
874 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
875 if (!done_.is_null())
876 done_.Run(success);
877 done_.Reset();
878 }
879
880 void ExtensionTaskExecutor::ExecuteFileActionsOnUIThread(
881 const std::string& file_system_name,
882 const GURL& file_system_root,
883 const FileDefinitionList& file_list,
884 int handler_pid) {
885 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
886
887 const Extension* extension = GetExtension();
888 if (!extension) {
889 ExecuteDoneOnUIThread(false);
890 return;
891 }
892
893 if (handler_pid > 0) {
894 SetupPermissionsAndDispatchEvent(file_system_name, file_system_root,
895 file_list, handler_pid, NULL);
896 } else {
897 // We have to wake the handler background page before we proceed.
898 extensions::LazyBackgroundTaskQueue* queue =
899 extensions::ExtensionSystem::Get(profile())->
900 lazy_background_task_queue();
901 if (!queue->ShouldEnqueueTask(profile(), extension)) {
902 ExecuteDoneOnUIThread(false);
903 return;
904 }
905 queue->AddPendingTask(
906 profile(), extension_id(),
907 base::Bind(&ExtensionTaskExecutor::SetupPermissionsAndDispatchEvent,
908 this, file_system_name, file_system_root, file_list,
909 handler_pid));
910 }
911 }
912
913 void ExtensionTaskExecutor::SetupPermissionsAndDispatchEvent(
914 const std::string& file_system_name,
915 const GURL& file_system_root,
916 const FileDefinitionList& file_list,
917 int handler_pid_in,
918 extensions::ExtensionHost* host) {
919 int handler_pid = host ? host->render_process_host()->GetID() :
920 handler_pid_in;
921
922 if (handler_pid <= 0) {
923 ExecuteDoneOnUIThread(false);
924 return;
925 }
926
927 extensions::EventRouter* event_router =
928 extensions::ExtensionSystem::Get(profile())->event_router();
929 if (!event_router) {
930 ExecuteDoneOnUIThread(false);
931 return;
932 }
933
934 const Extension* extension = GetExtension();
935 if (!extension) {
936 ExecuteDoneOnUIThread(false);
937 return;
938 }
939
940 SetupHandlerHostFileAccessPermissions(file_list, extension, handler_pid);
941
942 scoped_ptr<ListValue> event_args(new ListValue());
943 event_args->Append(new base::StringValue(action_id_));
944 DictionaryValue* details = new DictionaryValue();
945 event_args->Append(details);
946 // Get file definitions. These will be replaced with Entry instances by
947 // chromeHidden.Event.dispatchEvent() method from event_binding.js.
948 ListValue* files_urls = new ListValue();
949 details->Set("entries", files_urls);
950 for (FileDefinitionList::const_iterator iter = file_list.begin();
951 iter != file_list.end();
952 ++iter) {
953 DictionaryValue* file_def = new DictionaryValue();
954 files_urls->Append(file_def);
955 file_def->SetString("fileSystemName", file_system_name);
956 file_def->SetString("fileSystemRoot", file_system_root.spec());
957 base::FilePath root(FILE_PATH_LITERAL("/"));
958 base::FilePath full_path = root.Append(iter->virtual_path);
959 file_def->SetString("fileFullPath", full_path.value());
960 file_def->SetBoolean("fileIsDirectory", iter->is_directory);
961 }
962
963 details->SetInteger("tab_id", tab_id_);
964
965 scoped_ptr<extensions::Event> event(new extensions::Event(
966 "fileBrowserHandler.onExecute", event_args.Pass()));
967 event->restrict_to_profile = profile();
968 event_router->DispatchEventToExtension(extension_id(), event.Pass());
969
970 ExecuteDoneOnUIThread(true);
971 }
972
973 void ExtensionTaskExecutor::SetupHandlerHostFileAccessPermissions(
974 const FileDefinitionList& file_list,
975 const Extension* extension,
976 int handler_pid) {
977 for (FileDefinitionList::const_iterator iter = file_list.begin();
978 iter != file_list.end();
979 ++iter) {
980 content::ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
981 handler_pid,
982 iter->absolute_path,
983 GetAccessPermissionsForFileBrowserHandler(extension, action_id_));
984 }
985 }
986
987 AppTaskExecutor::AppTaskExecutor(
988 Profile* profile,
989 const GURL& source_url,
990 const std::string& file_browser_id,
991 const std::string& extension_id,
992 const std::string& action_id)
993 : FileTaskExecutor(profile, source_url, file_browser_id, extension_id),
994 action_id_(action_id) {
995 }
996
997 AppTaskExecutor::~AppTaskExecutor() {}
998
999 bool AppTaskExecutor::ExecuteAndNotify(
1000 const std::vector<FileSystemURL>& file_urls,
1001 const FileTaskFinishedCallback& done) {
1002 if (!FileBrowserHasAccessPermissionForFiles(file_urls))
1003 return false;
1004
1005 for (size_t i = 0; i != file_urls.size(); ++i) {
1006 extensions::LaunchPlatformAppWithFileHandler(profile(), GetExtension(),
1007 action_id_, file_urls[i].path());
1008 }
1009
1010 if (!done.is_null())
1011 done.Run(true);
1012 return true;
1013 }
1014
1015 } // namespace file_handler_util
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698