NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / drive / gdata_wapi_service.cc
blobc52f4a9fa7998dc7f48236f6e004c494b02c90ff
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.
5 #include "chrome/browser/drive/gdata_wapi_service.h"
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/values.h"
14 #include "chrome/browser/drive/drive_api_util.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "google_apis/drive/auth_service.h"
17 #include "google_apis/drive/drive_api_parser.h"
18 #include "google_apis/drive/gdata_errorcode.h"
19 #include "google_apis/drive/gdata_wapi_parser.h"
20 #include "google_apis/drive/gdata_wapi_requests.h"
21 #include "google_apis/drive/gdata_wapi_url_generator.h"
22 #include "google_apis/drive/request_sender.h"
23 #include "net/url_request/url_request_context_getter.h"
25 using content::BrowserThread;
26 using google_apis::AboutResource;
27 using google_apis::AboutResourceCallback;
28 using google_apis::AccountMetadata;
29 using google_apis::AddResourceToDirectoryRequest;
30 using google_apis::AppList;
31 using google_apis::AppListCallback;
32 using google_apis::AuthService;
33 using google_apis::AuthStatusCallback;
34 using google_apis::AuthorizeAppCallback;
35 using google_apis::AuthorizeAppRequest;
36 using google_apis::CancelCallback;
37 using google_apis::CreateDirectoryRequest;
38 using google_apis::DeleteResourceRequest;
39 using google_apis::DownloadActionCallback;
40 using google_apis::DownloadFileRequest;
41 using google_apis::EntryActionCallback;
42 using google_apis::GDATA_PARSE_ERROR;
43 using google_apis::GDataErrorCode;
44 using google_apis::GetAccountMetadataRequest;
45 using google_apis::GetContentCallback;
46 using google_apis::GetResourceEntryCallback;
47 using google_apis::GetResourceEntryRequest;
48 using google_apis::GetResourceListCallback;
49 using google_apis::GetResourceListRequest;
50 using google_apis::GetShareUrlCallback;
51 using google_apis::GetUploadStatusRequest;
52 using google_apis::HTTP_NOT_IMPLEMENTED;
53 using google_apis::InitiateUploadCallback;
54 using google_apis::InitiateUploadExistingFileRequest;
55 using google_apis::InitiateUploadNewFileRequest;
56 using google_apis::Link;
57 using google_apis::ProgressCallback;
58 using google_apis::RemoveResourceFromDirectoryRequest;
59 using google_apis::RenameResourceRequest;
60 using google_apis::RequestSender;
61 using google_apis::ResourceEntry;
62 using google_apis::ResumeUploadRequest;
63 using google_apis::SearchByTitleRequest;
64 using google_apis::UploadRangeCallback;
66 namespace drive {
68 namespace {
70 // OAuth2 scopes for the documents API.
71 const char kSpreadsheetsScope[] = "https://spreadsheets.google.com/feeds/";
72 const char kUserContentScope[] = "https://docs.googleusercontent.com/";
74 // Parses the JSON value to ResourceEntry runs |callback|.
75 void ParseResourceEntryAndRun(const GetResourceEntryCallback& callback,
76 GDataErrorCode error,
77 scoped_ptr<base::Value> value) {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
80 if (!value) {
81 callback.Run(error, scoped_ptr<ResourceEntry>());
82 return;
85 // Parsing ResourceEntry is cheap enough to do on UI thread.
86 scoped_ptr<ResourceEntry> entry =
87 google_apis::ResourceEntry::ExtractAndParse(*value);
88 if (!entry) {
89 callback.Run(GDATA_PARSE_ERROR, scoped_ptr<ResourceEntry>());
90 return;
93 callback.Run(error, entry.Pass());
96 void ConvertAboutResourceAndRun(
97 const AboutResourceCallback& callback,
98 GDataErrorCode error,
99 scoped_ptr<AccountMetadata> account_metadata) {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101 DCHECK(!callback.is_null());
103 scoped_ptr<AboutResource> about_resource;
104 if (account_metadata) {
105 about_resource = util::ConvertAccountMetadataToAboutResource(
106 *account_metadata, util::kWapiRootDirectoryResourceId);
109 callback.Run(error, about_resource.Pass());
112 void ConvertAppListAndRun(
113 const AppListCallback& callback,
114 GDataErrorCode error,
115 scoped_ptr<AccountMetadata> account_metadata) {
116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
117 DCHECK(!callback.is_null());
119 scoped_ptr<AppList> app_list;
120 if (account_metadata)
121 app_list = util::ConvertAccountMetadataToAppList(*account_metadata);
123 callback.Run(error, app_list.Pass());
126 } // namespace
128 GDataWapiService::GDataWapiService(
129 OAuth2TokenService* oauth2_token_service,
130 net::URLRequestContextGetter* url_request_context_getter,
131 base::SequencedTaskRunner* blocking_task_runner,
132 const GURL& base_url,
133 const GURL& base_download_url,
134 const std::string& custom_user_agent)
135 : oauth2_token_service_(oauth2_token_service),
136 url_request_context_getter_(url_request_context_getter),
137 blocking_task_runner_(blocking_task_runner),
138 url_generator_(base_url, base_download_url),
139 custom_user_agent_(custom_user_agent) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143 GDataWapiService::~GDataWapiService() {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145 if (sender_.get())
146 sender_->auth_service()->RemoveObserver(this);
149 void GDataWapiService::Initialize(const std::string& account_id) {
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152 std::vector<std::string> scopes;
153 scopes.push_back(util::kDocsListScope);
154 scopes.push_back(kSpreadsheetsScope);
155 scopes.push_back(kUserContentScope);
156 // Drive App scope is required for even WAPI v3 apps access.
157 scopes.push_back(util::kDriveAppsScope);
158 sender_.reset(new RequestSender(
159 new AuthService(oauth2_token_service_,
160 account_id,
161 url_request_context_getter_.get(),
162 scopes),
163 url_request_context_getter_.get(),
164 blocking_task_runner_.get(),
165 custom_user_agent_));
167 sender_->auth_service()->AddObserver(this);
170 void GDataWapiService::AddObserver(DriveServiceObserver* observer) {
171 observers_.AddObserver(observer);
174 void GDataWapiService::RemoveObserver(DriveServiceObserver* observer) {
175 observers_.RemoveObserver(observer);
178 bool GDataWapiService::CanSendRequest() const {
179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
181 return HasRefreshToken();
184 ResourceIdCanonicalizer GDataWapiService::GetResourceIdCanonicalizer() const {
185 return util::GetIdentityResourceIdCanonicalizer();
188 std::string GDataWapiService::GetRootResourceId() const {
189 return util::kWapiRootDirectoryResourceId;
192 // Because GData WAPI support is expected to be gone somehow soon by migration
193 // to the Drive API v2, so we'll reuse GetResourceListRequest to implement
194 // following methods, instead of cleaning the request class.
196 CancelCallback GDataWapiService::GetAllResourceList(
197 const GetResourceListCallback& callback) {
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
199 DCHECK(!callback.is_null());
201 return sender_->StartRequestWithRetry(
202 new GetResourceListRequest(sender_.get(),
203 url_generator_,
204 GURL(), // No override url
205 0, // start changestamp
206 std::string(), // empty search query
207 std::string(), // no directory resource id
208 callback));
211 CancelCallback GDataWapiService::GetResourceListInDirectory(
212 const std::string& directory_resource_id,
213 const GetResourceListCallback& callback) {
214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
215 DCHECK(!directory_resource_id.empty());
216 DCHECK(!callback.is_null());
218 return sender_->StartRequestWithRetry(
219 new GetResourceListRequest(sender_.get(),
220 url_generator_,
221 GURL(), // No override url
222 0, // start changestamp
223 std::string(), // empty search query
224 directory_resource_id,
225 callback));
228 CancelCallback GDataWapiService::Search(
229 const std::string& search_query,
230 const GetResourceListCallback& callback) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
232 DCHECK(!search_query.empty());
233 DCHECK(!callback.is_null());
235 return sender_->StartRequestWithRetry(
236 new GetResourceListRequest(sender_.get(),
237 url_generator_,
238 GURL(), // No override url
239 0, // start changestamp
240 search_query,
241 std::string(), // no directory resource id
242 callback));
245 CancelCallback GDataWapiService::SearchByTitle(
246 const std::string& title,
247 const std::string& directory_resource_id,
248 const GetResourceListCallback& callback) {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250 DCHECK(!title.empty());
251 DCHECK(!callback.is_null());
253 return sender_->StartRequestWithRetry(
254 new SearchByTitleRequest(sender_.get(),
255 url_generator_,
256 title,
257 directory_resource_id,
258 callback));
261 CancelCallback GDataWapiService::GetChangeList(
262 int64 start_changestamp,
263 const GetResourceListCallback& callback) {
264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
265 DCHECK(!callback.is_null());
267 return sender_->StartRequestWithRetry(
268 new GetResourceListRequest(sender_.get(),
269 url_generator_,
270 GURL(), // No override url
271 start_changestamp,
272 std::string(), // empty search query
273 std::string(), // no directory resource id
274 callback));
277 CancelCallback GDataWapiService::GetRemainingChangeList(
278 const GURL& next_link,
279 const GetResourceListCallback& callback) {
280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
281 DCHECK(!next_link.is_empty());
282 DCHECK(!callback.is_null());
284 return GetRemainingResourceList(next_link, callback);
287 CancelCallback GDataWapiService::GetRemainingFileList(
288 const GURL& next_link,
289 const GetResourceListCallback& callback) {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291 DCHECK(!next_link.is_empty());
292 DCHECK(!callback.is_null());
294 return GetRemainingResourceList(next_link, callback);
297 CancelCallback GDataWapiService::GetResourceEntry(
298 const std::string& resource_id,
299 const GetResourceEntryCallback& callback) {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
301 DCHECK(!callback.is_null());
303 return sender_->StartRequestWithRetry(
304 new GetResourceEntryRequest(sender_.get(),
305 url_generator_,
306 resource_id,
307 GURL(),
308 base::Bind(&ParseResourceEntryAndRun,
309 callback)));
312 CancelCallback GDataWapiService::GetShareUrl(
313 const std::string& resource_id,
314 const GURL& embed_origin,
315 const GetShareUrlCallback& callback) {
316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
317 DCHECK(!callback.is_null());
319 return sender_->StartRequestWithRetry(
320 new GetResourceEntryRequest(sender_.get(),
321 url_generator_,
322 resource_id,
323 embed_origin,
324 base::Bind(&util::ParseShareUrlAndRun,
325 callback)));
328 CancelCallback GDataWapiService::GetAboutResource(
329 const AboutResourceCallback& callback) {
330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
331 DCHECK(!callback.is_null());
333 return sender_->StartRequestWithRetry(
334 new GetAccountMetadataRequest(
335 sender_.get(),
336 url_generator_,
337 base::Bind(&ConvertAboutResourceAndRun, callback),
338 false)); // Exclude installed apps.
341 CancelCallback GDataWapiService::GetAppList(const AppListCallback& callback) {
342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
343 DCHECK(!callback.is_null());
345 return sender_->StartRequestWithRetry(
346 new GetAccountMetadataRequest(sender_.get(),
347 url_generator_,
348 base::Bind(&ConvertAppListAndRun, callback),
349 true)); // Include installed apps.
352 CancelCallback GDataWapiService::DownloadFile(
353 const base::FilePath& local_cache_path,
354 const std::string& resource_id,
355 const DownloadActionCallback& download_action_callback,
356 const GetContentCallback& get_content_callback,
357 const ProgressCallback& progress_callback) {
358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
359 DCHECK(!download_action_callback.is_null());
360 // get_content_callback and progress_callback may be null.
362 return sender_->StartRequestWithRetry(
363 new DownloadFileRequest(sender_.get(),
364 url_generator_,
365 download_action_callback,
366 get_content_callback,
367 progress_callback,
368 resource_id,
369 local_cache_path));
372 CancelCallback GDataWapiService::DeleteResource(
373 const std::string& resource_id,
374 const std::string& etag,
375 const EntryActionCallback& callback) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377 DCHECK(!callback.is_null());
379 NOTIMPLEMENTED();
380 callback.Run(google_apis::GDATA_OTHER_ERROR);
381 return CancelCallback();
384 CancelCallback GDataWapiService::TrashResource(
385 const std::string& resource_id,
386 const EntryActionCallback& callback) {
387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
388 DCHECK(!callback.is_null());
390 const std::string empty_etag;
391 return sender_->StartRequestWithRetry(
392 new DeleteResourceRequest(sender_.get(),
393 url_generator_,
394 callback,
395 resource_id,
396 empty_etag));
399 CancelCallback GDataWapiService::AddNewDirectory(
400 const std::string& parent_resource_id,
401 const std::string& directory_title,
402 const AddNewDirectoryOptions& options,
403 const GetResourceEntryCallback& callback) {
404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405 DCHECK(!callback.is_null());
407 return sender_->StartRequestWithRetry(
408 new CreateDirectoryRequest(sender_.get(),
409 url_generator_,
410 base::Bind(&ParseResourceEntryAndRun,
411 callback),
412 parent_resource_id,
413 directory_title));
416 CancelCallback GDataWapiService::CopyResource(
417 const std::string& resource_id,
418 const std::string& parent_resource_id,
419 const std::string& new_title,
420 const base::Time& last_modified,
421 const GetResourceEntryCallback& callback) {
422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
423 DCHECK(!callback.is_null());
425 // GData WAPI doesn't support "copy" of regular files.
426 // This method should never be called if GData WAPI is enabled.
427 // Instead, client code should download the file (if needed) and upload it.
428 NOTREACHED();
429 return CancelCallback();
432 CancelCallback GDataWapiService::UpdateResource(
433 const std::string& resource_id,
434 const std::string& parent_resource_id,
435 const std::string& new_title,
436 const base::Time& last_modified,
437 const base::Time& last_viewed_by_me,
438 const google_apis::GetResourceEntryCallback& callback) {
439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
440 DCHECK(!callback.is_null());
442 // GData WAPI doesn't support to "move" resources.
443 // This method should never be called if GData WAPI is enabled.
444 // Instead, client code should rename the file, add new parent, and then
445 // remove the old parent.
446 NOTREACHED();
447 return CancelCallback();
450 CancelCallback GDataWapiService::RenameResource(
451 const std::string& resource_id,
452 const std::string& new_title,
453 const EntryActionCallback& callback) {
454 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
455 DCHECK(!callback.is_null());
457 return sender_->StartRequestWithRetry(
458 new RenameResourceRequest(sender_.get(),
459 url_generator_,
460 callback,
461 resource_id,
462 new_title));
465 CancelCallback GDataWapiService::AddResourceToDirectory(
466 const std::string& parent_resource_id,
467 const std::string& resource_id,
468 const EntryActionCallback& callback) {
469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
470 DCHECK(!callback.is_null());
472 return sender_->StartRequestWithRetry(
473 new AddResourceToDirectoryRequest(sender_.get(),
474 url_generator_,
475 callback,
476 parent_resource_id,
477 resource_id));
480 CancelCallback GDataWapiService::RemoveResourceFromDirectory(
481 const std::string& parent_resource_id,
482 const std::string& resource_id,
483 const EntryActionCallback& callback) {
484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
485 DCHECK(!callback.is_null());
487 return sender_->StartRequestWithRetry(
488 new RemoveResourceFromDirectoryRequest(sender_.get(),
489 url_generator_,
490 callback,
491 parent_resource_id,
492 resource_id));
495 CancelCallback GDataWapiService::InitiateUploadNewFile(
496 const std::string& content_type,
497 int64 content_length,
498 const std::string& parent_resource_id,
499 const std::string& title,
500 const InitiateUploadNewFileOptions& options,
501 const InitiateUploadCallback& callback) {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503 DCHECK(!callback.is_null());
504 DCHECK(!parent_resource_id.empty());
506 return sender_->StartRequestWithRetry(
507 new InitiateUploadNewFileRequest(sender_.get(),
508 url_generator_,
509 callback,
510 content_type,
511 content_length,
512 parent_resource_id,
513 title));
516 CancelCallback GDataWapiService::InitiateUploadExistingFile(
517 const std::string& content_type,
518 int64 content_length,
519 const std::string& resource_id,
520 const InitiateUploadExistingFileOptions& options,
521 const InitiateUploadCallback& callback) {
522 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
523 DCHECK(!callback.is_null());
524 DCHECK(!resource_id.empty());
526 return sender_->StartRequestWithRetry(
527 new InitiateUploadExistingFileRequest(sender_.get(),
528 url_generator_,
529 callback,
530 content_type,
531 content_length,
532 resource_id,
533 options.etag));
536 CancelCallback GDataWapiService::ResumeUpload(
537 const GURL& upload_url,
538 int64 start_position,
539 int64 end_position,
540 int64 content_length,
541 const std::string& content_type,
542 const base::FilePath& local_file_path,
543 const UploadRangeCallback& callback,
544 const ProgressCallback& progress_callback) {
545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
546 DCHECK(!callback.is_null());
548 return sender_->StartRequestWithRetry(
549 new ResumeUploadRequest(sender_.get(),
550 callback,
551 progress_callback,
552 upload_url,
553 start_position,
554 end_position,
555 content_length,
556 content_type,
557 local_file_path));
560 CancelCallback GDataWapiService::GetUploadStatus(
561 const GURL& upload_url,
562 int64 content_length,
563 const UploadRangeCallback& callback) {
564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
565 DCHECK(!callback.is_null());
567 return sender_->StartRequestWithRetry(
568 new GetUploadStatusRequest(sender_.get(),
569 callback,
570 upload_url,
571 content_length));
574 CancelCallback GDataWapiService::AuthorizeApp(
575 const std::string& resource_id,
576 const std::string& app_id,
577 const AuthorizeAppCallback& callback) {
578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
579 DCHECK(!callback.is_null());
581 return sender_->StartRequestWithRetry(
582 new AuthorizeAppRequest(sender_.get(),
583 url_generator_,
584 callback,
585 resource_id,
586 app_id));
589 CancelCallback GDataWapiService::UninstallApp(
590 const std::string& app_id,
591 const EntryActionCallback& callback) {
592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
593 DCHECK(!callback.is_null());
595 // GData WAPI doesn't support app uninstallation.
596 // This method should never be called if GData WAPI is enabled.
597 NOTREACHED();
598 return CancelCallback();
601 CancelCallback GDataWapiService::GetResourceListInDirectoryByWapi(
602 const std::string& directory_resource_id,
603 const google_apis::GetResourceListCallback& callback) {
604 return GetResourceListInDirectory(directory_resource_id, callback);
607 CancelCallback GDataWapiService::GetRemainingResourceList(
608 const GURL& next_link,
609 const google_apis::GetResourceListCallback& callback) {
610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
611 DCHECK(!next_link.is_empty());
612 DCHECK(!callback.is_null());
614 return sender_->StartRequestWithRetry(
615 new GetResourceListRequest(sender_.get(),
616 url_generator_,
617 next_link,
618 0, // start changestamp
619 std::string(), // empty search query
620 std::string(), // no directory resource id
621 callback));
624 bool GDataWapiService::HasAccessToken() const {
625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
627 return sender_->auth_service()->HasAccessToken();
630 void GDataWapiService::RequestAccessToken(const AuthStatusCallback& callback) {
631 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
632 DCHECK(!callback.is_null());
634 const std::string access_token = sender_->auth_service()->access_token();
635 if (!access_token.empty()) {
636 callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token);
637 return;
640 // Retrieve the new auth token.
641 sender_->auth_service()->StartAuthentication(callback);
644 bool GDataWapiService::HasRefreshToken() const {
645 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
646 return sender_->auth_service()->HasRefreshToken();
649 void GDataWapiService::ClearAccessToken() {
650 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
651 sender_->auth_service()->ClearAccessToken();
654 void GDataWapiService::ClearRefreshToken() {
655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
656 sender_->auth_service()->ClearRefreshToken();
659 void GDataWapiService::OnOAuth2RefreshTokenChanged() {
660 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
661 if (CanSendRequest()) {
662 FOR_EACH_OBSERVER(
663 DriveServiceObserver, observers_, OnReadyToSendRequests());
664 } else if (!HasRefreshToken()) {
665 FOR_EACH_OBSERVER(
666 DriveServiceObserver, observers_, OnRefreshTokenInvalid());
670 } // namespace drive