OLD | NEW |
| (Empty) |
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/sync_file_system/drive_backend/api_util.h" | |
6 | |
7 #include <algorithm> | |
8 #include <functional> | |
9 #include <sstream> | |
10 #include <string> | |
11 | |
12 #include "base/file_util.h" | |
13 #include "base/strings/string_util.h" | |
14 #include "base/strings/utf_string_conversions.h" | |
15 #include "base/threading/sequenced_worker_pool.h" | |
16 #include "base/values.h" | |
17 #include "chrome/browser/drive/drive_api_service.h" | |
18 #include "chrome/browser/drive/drive_api_util.h" | |
19 #include "chrome/browser/drive/drive_uploader.h" | |
20 #include "chrome/browser/drive/gdata_wapi_service.h" | |
21 #include "chrome/browser/google_apis/drive_api_parser.h" | |
22 #include "chrome/browser/profiles/profile.h" | |
23 #include "chrome/browser/signin/profile_oauth2_token_service.h" | |
24 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" | |
25 #include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_util.h" | |
26 #include "chrome/browser/sync_file_system/logger.h" | |
27 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" | |
28 #include "chrome/common/extensions/extension.h" | |
29 #include "content/public/browser/browser_thread.h" | |
30 #include "extensions/common/constants.h" | |
31 #include "net/base/mime_util.h" | |
32 | |
33 namespace sync_file_system { | |
34 namespace drive_backend { | |
35 | |
36 namespace { | |
37 | |
38 enum ParentType { | |
39 PARENT_TYPE_ROOT_OR_EMPTY, | |
40 PARENT_TYPE_DIRECTORY, | |
41 }; | |
42 | |
43 const char kSyncRootDirectoryName[] = "Chrome Syncable FileSystem"; | |
44 const char kSyncRootDirectoryNameDev[] = "Chrome Syncable FileSystem Dev"; | |
45 const char kMimeTypeOctetStream[] = "application/octet-stream"; | |
46 | |
47 const char kFakeServerBaseUrl[] = "https://fake_server/"; | |
48 const char kFakeDownloadServerBaseUrl[] = "https://fake_download_server/"; | |
49 | |
50 void EmptyGDataErrorCodeCallback(google_apis::GDataErrorCode error) {} | |
51 | |
52 bool HasParentLinkTo(const ScopedVector<google_apis::Link>& links, | |
53 const std::string& parent_resource_id, | |
54 ParentType parent_type) { | |
55 bool has_parent = false; | |
56 | |
57 for (ScopedVector<google_apis::Link>::const_iterator itr = links.begin(); | |
58 itr != links.end(); ++itr) { | |
59 if ((*itr)->type() == google_apis::Link::LINK_PARENT) { | |
60 has_parent = true; | |
61 if (drive::util::ExtractResourceIdFromUrl((*itr)->href()) == | |
62 parent_resource_id) | |
63 return true; | |
64 } | |
65 } | |
66 | |
67 return parent_type == PARENT_TYPE_ROOT_OR_EMPTY && !has_parent; | |
68 } | |
69 | |
70 struct TitleAndParentQuery | |
71 : std::unary_function<const google_apis::ResourceEntry*, bool> { | |
72 TitleAndParentQuery(const std::string& title, | |
73 const std::string& parent_resource_id, | |
74 ParentType parent_type) | |
75 : title(title), | |
76 parent_resource_id(parent_resource_id), | |
77 parent_type(parent_type) {} | |
78 | |
79 bool operator()(const google_apis::ResourceEntry* entry) const { | |
80 return entry->title() == title && | |
81 HasParentLinkTo(entry->links(), parent_resource_id, parent_type); | |
82 } | |
83 | |
84 const std::string& title; | |
85 const std::string& parent_resource_id; | |
86 ParentType parent_type; | |
87 }; | |
88 | |
89 void FilterEntriesByTitleAndParent( | |
90 ScopedVector<google_apis::ResourceEntry>* entries, | |
91 const std::string& title, | |
92 const std::string& parent_resource_id, | |
93 ParentType parent_type) { | |
94 typedef ScopedVector<google_apis::ResourceEntry>::iterator iterator; | |
95 iterator itr = std::partition(entries->begin(), | |
96 entries->end(), | |
97 TitleAndParentQuery(title, | |
98 parent_resource_id, | |
99 parent_type)); | |
100 entries->erase(itr, entries->end()); | |
101 } | |
102 | |
103 google_apis::ResourceEntry* GetDocumentByTitleAndParent( | |
104 const ScopedVector<google_apis::ResourceEntry>& entries, | |
105 const std::string& title, | |
106 const std::string& parent_resource_id, | |
107 ParentType parent_type) { | |
108 typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator; | |
109 iterator found = | |
110 std::find_if(entries.begin(), | |
111 entries.end(), | |
112 TitleAndParentQuery(title, parent_resource_id, parent_type)); | |
113 if (found != entries.end()) | |
114 return *found; | |
115 return NULL; | |
116 } | |
117 | |
118 void EntryAdapterForEnsureTitleUniqueness( | |
119 scoped_ptr<google_apis::ResourceEntry> entry, | |
120 const APIUtil::EnsureUniquenessCallback& callback, | |
121 APIUtil::EnsureUniquenessStatus status, | |
122 google_apis::GDataErrorCode error) { | |
123 callback.Run(error, status, entry.Pass()); | |
124 } | |
125 | |
126 void UploadResultAdapter(const APIUtil::ResourceEntryCallback& callback, | |
127 google_apis::GDataErrorCode error, | |
128 const GURL& upload_location, | |
129 scoped_ptr<google_apis::ResourceEntry> entry) { | |
130 callback.Run(error, entry.Pass()); | |
131 } | |
132 | |
133 std::string GetMimeTypeFromTitle(const std::string& title) { | |
134 base::FilePath::StringType extension = | |
135 base::FilePath::FromUTF8Unsafe(title).Extension(); | |
136 std::string mime_type; | |
137 if (extension.empty() || | |
138 !net::GetWellKnownMimeTypeFromExtension(extension.substr(1), &mime_type)) | |
139 return kMimeTypeOctetStream; | |
140 return mime_type; | |
141 } | |
142 | |
143 bool CreateTemporaryFile(const base::FilePath& dir_path, | |
144 webkit_blob::ScopedFile* temp_file) { | |
145 base::FilePath temp_file_path; | |
146 const bool success = file_util::CreateDirectory(dir_path) && | |
147 file_util::CreateTemporaryFileInDir(dir_path, &temp_file_path); | |
148 if (!success) | |
149 return success; | |
150 *temp_file = | |
151 webkit_blob::ScopedFile(temp_file_path, | |
152 webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT, | |
153 base::MessageLoopProxy::current().get()); | |
154 return success; | |
155 } | |
156 | |
157 } // namespace | |
158 | |
159 APIUtil::APIUtil(Profile* profile, | |
160 const base::FilePath& temp_dir_path) | |
161 : wapi_url_generator_( | |
162 GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction), | |
163 GURL(google_apis::GDataWapiUrlGenerator:: | |
164 kBaseDownloadUrlForProduction)), | |
165 drive_api_url_generator_( | |
166 GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction), | |
167 GURL(google_apis::DriveApiUrlGenerator:: | |
168 kBaseDownloadUrlForProduction)), | |
169 upload_next_key_(0), | |
170 temp_dir_path_(temp_dir_path) { | |
171 OAuth2TokenService* oauth_service = | |
172 ProfileOAuth2TokenServiceFactory::GetForProfile(profile); | |
173 if (IsDriveAPIDisabled()) { | |
174 drive_service_.reset(new drive::GDataWapiService( | |
175 oauth_service, | |
176 profile->GetRequestContext(), | |
177 content::BrowserThread::GetBlockingPool(), | |
178 GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction), | |
179 GURL(google_apis::GDataWapiUrlGenerator::kBaseDownloadUrlForProduction), | |
180 std::string() /* custom_user_agent */)); | |
181 } else { | |
182 drive_service_.reset(new drive::DriveAPIService( | |
183 oauth_service, | |
184 profile->GetRequestContext(), | |
185 content::BrowserThread::GetBlockingPool(), | |
186 GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction), | |
187 GURL(google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction), | |
188 GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction), | |
189 std::string() /* custom_user_agent */)); | |
190 } | |
191 | |
192 drive_service_->Initialize(); | |
193 drive_service_->AddObserver(this); | |
194 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | |
195 | |
196 drive_uploader_.reset(new drive::DriveUploader( | |
197 drive_service_.get(), content::BrowserThread::GetBlockingPool())); | |
198 } | |
199 | |
200 scoped_ptr<APIUtil> APIUtil::CreateForTesting( | |
201 const base::FilePath& temp_dir_path, | |
202 scoped_ptr<drive::DriveServiceInterface> drive_service, | |
203 scoped_ptr<drive::DriveUploaderInterface> drive_uploader) { | |
204 return make_scoped_ptr(new APIUtil( | |
205 temp_dir_path, | |
206 GURL(kFakeServerBaseUrl), | |
207 GURL(kFakeDownloadServerBaseUrl), | |
208 drive_service.Pass(), | |
209 drive_uploader.Pass())); | |
210 } | |
211 | |
212 APIUtil::APIUtil(const base::FilePath& temp_dir_path, | |
213 const GURL& base_url, | |
214 const GURL& base_download_url, | |
215 scoped_ptr<drive::DriveServiceInterface> drive_service, | |
216 scoped_ptr<drive::DriveUploaderInterface> drive_uploader) | |
217 : wapi_url_generator_(base_url, base_download_url), | |
218 drive_api_url_generator_(base_url, base_download_url), | |
219 upload_next_key_(0), | |
220 temp_dir_path_(temp_dir_path) { | |
221 drive_service_ = drive_service.Pass(); | |
222 drive_service_->Initialize(); | |
223 drive_service_->AddObserver(this); | |
224 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | |
225 | |
226 drive_uploader_ = drive_uploader.Pass(); | |
227 } | |
228 | |
229 APIUtil::~APIUtil() { | |
230 DCHECK(CalledOnValidThread()); | |
231 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | |
232 drive_service_->RemoveObserver(this); | |
233 } | |
234 | |
235 void APIUtil::AddObserver(APIUtilObserver* observer) { | |
236 DCHECK(CalledOnValidThread()); | |
237 observers_.AddObserver(observer); | |
238 } | |
239 | |
240 void APIUtil::RemoveObserver(APIUtilObserver* observer) { | |
241 DCHECK(CalledOnValidThread()); | |
242 observers_.RemoveObserver(observer); | |
243 } | |
244 | |
245 void APIUtil::GetDriveRootResourceId(const GDataErrorCallback& callback) { | |
246 DCHECK(CalledOnValidThread()); | |
247 DCHECK(!IsDriveAPIDisabled()); | |
248 DVLOG(2) << "Getting resource id for Drive root"; | |
249 | |
250 drive_service_->GetAboutResource( | |
251 base::Bind(&APIUtil::DidGetDriveRootResourceId, AsWeakPtr(), callback)); | |
252 } | |
253 | |
254 void APIUtil::DidGetDriveRootResourceId( | |
255 const GDataErrorCallback& callback, | |
256 google_apis::GDataErrorCode error, | |
257 scoped_ptr<google_apis::AboutResource> about_resource) { | |
258 DCHECK(CalledOnValidThread()); | |
259 | |
260 if (error != google_apis::HTTP_SUCCESS) { | |
261 DVLOG(2) << "Error on getting resource id for Drive root: " << error; | |
262 callback.Run(error); | |
263 return; | |
264 } | |
265 | |
266 DCHECK(about_resource); | |
267 root_resource_id_ = about_resource->root_folder_id(); | |
268 DCHECK(!root_resource_id_.empty()); | |
269 DVLOG(2) << "Got resource id for Drive root: " << root_resource_id_; | |
270 callback.Run(error); | |
271 } | |
272 | |
273 void APIUtil::GetDriveDirectoryForSyncRoot(const ResourceIdCallback& callback) { | |
274 DCHECK(CalledOnValidThread()); | |
275 | |
276 if (GetRootResourceId().empty()) { | |
277 GetDriveRootResourceId( | |
278 base::Bind(&APIUtil::DidGetDriveRootResourceIdForGetSyncRoot, | |
279 AsWeakPtr(), callback)); | |
280 return; | |
281 } | |
282 | |
283 DVLOG(2) << "Getting Drive directory for SyncRoot"; | |
284 std::string directory_name(GetSyncRootDirectoryName()); | |
285 SearchByTitle(directory_name, | |
286 std::string(), | |
287 base::Bind(&APIUtil::DidGetDirectory, | |
288 AsWeakPtr(), | |
289 std::string(), | |
290 directory_name, | |
291 callback)); | |
292 } | |
293 | |
294 void APIUtil::DidGetDriveRootResourceIdForGetSyncRoot( | |
295 const ResourceIdCallback& callback, | |
296 google_apis::GDataErrorCode error) { | |
297 DCHECK(CalledOnValidThread()); | |
298 if (error != google_apis::HTTP_SUCCESS) { | |
299 DVLOG(2) << "Error on getting Drive directory for SyncRoot: " << error; | |
300 callback.Run(error, std::string()); | |
301 return; | |
302 } | |
303 GetDriveDirectoryForSyncRoot(callback); | |
304 } | |
305 | |
306 void APIUtil::GetDriveDirectoryForOrigin( | |
307 const std::string& sync_root_resource_id, | |
308 const GURL& origin, | |
309 const ResourceIdCallback& callback) { | |
310 DCHECK(CalledOnValidThread()); | |
311 DVLOG(2) << "Getting Drive directory for Origin: " << origin; | |
312 | |
313 std::string directory_name(OriginToDirectoryTitle(origin)); | |
314 SearchByTitle(directory_name, | |
315 sync_root_resource_id, | |
316 base::Bind(&APIUtil::DidGetDirectory, | |
317 AsWeakPtr(), | |
318 sync_root_resource_id, | |
319 directory_name, | |
320 callback)); | |
321 } | |
322 | |
323 void APIUtil::DidGetDirectory(const std::string& parent_resource_id, | |
324 const std::string& directory_name, | |
325 const ResourceIdCallback& callback, | |
326 google_apis::GDataErrorCode error, | |
327 scoped_ptr<google_apis::ResourceList> feed) { | |
328 DCHECK(CalledOnValidThread()); | |
329 DCHECK(IsStringASCII(directory_name)); | |
330 | |
331 if (error != google_apis::HTTP_SUCCESS) { | |
332 DVLOG(2) << "Error on getting Drive directory: " << error; | |
333 callback.Run(error, std::string()); | |
334 return; | |
335 } | |
336 | |
337 std::string resource_id; | |
338 ParentType parent_type = PARENT_TYPE_DIRECTORY; | |
339 if (parent_resource_id.empty()) { | |
340 resource_id = GetRootResourceId(); | |
341 DCHECK(!resource_id.empty()); | |
342 parent_type = PARENT_TYPE_ROOT_OR_EMPTY; | |
343 } else { | |
344 resource_id = parent_resource_id; | |
345 } | |
346 std::string title(directory_name); | |
347 google_apis::ResourceEntry* entry = GetDocumentByTitleAndParent( | |
348 feed->entries(), title, resource_id, parent_type); | |
349 if (!entry) { | |
350 DVLOG(2) << "Directory not found. Creating: " << directory_name; | |
351 drive_service_->AddNewDirectory(resource_id, | |
352 directory_name, | |
353 base::Bind(&APIUtil::DidCreateDirectory, | |
354 AsWeakPtr(), | |
355 parent_resource_id, | |
356 title, | |
357 callback)); | |
358 return; | |
359 } | |
360 DVLOG(2) << "Found Drive directory."; | |
361 | |
362 // TODO(tzik): Handle error. | |
363 DCHECK_EQ(google_apis::ENTRY_KIND_FOLDER, entry->kind()); | |
364 DCHECK_EQ(directory_name, entry->title()); | |
365 | |
366 if (entry->title() == GetSyncRootDirectoryName()) | |
367 EnsureSyncRootIsNotInMyDrive(entry->resource_id()); | |
368 | |
369 callback.Run(error, entry->resource_id()); | |
370 } | |
371 | |
372 void APIUtil::DidCreateDirectory(const std::string& parent_resource_id, | |
373 const std::string& title, | |
374 const ResourceIdCallback& callback, | |
375 google_apis::GDataErrorCode error, | |
376 scoped_ptr<google_apis::ResourceEntry> entry) { | |
377 DCHECK(CalledOnValidThread()); | |
378 | |
379 if (error != google_apis::HTTP_SUCCESS && | |
380 error != google_apis::HTTP_CREATED) { | |
381 DVLOG(2) << "Error on creating Drive directory: " << error; | |
382 callback.Run(error, std::string()); | |
383 return; | |
384 } | |
385 DVLOG(2) << "Created Drive directory."; | |
386 | |
387 DCHECK(entry); | |
388 // Check if any other client creates a directory with same title. | |
389 EnsureTitleUniqueness( | |
390 parent_resource_id, | |
391 title, | |
392 base::Bind(&APIUtil::DidEnsureUniquenessForCreateDirectory, | |
393 AsWeakPtr(), | |
394 callback)); | |
395 } | |
396 | |
397 void APIUtil::DidEnsureUniquenessForCreateDirectory( | |
398 const ResourceIdCallback& callback, | |
399 google_apis::GDataErrorCode error, | |
400 EnsureUniquenessStatus status, | |
401 scoped_ptr<google_apis::ResourceEntry> entry) { | |
402 DCHECK(CalledOnValidThread()); | |
403 | |
404 if (error != google_apis::HTTP_SUCCESS) { | |
405 callback.Run(error, std::string()); | |
406 return; | |
407 } | |
408 | |
409 if (status == NO_DUPLICATES_FOUND) | |
410 error = google_apis::HTTP_CREATED; | |
411 | |
412 DCHECK(entry) << "No entry: " << error; | |
413 | |
414 if (!entry->is_folder()) { | |
415 // TODO(kinuko): Fix this. http://crbug.com/237090 | |
416 util::Log( | |
417 logging::LOG_ERROR, | |
418 FROM_HERE, | |
419 "A file is left for CreateDirectory due to file-folder conflict!"); | |
420 callback.Run(google_apis::HTTP_CONFLICT, std::string()); | |
421 return; | |
422 } | |
423 | |
424 if (entry->title() == GetSyncRootDirectoryName()) | |
425 EnsureSyncRootIsNotInMyDrive(entry->resource_id()); | |
426 | |
427 callback.Run(error, entry->resource_id()); | |
428 } | |
429 | |
430 void APIUtil::GetLargestChangeStamp(const ChangeStampCallback& callback) { | |
431 DCHECK(CalledOnValidThread()); | |
432 DVLOG(2) << "Getting largest change id"; | |
433 | |
434 drive_service_->GetAboutResource( | |
435 base::Bind(&APIUtil::DidGetLargestChangeStamp, AsWeakPtr(), callback)); | |
436 } | |
437 | |
438 void APIUtil::GetResourceEntry(const std::string& resource_id, | |
439 const ResourceEntryCallback& callback) { | |
440 DCHECK(CalledOnValidThread()); | |
441 DVLOG(2) << "Getting ResourceEntry for: " << resource_id; | |
442 | |
443 drive_service_->GetResourceEntry( | |
444 resource_id, | |
445 base::Bind(&APIUtil::DidGetResourceEntry, AsWeakPtr(), callback)); | |
446 } | |
447 | |
448 void APIUtil::DidGetLargestChangeStamp( | |
449 const ChangeStampCallback& callback, | |
450 google_apis::GDataErrorCode error, | |
451 scoped_ptr<google_apis::AboutResource> about_resource) { | |
452 DCHECK(CalledOnValidThread()); | |
453 | |
454 int64 largest_change_id = 0; | |
455 if (error == google_apis::HTTP_SUCCESS) { | |
456 DCHECK(about_resource); | |
457 largest_change_id = about_resource->largest_change_id(); | |
458 root_resource_id_ = about_resource->root_folder_id(); | |
459 DVLOG(2) << "Got largest change id: " << largest_change_id; | |
460 } else { | |
461 DVLOG(2) << "Error on getting largest change id: " << error; | |
462 } | |
463 | |
464 callback.Run(error, largest_change_id); | |
465 } | |
466 | |
467 void APIUtil::SearchByTitle(const std::string& title, | |
468 const std::string& directory_resource_id, | |
469 const ResourceListCallback& callback) { | |
470 DCHECK(CalledOnValidThread()); | |
471 DCHECK(!title.empty()); | |
472 DVLOG(2) << "Searching resources in the directory [" << directory_resource_id | |
473 << "] with title [" << title << "]"; | |
474 | |
475 drive_service_->SearchByTitle( | |
476 title, | |
477 directory_resource_id, | |
478 base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback)); | |
479 } | |
480 | |
481 void APIUtil::ListFiles(const std::string& directory_resource_id, | |
482 const ResourceListCallback& callback) { | |
483 DCHECK(CalledOnValidThread()); | |
484 DVLOG(2) << "Listing resources in the directory [" << directory_resource_id | |
485 << "]"; | |
486 | |
487 drive_service_->GetResourceListInDirectory(directory_resource_id, callback); | |
488 } | |
489 | |
490 void APIUtil::ListChanges(int64 start_changestamp, | |
491 const ResourceListCallback& callback) { | |
492 DCHECK(CalledOnValidThread()); | |
493 DVLOG(2) << "Listing changes since: " << start_changestamp; | |
494 | |
495 drive_service_->GetChangeList( | |
496 start_changestamp, | |
497 base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback)); | |
498 } | |
499 | |
500 void APIUtil::ContinueListing(const GURL& next_link, | |
501 const ResourceListCallback& callback) { | |
502 DCHECK(CalledOnValidThread()); | |
503 DVLOG(2) << "Continue listing on feed: " << next_link.spec(); | |
504 | |
505 drive_service_->GetRemainingFileList( | |
506 next_link, | |
507 base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback)); | |
508 } | |
509 | |
510 void APIUtil::DownloadFile(const std::string& resource_id, | |
511 const std::string& local_file_md5, | |
512 const DownloadFileCallback& callback) { | |
513 DCHECK(CalledOnValidThread()); | |
514 DCHECK(!temp_dir_path_.empty()); | |
515 DVLOG(2) << "Downloading file [" << resource_id << "]"; | |
516 | |
517 scoped_ptr<webkit_blob::ScopedFile> temp_file(new webkit_blob::ScopedFile); | |
518 webkit_blob::ScopedFile* temp_file_ptr = temp_file.get(); | |
519 content::BrowserThread::PostTaskAndReplyWithResult( | |
520 content::BrowserThread::FILE, FROM_HERE, | |
521 base::Bind(&CreateTemporaryFile, temp_dir_path_, temp_file_ptr), | |
522 base::Bind(&APIUtil::DidGetTemporaryFileForDownload, | |
523 AsWeakPtr(), resource_id, local_file_md5, | |
524 base::Passed(&temp_file), callback)); | |
525 } | |
526 | |
527 void APIUtil::UploadNewFile(const std::string& directory_resource_id, | |
528 const base::FilePath& local_file_path, | |
529 const std::string& title, | |
530 const UploadFileCallback& callback) { | |
531 DCHECK(CalledOnValidThread()); | |
532 DVLOG(2) << "Uploading new file into the directory [" << directory_resource_id | |
533 << "] with title [" << title << "]"; | |
534 | |
535 std::string mime_type = GetMimeTypeFromTitle(title); | |
536 UploadKey upload_key = RegisterUploadCallback(callback); | |
537 ResourceEntryCallback did_upload_callback = | |
538 base::Bind(&APIUtil::DidUploadNewFile, | |
539 AsWeakPtr(), | |
540 directory_resource_id, | |
541 title, | |
542 upload_key); | |
543 drive_uploader_->UploadNewFile( | |
544 directory_resource_id, | |
545 local_file_path, | |
546 title, | |
547 mime_type, | |
548 base::Bind(&UploadResultAdapter, did_upload_callback), | |
549 google_apis::ProgressCallback()); | |
550 } | |
551 | |
552 void APIUtil::UploadExistingFile(const std::string& resource_id, | |
553 const std::string& remote_file_md5, | |
554 const base::FilePath& local_file_path, | |
555 const UploadFileCallback& callback) { | |
556 DCHECK(CalledOnValidThread()); | |
557 DVLOG(2) << "Uploading existing file [" << resource_id << "]"; | |
558 drive_service_->GetResourceEntry( | |
559 resource_id, | |
560 base::Bind(&APIUtil::DidGetResourceEntry, | |
561 AsWeakPtr(), | |
562 base::Bind(&APIUtil::UploadExistingFileInternal, | |
563 AsWeakPtr(), | |
564 remote_file_md5, | |
565 local_file_path, | |
566 callback))); | |
567 } | |
568 | |
569 void APIUtil::CreateDirectory(const std::string& parent_resource_id, | |
570 const std::string& title, | |
571 const ResourceIdCallback& callback) { | |
572 DCHECK(CalledOnValidThread()); | |
573 // TODO(kinuko): This will call EnsureTitleUniqueness and will delete | |
574 // directories if there're duplicated directories. This must be ok | |
575 // for current design but we'll need to merge directories when we support | |
576 // 'real' directories. | |
577 drive_service_->AddNewDirectory(parent_resource_id, | |
578 title, | |
579 base::Bind(&APIUtil::DidCreateDirectory, | |
580 AsWeakPtr(), | |
581 parent_resource_id, | |
582 title, | |
583 callback)); | |
584 } | |
585 | |
586 void APIUtil::DeleteFile(const std::string& resource_id, | |
587 const std::string& remote_file_md5, | |
588 const GDataErrorCallback& callback) { | |
589 DCHECK(CalledOnValidThread()); | |
590 DVLOG(2) << "Deleting file: " << resource_id; | |
591 | |
592 // Load actual remote_file_md5 to check for conflict before deletion. | |
593 if (!remote_file_md5.empty()) { | |
594 drive_service_->GetResourceEntry( | |
595 resource_id, | |
596 base::Bind(&APIUtil::DidGetResourceEntry, | |
597 AsWeakPtr(), | |
598 base::Bind(&APIUtil::DeleteFileInternal, | |
599 AsWeakPtr(), | |
600 remote_file_md5, | |
601 callback))); | |
602 return; | |
603 } | |
604 | |
605 // Expected remote_file_md5 is empty so do a force delete. | |
606 drive_service_->DeleteResource( | |
607 resource_id, | |
608 std::string(), | |
609 base::Bind(&APIUtil::DidDeleteFile, AsWeakPtr(), callback)); | |
610 return; | |
611 } | |
612 | |
613 GURL APIUtil::ResourceIdToResourceLink(const std::string& resource_id) const { | |
614 return IsDriveAPIDisabled() | |
615 ? wapi_url_generator_.GenerateEditUrl(resource_id) | |
616 : drive_api_url_generator_.GetFilesGetUrl(resource_id); | |
617 } | |
618 | |
619 void APIUtil::EnsureSyncRootIsNotInMyDrive( | |
620 const std::string& sync_root_resource_id) { | |
621 DCHECK(CalledOnValidThread()); | |
622 | |
623 if (GetRootResourceId().empty()) { | |
624 GetDriveRootResourceId( | |
625 base::Bind(&APIUtil::DidGetDriveRootResourceIdForEnsureSyncRoot, | |
626 AsWeakPtr(), sync_root_resource_id)); | |
627 return; | |
628 } | |
629 | |
630 DVLOG(2) << "Ensuring the sync root directory is not in 'My Drive'."; | |
631 drive_service_->RemoveResourceFromDirectory( | |
632 GetRootResourceId(), | |
633 sync_root_resource_id, | |
634 base::Bind(&EmptyGDataErrorCodeCallback)); | |
635 } | |
636 | |
637 void APIUtil::DidGetDriveRootResourceIdForEnsureSyncRoot( | |
638 const std::string& sync_root_resource_id, | |
639 google_apis::GDataErrorCode error) { | |
640 DCHECK(CalledOnValidThread()); | |
641 | |
642 if (error != google_apis::HTTP_SUCCESS) { | |
643 DVLOG(2) << "Error on ensuring the sync root directory is not in" | |
644 << " 'My Drive': " << error; | |
645 // Give up ensuring the sync root directory is not in 'My Drive'. This will | |
646 // be retried at some point. | |
647 return; | |
648 } | |
649 | |
650 DCHECK(!GetRootResourceId().empty()); | |
651 EnsureSyncRootIsNotInMyDrive(sync_root_resource_id); | |
652 } | |
653 | |
654 // static | |
655 // TODO(calvinlo): Delete this when Sync Directory Operations are supported by | |
656 // default. | |
657 std::string APIUtil::GetSyncRootDirectoryName() { | |
658 return IsSyncFSDirectoryOperationEnabled() ? kSyncRootDirectoryNameDev | |
659 : kSyncRootDirectoryName; | |
660 } | |
661 | |
662 // static | |
663 std::string APIUtil::OriginToDirectoryTitle(const GURL& origin) { | |
664 DCHECK(origin.SchemeIs(extensions::kExtensionScheme)); | |
665 return origin.host(); | |
666 } | |
667 | |
668 // static | |
669 GURL APIUtil::DirectoryTitleToOrigin(const std::string& title) { | |
670 return extensions::Extension::GetBaseURLFromExtensionId(title); | |
671 } | |
672 | |
673 void APIUtil::OnReadyToSendRequests() { | |
674 DCHECK(CalledOnValidThread()); | |
675 FOR_EACH_OBSERVER(APIUtilObserver, observers_, OnAuthenticated()); | |
676 } | |
677 | |
678 void APIUtil::OnConnectionTypeChanged( | |
679 net::NetworkChangeNotifier::ConnectionType type) { | |
680 DCHECK(CalledOnValidThread()); | |
681 if (type != net::NetworkChangeNotifier::CONNECTION_NONE) { | |
682 FOR_EACH_OBSERVER(APIUtilObserver, observers_, OnNetworkConnected()); | |
683 return; | |
684 } | |
685 // We're now disconnected, reset the drive_uploader_ to force stop | |
686 // uploading, otherwise the uploader may get stuck. | |
687 // TODO(kinuko): Check the uploader behavior if it's the expected behavior | |
688 // (http://crbug.com/223818) | |
689 CancelAllUploads(google_apis::GDATA_NO_CONNECTION); | |
690 } | |
691 | |
692 void APIUtil::DidGetResourceList( | |
693 const ResourceListCallback& callback, | |
694 google_apis::GDataErrorCode error, | |
695 scoped_ptr<google_apis::ResourceList> resource_list) { | |
696 DCHECK(CalledOnValidThread()); | |
697 | |
698 if (error != google_apis::HTTP_SUCCESS) { | |
699 DVLOG(2) << "Error on listing resource: " << error; | |
700 callback.Run(error, scoped_ptr<google_apis::ResourceList>()); | |
701 return; | |
702 } | |
703 | |
704 DVLOG(2) << "Got resource list"; | |
705 DCHECK(resource_list); | |
706 callback.Run(error, resource_list.Pass()); | |
707 } | |
708 | |
709 void APIUtil::DidGetResourceEntry( | |
710 const ResourceEntryCallback& callback, | |
711 google_apis::GDataErrorCode error, | |
712 scoped_ptr<google_apis::ResourceEntry> entry) { | |
713 DCHECK(CalledOnValidThread()); | |
714 | |
715 if (error != google_apis::HTTP_SUCCESS) { | |
716 DVLOG(2) << "Error on getting resource entry:" << error; | |
717 callback.Run(error, scoped_ptr<google_apis::ResourceEntry>()); | |
718 return; | |
719 } | |
720 | |
721 if (entry->deleted()) { | |
722 DVLOG(2) << "Got resource entry, the entry was trashed."; | |
723 callback.Run(google_apis::HTTP_NOT_FOUND, entry.Pass()); | |
724 return; | |
725 } | |
726 | |
727 DVLOG(2) << "Got resource entry"; | |
728 DCHECK(entry); | |
729 callback.Run(error, entry.Pass()); | |
730 } | |
731 | |
732 void APIUtil::DidGetTemporaryFileForDownload( | |
733 const std::string& resource_id, | |
734 const std::string& local_file_md5, | |
735 scoped_ptr<webkit_blob::ScopedFile> local_file, | |
736 const DownloadFileCallback& callback, | |
737 bool success) { | |
738 if (!success) { | |
739 DVLOG(2) << "Error in creating a temp file under " | |
740 << temp_dir_path_.value(); | |
741 callback.Run(google_apis::GDATA_FILE_ERROR, std::string(), 0, base::Time(), | |
742 local_file.Pass()); | |
743 return; | |
744 } | |
745 drive_service_->GetResourceEntry( | |
746 resource_id, | |
747 base::Bind(&APIUtil::DidGetResourceEntry, | |
748 AsWeakPtr(), | |
749 base::Bind(&APIUtil::DownloadFileInternal, | |
750 AsWeakPtr(), | |
751 local_file_md5, | |
752 base::Passed(&local_file), | |
753 callback))); | |
754 } | |
755 | |
756 void APIUtil::DownloadFileInternal( | |
757 const std::string& local_file_md5, | |
758 scoped_ptr<webkit_blob::ScopedFile> local_file, | |
759 const DownloadFileCallback& callback, | |
760 google_apis::GDataErrorCode error, | |
761 scoped_ptr<google_apis::ResourceEntry> entry) { | |
762 DCHECK(CalledOnValidThread()); | |
763 | |
764 if (error != google_apis::HTTP_SUCCESS) { | |
765 DVLOG(2) << "Error on getting resource entry for download"; | |
766 callback.Run(error, std::string(), 0, base::Time(), | |
767 local_file.Pass()); | |
768 return; | |
769 } | |
770 DCHECK(entry); | |
771 | |
772 DVLOG(2) << "Got resource entry for download"; | |
773 // If local file and remote file are same, cancel the download. | |
774 if (local_file_md5 == entry->file_md5()) { | |
775 callback.Run(google_apis::HTTP_NOT_MODIFIED, | |
776 local_file_md5, | |
777 entry->file_size(), | |
778 entry->updated_time(), | |
779 local_file.Pass()); | |
780 return; | |
781 } | |
782 | |
783 DVLOG(2) << "Downloading file: " << entry->resource_id(); | |
784 const std::string& resource_id = entry->resource_id(); | |
785 const base::FilePath& local_file_path = local_file->path(); | |
786 drive_service_->DownloadFile(local_file_path, | |
787 resource_id, | |
788 base::Bind(&APIUtil::DidDownloadFile, | |
789 AsWeakPtr(), | |
790 base::Passed(&entry), | |
791 base::Passed(&local_file), | |
792 callback), | |
793 google_apis::GetContentCallback(), | |
794 google_apis::ProgressCallback()); | |
795 } | |
796 | |
797 void APIUtil::DidDownloadFile(scoped_ptr<google_apis::ResourceEntry> entry, | |
798 scoped_ptr<webkit_blob::ScopedFile> local_file, | |
799 const DownloadFileCallback& callback, | |
800 google_apis::GDataErrorCode error, | |
801 const base::FilePath& downloaded_file_path) { | |
802 DCHECK(CalledOnValidThread()); | |
803 if (error == google_apis::HTTP_SUCCESS) | |
804 DVLOG(2) << "Download completed"; | |
805 else | |
806 DVLOG(2) << "Error on downloading file: " << error; | |
807 | |
808 callback.Run( | |
809 error, entry->file_md5(), entry->file_size(), entry->updated_time(), | |
810 local_file.Pass()); | |
811 } | |
812 | |
813 void APIUtil::DidUploadNewFile(const std::string& parent_resource_id, | |
814 const std::string& title, | |
815 UploadKey upload_key, | |
816 google_apis::GDataErrorCode error, | |
817 scoped_ptr<google_apis::ResourceEntry> entry) { | |
818 UploadFileCallback callback = GetAndUnregisterUploadCallback(upload_key); | |
819 DCHECK(!callback.is_null()); | |
820 if (error != google_apis::HTTP_SUCCESS && | |
821 error != google_apis::HTTP_CREATED) { | |
822 DVLOG(2) << "Error on uploading new file: " << error; | |
823 callback.Run(error, std::string(), std::string()); | |
824 return; | |
825 } | |
826 | |
827 DVLOG(2) << "Upload completed"; | |
828 EnsureTitleUniqueness(parent_resource_id, | |
829 title, | |
830 base::Bind(&APIUtil::DidEnsureUniquenessForCreateFile, | |
831 AsWeakPtr(), | |
832 entry->resource_id(), | |
833 callback)); | |
834 } | |
835 | |
836 void APIUtil::DidEnsureUniquenessForCreateFile( | |
837 const std::string& expected_resource_id, | |
838 const UploadFileCallback& callback, | |
839 google_apis::GDataErrorCode error, | |
840 EnsureUniquenessStatus status, | |
841 scoped_ptr<google_apis::ResourceEntry> entry) { | |
842 if (error != google_apis::HTTP_SUCCESS) { | |
843 DVLOG(2) << "Error on uploading new file: " << error; | |
844 callback.Run(error, std::string(), std::string()); | |
845 return; | |
846 } | |
847 | |
848 switch (status) { | |
849 case NO_DUPLICATES_FOUND: | |
850 // The file was uploaded successfully and no conflict was detected. | |
851 DCHECK(entry); | |
852 DVLOG(2) << "No conflict detected on uploading new file"; | |
853 callback.Run( | |
854 google_apis::HTTP_CREATED, entry->resource_id(), entry->file_md5()); | |
855 return; | |
856 | |
857 case RESOLVED_DUPLICATES: | |
858 // The file was uploaded successfully but a conflict was detected. | |
859 // The duplicated file was deleted successfully. | |
860 DCHECK(entry); | |
861 if (entry->resource_id() != expected_resource_id) { | |
862 // TODO(kinuko): We should check local vs remote md5 here. | |
863 DVLOG(2) << "Conflict detected on uploading new file"; | |
864 callback.Run(google_apis::HTTP_CONFLICT, | |
865 entry->resource_id(), | |
866 entry->file_md5()); | |
867 return; | |
868 } | |
869 | |
870 DVLOG(2) << "Conflict detected on uploading new file and resolved"; | |
871 callback.Run( | |
872 google_apis::HTTP_CREATED, entry->resource_id(), entry->file_md5()); | |
873 return; | |
874 | |
875 default: | |
876 NOTREACHED() << "Unknown status from EnsureTitleUniqueness:" << status | |
877 << " for " << expected_resource_id; | |
878 } | |
879 } | |
880 | |
881 void APIUtil::UploadExistingFileInternal( | |
882 const std::string& remote_file_md5, | |
883 const base::FilePath& local_file_path, | |
884 const UploadFileCallback& callback, | |
885 google_apis::GDataErrorCode error, | |
886 scoped_ptr<google_apis::ResourceEntry> entry) { | |
887 DCHECK(CalledOnValidThread()); | |
888 | |
889 if (error != google_apis::HTTP_SUCCESS) { | |
890 DVLOG(2) << "Error on uploading existing file: " << error; | |
891 callback.Run(error, std::string(), std::string()); | |
892 return; | |
893 } | |
894 DCHECK(entry); | |
895 | |
896 // If remote file's hash value is different from the expected one, conflict | |
897 // might have occurred. | |
898 if (!remote_file_md5.empty() && remote_file_md5 != entry->file_md5()) { | |
899 DVLOG(2) << "Conflict detected before uploading existing file"; | |
900 callback.Run(google_apis::HTTP_CONFLICT, std::string(), std::string()); | |
901 return; | |
902 } | |
903 | |
904 std::string mime_type = GetMimeTypeFromTitle(entry->title()); | |
905 UploadKey upload_key = RegisterUploadCallback(callback); | |
906 ResourceEntryCallback did_upload_callback = | |
907 base::Bind(&APIUtil::DidUploadExistingFile, AsWeakPtr(), upload_key); | |
908 drive_uploader_->UploadExistingFile( | |
909 entry->resource_id(), | |
910 local_file_path, | |
911 mime_type, | |
912 entry->etag(), | |
913 base::Bind(&UploadResultAdapter, did_upload_callback), | |
914 google_apis::ProgressCallback()); | |
915 } | |
916 | |
917 bool APIUtil::IsAuthenticated() const { | |
918 return drive_service_->HasRefreshToken(); | |
919 } | |
920 | |
921 void APIUtil::DidUploadExistingFile( | |
922 UploadKey upload_key, | |
923 google_apis::GDataErrorCode error, | |
924 scoped_ptr<google_apis::ResourceEntry> entry) { | |
925 DCHECK(CalledOnValidThread()); | |
926 UploadFileCallback callback = GetAndUnregisterUploadCallback(upload_key); | |
927 DCHECK(!callback.is_null()); | |
928 if (error != google_apis::HTTP_SUCCESS) { | |
929 DVLOG(2) << "Error on uploading existing file: " << error; | |
930 callback.Run(error, std::string(), std::string()); | |
931 return; | |
932 } | |
933 | |
934 DCHECK(entry); | |
935 DVLOG(2) << "Upload completed"; | |
936 callback.Run(error, entry->resource_id(), entry->file_md5()); | |
937 } | |
938 | |
939 void APIUtil::DeleteFileInternal(const std::string& remote_file_md5, | |
940 const GDataErrorCallback& callback, | |
941 google_apis::GDataErrorCode error, | |
942 scoped_ptr<google_apis::ResourceEntry> entry) { | |
943 DCHECK(CalledOnValidThread()); | |
944 | |
945 if (error != google_apis::HTTP_SUCCESS) { | |
946 DVLOG(2) << "Error on getting resource entry for deleting file: " << error; | |
947 callback.Run(error); | |
948 return; | |
949 } | |
950 DCHECK(entry); | |
951 | |
952 // If remote file's hash value is different from the expected one, conflict | |
953 // might have occurred. | |
954 if (!remote_file_md5.empty() && remote_file_md5 != entry->file_md5()) { | |
955 DVLOG(2) << "Conflict detected before deleting file"; | |
956 callback.Run(google_apis::HTTP_CONFLICT); | |
957 return; | |
958 } | |
959 DVLOG(2) << "Got resource entry for deleting file"; | |
960 | |
961 // Move the file to trash (don't delete it completely). | |
962 drive_service_->DeleteResource( | |
963 entry->resource_id(), | |
964 entry->etag(), | |
965 base::Bind(&APIUtil::DidDeleteFile, AsWeakPtr(), callback)); | |
966 } | |
967 | |
968 void APIUtil::DidDeleteFile(const GDataErrorCallback& callback, | |
969 google_apis::GDataErrorCode error) { | |
970 DCHECK(CalledOnValidThread()); | |
971 if (error == google_apis::HTTP_SUCCESS) | |
972 DVLOG(2) << "Deletion completed"; | |
973 else | |
974 DVLOG(2) << "Error on deleting file: " << error; | |
975 | |
976 callback.Run(error); | |
977 } | |
978 | |
979 void APIUtil::EnsureTitleUniqueness(const std::string& parent_resource_id, | |
980 const std::string& expected_title, | |
981 const EnsureUniquenessCallback& callback) { | |
982 DCHECK(CalledOnValidThread()); | |
983 DVLOG(2) << "Checking if there's no conflict on entry creation"; | |
984 | |
985 const google_apis::GetResourceListCallback& bound_callback = | |
986 base::Bind(&APIUtil::DidListEntriesToEnsureUniqueness, | |
987 AsWeakPtr(), | |
988 parent_resource_id, | |
989 expected_title, | |
990 callback); | |
991 | |
992 SearchByTitle(expected_title, parent_resource_id, bound_callback); | |
993 } | |
994 | |
995 void APIUtil::DidListEntriesToEnsureUniqueness( | |
996 const std::string& parent_resource_id, | |
997 const std::string& expected_title, | |
998 const EnsureUniquenessCallback& callback, | |
999 google_apis::GDataErrorCode error, | |
1000 scoped_ptr<google_apis::ResourceList> feed) { | |
1001 DCHECK(CalledOnValidThread()); | |
1002 | |
1003 if (error != google_apis::HTTP_SUCCESS) { | |
1004 DVLOG(2) << "Error on listing resource for ensuring title uniqueness"; | |
1005 callback.Run( | |
1006 error, NO_DUPLICATES_FOUND, scoped_ptr<google_apis::ResourceEntry>()); | |
1007 return; | |
1008 } | |
1009 DVLOG(2) << "Got resource list for ensuring title uniqueness"; | |
1010 | |
1011 // This filtering is needed only on WAPI. Once we move to Drive API we can | |
1012 // drop this. | |
1013 std::string resource_id; | |
1014 ParentType parent_type = PARENT_TYPE_DIRECTORY; | |
1015 if (parent_resource_id.empty()) { | |
1016 resource_id = GetRootResourceId(); | |
1017 DCHECK(!resource_id.empty()); | |
1018 parent_type = PARENT_TYPE_ROOT_OR_EMPTY; | |
1019 } else { | |
1020 resource_id = parent_resource_id; | |
1021 } | |
1022 ScopedVector<google_apis::ResourceEntry> entries; | |
1023 entries.swap(*feed->mutable_entries()); | |
1024 FilterEntriesByTitleAndParent( | |
1025 &entries, expected_title, resource_id, parent_type); | |
1026 | |
1027 if (entries.empty()) { | |
1028 DVLOG(2) << "Uploaded file is not found"; | |
1029 callback.Run(google_apis::HTTP_NOT_FOUND, | |
1030 NO_DUPLICATES_FOUND, | |
1031 scoped_ptr<google_apis::ResourceEntry>()); | |
1032 return; | |
1033 } | |
1034 | |
1035 if (entries.size() >= 2) { | |
1036 DVLOG(2) << "Conflict detected on creating entry"; | |
1037 for (size_t i = 0; i < entries.size() - 1; ++i) { | |
1038 // TODO(tzik): Replace published_time with creation time after we move to | |
1039 // Drive API. | |
1040 if (entries[i]->published_time() < entries.back()->published_time()) | |
1041 std::swap(entries[i], entries.back()); | |
1042 } | |
1043 | |
1044 scoped_ptr<google_apis::ResourceEntry> earliest_entry(entries.back()); | |
1045 entries.back() = NULL; | |
1046 entries.get().pop_back(); | |
1047 | |
1048 DeleteEntriesForEnsuringTitleUniqueness( | |
1049 entries.Pass(), | |
1050 base::Bind(&EntryAdapterForEnsureTitleUniqueness, | |
1051 base::Passed(&earliest_entry), | |
1052 callback, | |
1053 RESOLVED_DUPLICATES)); | |
1054 return; | |
1055 } | |
1056 | |
1057 DVLOG(2) << "no conflict detected"; | |
1058 DCHECK_EQ(1u, entries.size()); | |
1059 scoped_ptr<google_apis::ResourceEntry> entry(entries.front()); | |
1060 entries.weak_clear(); | |
1061 | |
1062 callback.Run(google_apis::HTTP_SUCCESS, NO_DUPLICATES_FOUND, entry.Pass()); | |
1063 } | |
1064 | |
1065 void APIUtil::DeleteEntriesForEnsuringTitleUniqueness( | |
1066 ScopedVector<google_apis::ResourceEntry> entries, | |
1067 const GDataErrorCallback& callback) { | |
1068 DCHECK(CalledOnValidThread()); | |
1069 DVLOG(2) << "Cleaning up conflict on entry creation"; | |
1070 | |
1071 if (entries.empty()) { | |
1072 callback.Run(google_apis::HTTP_SUCCESS); | |
1073 return; | |
1074 } | |
1075 | |
1076 scoped_ptr<google_apis::ResourceEntry> entry(entries.back()); | |
1077 entries.back() = NULL; | |
1078 entries.get().pop_back(); | |
1079 | |
1080 // We don't care conflicts here as other clients may be also deleting this | |
1081 // file, so passing an empty etag. | |
1082 drive_service_->DeleteResource( | |
1083 entry->resource_id(), | |
1084 std::string(), // empty etag | |
1085 base::Bind(&APIUtil::DidDeleteEntriesForEnsuringTitleUniqueness, | |
1086 AsWeakPtr(), | |
1087 base::Passed(&entries), | |
1088 callback)); | |
1089 } | |
1090 | |
1091 void APIUtil::DidDeleteEntriesForEnsuringTitleUniqueness( | |
1092 ScopedVector<google_apis::ResourceEntry> entries, | |
1093 const GDataErrorCallback& callback, | |
1094 google_apis::GDataErrorCode error) { | |
1095 DCHECK(CalledOnValidThread()); | |
1096 | |
1097 if (error != google_apis::HTTP_SUCCESS && | |
1098 error != google_apis::HTTP_NOT_FOUND) { | |
1099 DVLOG(2) << "Error on deleting file: " << error; | |
1100 callback.Run(error); | |
1101 return; | |
1102 } | |
1103 | |
1104 DVLOG(2) << "Deletion completed"; | |
1105 DeleteEntriesForEnsuringTitleUniqueness(entries.Pass(), callback); | |
1106 } | |
1107 | |
1108 APIUtil::UploadKey APIUtil::RegisterUploadCallback( | |
1109 const UploadFileCallback& callback) { | |
1110 const bool inserted = upload_callback_map_.insert( | |
1111 std::make_pair(upload_next_key_, callback)).second; | |
1112 CHECK(inserted); | |
1113 return upload_next_key_++; | |
1114 } | |
1115 | |
1116 APIUtil::UploadFileCallback APIUtil::GetAndUnregisterUploadCallback( | |
1117 UploadKey key) { | |
1118 UploadFileCallback callback; | |
1119 UploadCallbackMap::iterator found = upload_callback_map_.find(key); | |
1120 if (found == upload_callback_map_.end()) | |
1121 return callback; | |
1122 callback = found->second; | |
1123 upload_callback_map_.erase(found); | |
1124 return callback; | |
1125 } | |
1126 | |
1127 void APIUtil::CancelAllUploads(google_apis::GDataErrorCode error) { | |
1128 if (upload_callback_map_.empty()) | |
1129 return; | |
1130 for (UploadCallbackMap::iterator iter = upload_callback_map_.begin(); | |
1131 iter != upload_callback_map_.end(); | |
1132 ++iter) { | |
1133 iter->second.Run(error, std::string(), std::string()); | |
1134 } | |
1135 upload_callback_map_.clear(); | |
1136 drive_uploader_.reset(new drive::DriveUploader( | |
1137 drive_service_.get(), content::BrowserThread::GetBlockingPool())); | |
1138 } | |
1139 | |
1140 std::string APIUtil::GetRootResourceId() const { | |
1141 if (IsDriveAPIDisabled()) | |
1142 return drive_service_->GetRootResourceId(); | |
1143 return root_resource_id_; | |
1144 } | |
1145 | |
1146 } // namespace drive_backend | |
1147 } // namespace sync_file_system | |
OLD | NEW |