private_api_drive.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1// Copyright 2013 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_manager/private_api_drive.h"
6
7#include "base/prefs/pref_service.h"
8#include "base/strings/stringprintf.h"
9#include "chrome/browser/chromeos/drive/drive_app_registry.h"
10#include "chrome/browser/chromeos/drive/drive_integration_service.h"
11#include "chrome/browser/chromeos/drive/logging.h"
12#include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
13#include "chrome/browser/chromeos/file_manager/file_tasks.h"
14#include "chrome/browser/chromeos/file_manager/url_util.h"
15#include "chrome/browser/chromeos/fileapi/file_system_backend.h"
16#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/common/extensions/api/file_browser_private.h"
19#include "chrome/common/pref_names.h"
20#include "content/public/browser/browser_thread.h"
21#include "content/public/browser/render_view_host.h"
22#include "webkit/common/fileapi/file_system_info.h"
23#include "webkit/common/fileapi/file_system_util.h"
24
25using content::BrowserThread;
26
27namespace extensions {
28namespace {
29
30// List of connection types of drive.
31// Keep this in sync with the DriveConnectionType in volume_manager.js.
32const char kDriveConnectionTypeOffline[] = "offline";
33const char kDriveConnectionTypeMetered[] = "metered";
34const char kDriveConnectionTypeOnline[] = "online";
35
36// List of reasons of kDriveConnectionType*.
37// Keep this in sync with the DriveConnectionReason in volume_manager.js.
38const char kDriveConnectionReasonNotReady[] = "not_ready";
39const char kDriveConnectionReasonNoNetwork[] = "no_network";
40const char kDriveConnectionReasonNoService[] = "no_service";
41
42// Does nothing with a bool parameter. Used as a placeholder for calling
43// ClearCacheAndRemountFileSystem(). TODO(yoshiki): Handle an error from
44// ClearCacheAndRemountFileSystem() properly: http://crbug.com/140511.
45void DoNothingWithBool(bool /* success */) {
46}
47
48// Copies properties from |entry_proto| to |properties|.
49void FillDriveEntryPropertiesValue(
50    const drive::ResourceEntry& entry_proto,
51    api::file_browser_private::DriveEntryProperties* properties) {
52  properties->shared_with_me.reset(new bool(entry_proto.shared_with_me()));
53
54  if (!entry_proto.has_file_specific_info())
55    return;
56
57  const drive::FileSpecificInfo& file_specific_info =
58      entry_proto.file_specific_info();
59
60  properties->thumbnail_url.reset(
61      new std::string("https://www.googledrive.com/thumb/" +
62          entry_proto.resource_id() + "?width=500&height=500"));
63  if (file_specific_info.has_image_width()) {
64    properties->image_width.reset(
65        new int(file_specific_info.image_width()));
66  }
67  if (file_specific_info.has_image_height()) {
68    properties->image_height.reset(
69        new int(file_specific_info.image_height()));
70  }
71  if (file_specific_info.has_image_rotation()) {
72    properties->image_rotation.reset(
73        new int(file_specific_info.image_rotation()));
74  }
75  properties->is_hosted.reset(
76      new bool(file_specific_info.is_hosted_document()));
77  properties->content_mime_type.reset(
78      new std::string(file_specific_info.content_mime_type()));
79}
80
81}  // namespace
82
83FileBrowserPrivateGetDriveEntryPropertiesFunction::
84    FileBrowserPrivateGetDriveEntryPropertiesFunction() {
85}
86
87FileBrowserPrivateGetDriveEntryPropertiesFunction::
88    ~FileBrowserPrivateGetDriveEntryPropertiesFunction() {
89}
90
91bool FileBrowserPrivateGetDriveEntryPropertiesFunction::RunImpl() {
92  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
93
94  using extensions::api::file_browser_private::GetDriveEntryProperties::Params;
95  const scoped_ptr<Params> params(Params::Create(*args_));
96  EXTENSION_FUNCTION_VALIDATE(params);
97
98  const GURL file_url = GURL(params->file_url);
99  file_path_ =
100      drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL(
101          render_view_host(), GetProfile(), file_url));
102
103  properties_.reset(new extensions::api::file_browser_private::
104                    DriveEntryProperties);
105
106  // Start getting the file info.
107  drive::FileSystemInterface* file_system =
108      drive::util::GetFileSystemByProfile(GetProfile());
109  if (!file_system) {
110    // |file_system| is NULL if Drive is disabled or not mounted.
111    CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
112    return true;
113  }
114
115  file_system->GetResourceEntryByPath(
116      file_path_,
117      base::Bind(&FileBrowserPrivateGetDriveEntryPropertiesFunction::
118                     OnGetFileInfo, this));
119  return true;
120}
121
122void FileBrowserPrivateGetDriveEntryPropertiesFunction::OnGetFileInfo(
123    drive::FileError error,
124    scoped_ptr<drive::ResourceEntry> entry) {
125  DCHECK(properties_);
126
127  if (error != drive::FILE_ERROR_OK) {
128    CompleteGetFileProperties(error);
129    return;
130  }
131  DCHECK(entry);
132
133  FillDriveEntryPropertiesValue(*entry, properties_.get());
134
135  drive::FileSystemInterface* file_system =
136      drive::util::GetFileSystemByProfile(GetProfile());
137  drive::DriveAppRegistry* app_registry =
138      drive::util::GetDriveAppRegistryByProfile(GetProfile());
139  if (!file_system || !app_registry) {
140    // |file_system| or |app_registry| is NULL if Drive is disabled.
141    CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
142    return;
143  }
144
145  // The properties meaningful for directories are already filled in
146  // FillDriveEntryPropertiesValue().
147  if (entry.get() && !entry->has_file_specific_info()) {
148    CompleteGetFileProperties(error);
149    return;
150  }
151
152  const drive::FileSpecificInfo& file_specific_info =
153      entry->file_specific_info();
154
155  // Get drive WebApps that can accept this file. We just need to extract the
156  // doc icon for the drive app, which is set as default.
157  ScopedVector<drive::DriveAppInfo> drive_apps;
158  app_registry->GetAppsForFile(file_path_.Extension(),
159                               file_specific_info.content_mime_type(),
160                               &drive_apps);
161  if (!drive_apps.empty()) {
162    std::string default_task_id =
163        file_manager::file_tasks::GetDefaultTaskIdFromPrefs(
164            *GetProfile()->GetPrefs(),
165            file_specific_info.content_mime_type(),
166            file_path_.Extension());
167    file_manager::file_tasks::TaskDescriptor default_task;
168    file_manager::file_tasks::ParseTaskID(default_task_id, &default_task);
169    DCHECK(default_task_id.empty() || !default_task.app_id.empty());
170    for (size_t i = 0; i < drive_apps.size(); ++i) {
171      const drive::DriveAppInfo* app_info = drive_apps[i];
172      if (default_task.app_id == app_info->app_id) {
173        // The drive app is set as default. Files.app should use the doc icon.
174        const GURL doc_icon =
175            drive::util::FindPreferredIcon(app_info->document_icons,
176                                           drive::util::kPreferredIconSize);
177        properties_->custom_icon_url.reset(new std::string(doc_icon.spec()));
178      }
179    }
180  }
181
182  file_system->GetCacheEntryByPath(
183      file_path_,
184      base::Bind(&FileBrowserPrivateGetDriveEntryPropertiesFunction::
185                     CacheStateReceived, this));
186}
187
188void FileBrowserPrivateGetDriveEntryPropertiesFunction::CacheStateReceived(
189    bool /* success */,
190    const drive::FileCacheEntry& cache_entry) {
191  // In case of an error (i.e. success is false), cache_entry.is_*() all
192  // returns false.
193  properties_->is_pinned.reset(new bool(cache_entry.is_pinned()));
194  properties_->is_present.reset(new bool(cache_entry.is_present()));
195
196  CompleteGetFileProperties(drive::FILE_ERROR_OK);
197}
198
199void FileBrowserPrivateGetDriveEntryPropertiesFunction::
200    CompleteGetFileProperties(drive::FileError error) {
201  results_ = extensions::api::file_browser_private::GetDriveEntryProperties::
202      Results::Create(*properties_);
203  SendResponse(true);
204}
205
206bool FileBrowserPrivatePinDriveFileFunction::RunImpl() {
207  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208
209  using extensions::api::file_browser_private::PinDriveFile::Params;
210  const scoped_ptr<Params> params(Params::Create(*args_));
211  EXTENSION_FUNCTION_VALIDATE(params);
212
213  drive::FileSystemInterface* const file_system =
214      drive::util::GetFileSystemByProfile(GetProfile());
215  if (!file_system)  // |file_system| is NULL if Drive is disabled.
216    return false;
217
218  const base::FilePath drive_path =
219      drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL(
220          render_view_host(), GetProfile(), GURL(params->file_url)));
221  if (params->pin) {
222    file_system->Pin(drive_path,
223                     base::Bind(&FileBrowserPrivatePinDriveFileFunction::
224                                    OnPinStateSet, this));
225  } else {
226    file_system->Unpin(drive_path,
227                       base::Bind(&FileBrowserPrivatePinDriveFileFunction::
228                                      OnPinStateSet, this));
229  }
230  return true;
231}
232
233void FileBrowserPrivatePinDriveFileFunction::
234    OnPinStateSet(drive::FileError error) {
235  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
236
237  if (error == drive::FILE_ERROR_OK) {
238    SendResponse(true);
239  } else {
240    error_ = drive::FileErrorToString(error);
241    SendResponse(false);
242  }
243}
244
245FileBrowserPrivateGetDriveFilesFunction::
246    FileBrowserPrivateGetDriveFilesFunction() {
247}
248
249FileBrowserPrivateGetDriveFilesFunction::
250    ~FileBrowserPrivateGetDriveFilesFunction() {
251}
252
253bool FileBrowserPrivateGetDriveFilesFunction::RunImpl() {
254  using extensions::api::file_browser_private::GetDriveFiles::Params;
255  const scoped_ptr<Params> params(Params::Create(*args_));
256  EXTENSION_FUNCTION_VALIDATE(params);
257
258  // Convert the list of strings to a list of GURLs.
259  for (size_t i = 0; i < params->file_urls.size(); ++i) {
260    const base::FilePath path = file_manager::util::GetLocalPathFromURL(
261        render_view_host(), GetProfile(), GURL(params->file_urls[i]));
262    DCHECK(drive::util::IsUnderDriveMountPoint(path));
263    base::FilePath drive_path = drive::util::ExtractDrivePath(path);
264    remaining_drive_paths_.push(drive_path);
265  }
266
267  GetFileOrSendResponse();
268  return true;
269}
270
271void FileBrowserPrivateGetDriveFilesFunction::GetFileOrSendResponse() {
272  // Send the response if all files are obtained.
273  if (remaining_drive_paths_.empty()) {
274    results_ = extensions::api::file_browser_private::
275        GetDriveFiles::Results::Create(local_paths_);
276    SendResponse(true);
277    return;
278  }
279
280  // Get the file on the top of the queue.
281  base::FilePath drive_path = remaining_drive_paths_.front();
282
283  drive::FileSystemInterface* file_system =
284      drive::util::GetFileSystemByProfile(GetProfile());
285  if (!file_system) {
286    // |file_system| is NULL if Drive is disabled or not mounted.
287    OnFileReady(drive::FILE_ERROR_FAILED, drive_path,
288                scoped_ptr<drive::ResourceEntry>());
289    return;
290  }
291
292  file_system->GetFileByPath(
293      drive_path,
294      base::Bind(&FileBrowserPrivateGetDriveFilesFunction::OnFileReady, this));
295}
296
297
298void FileBrowserPrivateGetDriveFilesFunction::OnFileReady(
299    drive::FileError error,
300    const base::FilePath& local_path,
301    scoped_ptr<drive::ResourceEntry> entry) {
302  base::FilePath drive_path = remaining_drive_paths_.front();
303
304  if (error == drive::FILE_ERROR_OK) {
305    local_paths_.push_back(local_path.AsUTF8Unsafe());
306    DVLOG(1) << "Got " << drive_path.value() << " as " << local_path.value();
307
308    // TODO(benchan): If the file is a hosted document, a temporary JSON file
309    // is created to represent the document. The JSON file is not cached and
310    // should be deleted after use. We need to somehow communicate with
311    // file_manager.js to manage the lifetime of the temporary file.
312    // See crosbug.com/28058.
313  } else {
314    local_paths_.push_back("");
315    DVLOG(1) << "Failed to get " << drive_path.value()
316             << " with error code: " << error;
317  }
318
319  remaining_drive_paths_.pop();
320
321  // Start getting the next file.
322  GetFileOrSendResponse();
323}
324
325bool FileBrowserPrivateCancelFileTransfersFunction::RunImpl() {
326  using extensions::api::file_browser_private::CancelFileTransfers::Params;
327  const scoped_ptr<Params> params(Params::Create(*args_));
328  EXTENSION_FUNCTION_VALIDATE(params);
329
330  drive::DriveIntegrationService* integration_service =
331      drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile());
332  if (!integration_service || !integration_service->IsMounted())
333    return false;
334
335  // Create the mapping from file path to job ID.
336  drive::JobListInterface* job_list = integration_service->job_list();
337  DCHECK(job_list);
338  std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList();
339
340  typedef std::map<base::FilePath, std::vector<drive::JobID> > PathToIdMap;
341  PathToIdMap path_to_id_map;
342  for (size_t i = 0; i < jobs.size(); ++i) {
343    if (drive::IsActiveFileTransferJobInfo(jobs[i]))
344      path_to_id_map[jobs[i].file_path].push_back(jobs[i].job_id);
345  }
346
347  // Cancel by Job ID.
348  std::vector<linked_ptr<api::file_browser_private::
349                         FileTransferCancelStatus> > responses;
350  for (size_t i = 0; i < params->file_urls.size(); ++i) {
351    base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
352        render_view_host(), GetProfile(), GURL(params->file_urls[i]));
353    if (file_path.empty())
354      continue;
355
356    DCHECK(drive::util::IsUnderDriveMountPoint(file_path));
357    file_path = drive::util::ExtractDrivePath(file_path);
358
359    // Cancel all the jobs for the file.
360    PathToIdMap::iterator it = path_to_id_map.find(file_path);
361    if (it != path_to_id_map.end()) {
362      for (size_t i = 0; i < it->second.size(); ++i)
363        job_list->CancelJob(it->second[i]);
364    }
365    linked_ptr<api::file_browser_private::FileTransferCancelStatus> result(
366        new api::file_browser_private::FileTransferCancelStatus);
367    result->canceled = it != path_to_id_map.end();
368    // TODO(kinaba): simplify cancelFileTransfer() to take single URL each time,
369    // and eliminate this field; it is just returning a copy of the argument.
370    result->file_url = params->file_urls[i];
371    responses.push_back(result);
372  }
373  results_ = api::file_browser_private::CancelFileTransfers::Results::Create(
374      responses);
375  SendResponse(true);
376  return true;
377}
378
379bool FileBrowserPrivateSearchDriveFunction::RunImpl() {
380  using extensions::api::file_browser_private::SearchDrive::Params;
381  const scoped_ptr<Params> params(Params::Create(*args_));
382  EXTENSION_FUNCTION_VALIDATE(params);
383
384  drive::FileSystemInterface* const file_system =
385      drive::util::GetFileSystemByProfile(GetProfile());
386  if (!file_system) {
387    // |file_system| is NULL if Drive is disabled.
388    return false;
389  }
390
391  file_system->Search(
392      params->search_params.query, GURL(params->search_params.next_feed),
393      base::Bind(&FileBrowserPrivateSearchDriveFunction::OnSearch, this));
394  return true;
395}
396
397void FileBrowserPrivateSearchDriveFunction::OnSearch(
398    drive::FileError error,
399    const GURL& next_link,
400    scoped_ptr<std::vector<drive::SearchResultInfo> > results) {
401  if (error != drive::FILE_ERROR_OK) {
402    SendResponse(false);
403    return;
404  }
405
406  DCHECK(results.get());
407
408  base::ListValue* entries = new ListValue();
409
410  // Convert Drive files to something File API stack can understand.
411  fileapi::FileSystemInfo info =
412      fileapi::GetFileSystemInfoForChromeOS(source_url_.GetOrigin());
413  for (size_t i = 0; i < results->size(); ++i) {
414    DictionaryValue* entry = new DictionaryValue();
415    entry->SetString("fileSystemName", info.name);
416    entry->SetString("fileSystemRoot", info.root_url.spec());
417    entry->SetString("fileFullPath", "/" + results->at(i).path.value());
418    entry->SetBoolean("fileIsDirectory", results->at(i).is_directory);
419    entries->Append(entry);
420  }
421
422  base::DictionaryValue* result = new DictionaryValue();
423  result->Set("entries", entries);
424  result->SetString("nextFeed", next_link.spec());
425
426  SetResult(result);
427  SendResponse(true);
428}
429
430bool FileBrowserPrivateSearchDriveMetadataFunction::RunImpl() {
431  using extensions::api::file_browser_private::SearchDriveMetadata::Params;
432  const scoped_ptr<Params> params(Params::Create(*args_));
433  EXTENSION_FUNCTION_VALIDATE(params);
434
435  drive::util::Log(logging::LOG_INFO,
436                   "%s[%d] called. (types: '%s', maxResults: '%d')",
437                   name().c_str(),
438                   request_id(),
439                   Params::SearchParams::ToString(
440                       params->search_params.types).c_str(),
441                   params->search_params.max_results);
442  set_log_on_completion(true);
443
444  drive::FileSystemInterface* const file_system =
445      drive::util::GetFileSystemByProfile(GetProfile());
446  if (!file_system) {
447    // |file_system| is NULL if Drive is disabled.
448    return false;
449  }
450
451  int options = -1;
452  switch (params->search_params.types) {
453    case Params::SearchParams::TYPES_EXCLUDE_DIRECTORIES:
454      options = drive::SEARCH_METADATA_EXCLUDE_DIRECTORIES;
455      break;
456    case Params::SearchParams::TYPES_SHARED_WITH_ME:
457      options = drive::SEARCH_METADATA_SHARED_WITH_ME;
458      break;
459    case Params::SearchParams::TYPES_OFFLINE:
460      options = drive::SEARCH_METADATA_OFFLINE;
461      break;
462    case Params::SearchParams::TYPES_ALL:
463      options = drive::SEARCH_METADATA_ALL;
464      break;
465    case Params::SearchParams::TYPES_NONE:
466      break;
467  }
468  DCHECK_NE(options, -1);
469
470  file_system->SearchMetadata(
471      params->search_params.query,
472      options,
473      params->search_params.max_results,
474      base::Bind(&FileBrowserPrivateSearchDriveMetadataFunction::
475                     OnSearchMetadata, this));
476  return true;
477}
478
479void FileBrowserPrivateSearchDriveMetadataFunction::OnSearchMetadata(
480    drive::FileError error,
481    scoped_ptr<drive::MetadataSearchResultVector> results) {
482  if (error != drive::FILE_ERROR_OK) {
483    SendResponse(false);
484    return;
485  }
486
487  DCHECK(results.get());
488
489  base::ListValue* results_list = new ListValue();
490
491  // Convert Drive files to something File API stack can understand.  See
492  // file_browser_handler_custom_bindings.cc and
493  // file_browser_private_custom_bindings.js for how this is magically
494  // converted to a FileEntry.
495  fileapi::FileSystemInfo info =
496      fileapi::GetFileSystemInfoForChromeOS(source_url_.GetOrigin());
497  for (size_t i = 0; i < results->size(); ++i) {
498    DictionaryValue* result_dict = new DictionaryValue();
499
500    // FileEntry fields.
501    DictionaryValue* entry = new DictionaryValue();
502    entry->SetString("fileSystemName", info.name);
503    entry->SetString("fileSystemRoot", info.root_url.spec());
504    entry->SetString("fileFullPath", "/" + results->at(i).path.value());
505    entry->SetBoolean("fileIsDirectory",
506                      results->at(i).entry.file_info().is_directory());
507
508    result_dict->Set("entry", entry);
509    result_dict->SetString("highlightedBaseName",
510                           results->at(i).highlighted_base_name);
511    results_list->Append(result_dict);
512  }
513
514  SetResult(results_list);
515  SendResponse(true);
516}
517
518bool FileBrowserPrivateClearDriveCacheFunction::RunImpl() {
519  drive::DriveIntegrationService* integration_service =
520      drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile());
521  if (!integration_service || !integration_service->IsMounted())
522    return false;
523
524  // TODO(yoshiki): Receive a callback from JS-side and pass it to
525  // ClearCacheAndRemountFileSystem(). http://crbug.com/140511
526  integration_service->ClearCacheAndRemountFileSystem(
527      base::Bind(&DoNothingWithBool));
528
529  SendResponse(true);
530  return true;
531}
532
533bool FileBrowserPrivateGetDriveConnectionStateFunction::RunImpl() {
534  drive::DriveServiceInterface* const drive_service =
535      drive::util::GetDriveServiceByProfile(GetProfile());
536
537  api::file_browser_private::GetDriveConnectionState::Results::Result result;
538
539  const bool ready = drive_service && drive_service->CanSendRequest();
540  const bool is_connection_cellular =
541      net::NetworkChangeNotifier::IsConnectionCellular(
542          net::NetworkChangeNotifier::GetConnectionType());
543
544  if (net::NetworkChangeNotifier::IsOffline() || !ready) {
545    result.type = kDriveConnectionTypeOffline;
546    if (net::NetworkChangeNotifier::IsOffline())
547      result.reasons.push_back(kDriveConnectionReasonNoNetwork);
548    if (!ready)
549      result.reasons.push_back(kDriveConnectionReasonNotReady);
550    if (!drive_service)
551      result.reasons.push_back(kDriveConnectionReasonNoService);
552  } else if (
553      is_connection_cellular &&
554      GetProfile()->GetPrefs()->GetBoolean(
555        prefs::kDisableDriveOverCellular)) {
556    result.type = kDriveConnectionTypeMetered;
557  } else {
558    result.type = kDriveConnectionTypeOnline;
559  }
560
561  results_ = api::file_browser_private::GetDriveConnectionState::Results::
562      Create(result);
563
564  drive::util::Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
565  return true;
566}
567
568bool FileBrowserPrivateRequestAccessTokenFunction::RunImpl() {
569  using extensions::api::file_browser_private::RequestAccessToken::Params;
570  const scoped_ptr<Params> params(Params::Create(*args_));
571  EXTENSION_FUNCTION_VALIDATE(params);
572
573  drive::DriveServiceInterface* const drive_service =
574      drive::util::GetDriveServiceByProfile(GetProfile());
575
576  if (!drive_service) {
577    // DriveService is not available.
578    SetResult(new base::StringValue(""));
579    SendResponse(true);
580    return true;
581  }
582
583  // If refreshing is requested, then clear the token to refetch it.
584  if (params->refresh)
585    drive_service->ClearAccessToken();
586
587  // Retrieve the cached auth token (if available), otherwise the AuthService
588  // instance will try to refetch it.
589  drive_service->RequestAccessToken(
590      base::Bind(&FileBrowserPrivateRequestAccessTokenFunction::
591                      OnAccessTokenFetched, this));
592  return true;
593}
594
595void FileBrowserPrivateRequestAccessTokenFunction::OnAccessTokenFetched(
596    google_apis::GDataErrorCode code,
597    const std::string& access_token) {
598  SetResult(new base::StringValue(access_token));
599  SendResponse(true);
600}
601
602bool FileBrowserPrivateGetShareUrlFunction::RunImpl() {
603  using extensions::api::file_browser_private::GetShareUrl::Params;
604  const scoped_ptr<Params> params(Params::Create(*args_));
605  EXTENSION_FUNCTION_VALIDATE(params);
606
607  const base::FilePath path = file_manager::util::GetLocalPathFromURL(
608      render_view_host(), GetProfile(), GURL(params->url));
609  DCHECK(drive::util::IsUnderDriveMountPoint(path));
610
611  const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
612
613  drive::FileSystemInterface* const file_system =
614      drive::util::GetFileSystemByProfile(GetProfile());
615  if (!file_system) {
616    // |file_system| is NULL if Drive is disabled.
617    return false;
618  }
619
620  file_system->GetShareUrl(
621      drive_path,
622      file_manager::util::GetFileManagerBaseUrl(),  // embed origin
623      base::Bind(&FileBrowserPrivateGetShareUrlFunction::OnGetShareUrl, this));
624  return true;
625}
626
627void FileBrowserPrivateGetShareUrlFunction::OnGetShareUrl(
628    drive::FileError error,
629    const GURL& share_url) {
630  if (error != drive::FILE_ERROR_OK) {
631    error_ = "Share Url for this item is not available.";
632    SendResponse(false);
633    return;
634  }
635
636  SetResult(new base::StringValue(share_url.spec()));
637  SendResponse(true);
638}
639
640}  // namespace extensions
641