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