OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/drive/fake_drive_service.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/files/file_util.h" | |
10 #include "base/json/json_string_value_serializer.h" | |
11 #include "base/logging.h" | |
12 #include "base/md5.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/strings/string_split.h" | |
15 #include "base/strings/string_tokenizer.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "base/strings/stringprintf.h" | |
18 #include "base/strings/utf_string_conversions.h" | |
19 #include "base/thread_task_runner_handle.h" | |
20 #include "base/values.h" | |
21 #include "chrome/browser/drive/drive_api_util.h" | |
22 #include "google_apis/drive/drive_api_parser.h" | |
23 #include "google_apis/drive/test_util.h" | |
24 #include "net/base/escape.h" | |
25 #include "net/base/url_util.h" | |
26 | |
27 using google_apis::AboutResource; | |
28 using google_apis::AboutResourceCallback; | |
29 using google_apis::AppList; | |
30 using google_apis::AppListCallback; | |
31 using google_apis::AuthStatusCallback; | |
32 using google_apis::AuthorizeAppCallback; | |
33 using google_apis::CancelCallback; | |
34 using google_apis::ChangeList; | |
35 using google_apis::ChangeListCallback; | |
36 using google_apis::ChangeResource; | |
37 using google_apis::DownloadActionCallback; | |
38 using google_apis::EntryActionCallback; | |
39 using google_apis::FileList; | |
40 using google_apis::FileListCallback; | |
41 using google_apis::FileResource; | |
42 using google_apis::FileResourceCallback; | |
43 using google_apis::DRIVE_FILE_ERROR; | |
44 using google_apis::DRIVE_NO_CONNECTION; | |
45 using google_apis::DRIVE_OTHER_ERROR; | |
46 using google_apis::DriveApiErrorCode; | |
47 using google_apis::GetContentCallback; | |
48 using google_apis::GetShareUrlCallback; | |
49 using google_apis::HTTP_BAD_REQUEST; | |
50 using google_apis::HTTP_CREATED; | |
51 using google_apis::HTTP_FORBIDDEN; | |
52 using google_apis::HTTP_NOT_FOUND; | |
53 using google_apis::HTTP_NO_CONTENT; | |
54 using google_apis::HTTP_PRECONDITION; | |
55 using google_apis::HTTP_RESUME_INCOMPLETE; | |
56 using google_apis::HTTP_SUCCESS; | |
57 using google_apis::InitiateUploadCallback; | |
58 using google_apis::ParentReference; | |
59 using google_apis::ProgressCallback; | |
60 using google_apis::UploadRangeResponse; | |
61 using google_apis::drive::UploadRangeCallback; | |
62 namespace test_util = google_apis::test_util; | |
63 | |
64 namespace drive { | |
65 namespace { | |
66 | |
67 // Returns true if the entry matches with the search query. | |
68 // Supports queries consist of following format. | |
69 // - Phrases quoted by double/single quotes | |
70 // - AND search for multiple words/phrases segmented by space | |
71 // - Limited attribute search. Only "title:" is supported. | |
72 bool EntryMatchWithQuery(const ChangeResource& entry, | |
73 const std::string& query) { | |
74 base::StringTokenizer tokenizer(query, " "); | |
75 tokenizer.set_quote_chars("\"'"); | |
76 while (tokenizer.GetNext()) { | |
77 std::string key, value; | |
78 const std::string& token = tokenizer.token(); | |
79 if (token.find(':') == std::string::npos) { | |
80 base::TrimString(token, "\"'", &value); | |
81 } else { | |
82 base::StringTokenizer key_value(token, ":"); | |
83 key_value.set_quote_chars("\"'"); | |
84 if (!key_value.GetNext()) | |
85 return false; | |
86 key = key_value.token(); | |
87 if (!key_value.GetNext()) | |
88 return false; | |
89 base::TrimString(key_value.token(), "\"'", &value); | |
90 } | |
91 | |
92 // TODO(peria): Deal with other attributes than title. | |
93 if (!key.empty() && key != "title") | |
94 return false; | |
95 // Search query in the title. | |
96 if (!entry.file() || | |
97 entry.file()->title().find(value) == std::string::npos) | |
98 return false; | |
99 } | |
100 return true; | |
101 } | |
102 | |
103 void ScheduleUploadRangeCallback(const UploadRangeCallback& callback, | |
104 int64 start_position, | |
105 int64 end_position, | |
106 DriveApiErrorCode error, | |
107 scoped_ptr<FileResource> entry) { | |
108 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
109 FROM_HERE, | |
110 base::Bind(callback, | |
111 UploadRangeResponse(error, | |
112 start_position, | |
113 end_position), | |
114 base::Passed(&entry))); | |
115 } | |
116 | |
117 void FileListCallbackAdapter(const FileListCallback& callback, | |
118 DriveApiErrorCode error, | |
119 scoped_ptr<ChangeList> change_list) { | |
120 scoped_ptr<FileList> file_list; | |
121 if (!change_list) { | |
122 callback.Run(error, file_list.Pass()); | |
123 return; | |
124 } | |
125 | |
126 file_list.reset(new FileList); | |
127 file_list->set_next_link(change_list->next_link()); | |
128 for (size_t i = 0; i < change_list->items().size(); ++i) { | |
129 const ChangeResource& entry = *change_list->items()[i]; | |
130 if (entry.file()) | |
131 file_list->mutable_items()->push_back(new FileResource(*entry.file())); | |
132 } | |
133 callback.Run(error, file_list.Pass()); | |
134 } | |
135 | |
136 bool UserHasWriteAccess(google_apis::drive::PermissionRole user_permission) { | |
137 switch (user_permission) { | |
138 case google_apis::drive::PERMISSION_ROLE_OWNER: | |
139 case google_apis::drive::PERMISSION_ROLE_WRITER: | |
140 return true; | |
141 case google_apis::drive::PERMISSION_ROLE_READER: | |
142 case google_apis::drive::PERMISSION_ROLE_COMMENTER: | |
143 break; | |
144 } | |
145 return false; | |
146 } | |
147 | |
148 void CallFileResouceCallback(const FileResourceCallback& callback, | |
149 const UploadRangeResponse& response, | |
150 scoped_ptr<FileResource> entry) { | |
151 callback.Run(response.code, entry.Pass()); | |
152 } | |
153 | |
154 struct CallResumeUpload { | |
155 CallResumeUpload() {} | |
156 ~CallResumeUpload() {} | |
157 | |
158 void Run(DriveApiErrorCode code, const GURL& upload_url) { | |
159 if (service) { | |
160 service->ResumeUpload( | |
161 upload_url, | |
162 /* start position */ 0, | |
163 /* end position */ content_length, | |
164 content_length, | |
165 content_type, | |
166 local_file_path, | |
167 base::Bind(&CallFileResouceCallback, callback), | |
168 progress_callback); | |
169 } | |
170 } | |
171 | |
172 base::WeakPtr<FakeDriveService> service; | |
173 int64 content_length; | |
174 std::string content_type; | |
175 base::FilePath local_file_path; | |
176 FileResourceCallback callback; | |
177 ProgressCallback progress_callback; | |
178 }; | |
179 | |
180 } // namespace | |
181 | |
182 struct FakeDriveService::EntryInfo { | |
183 EntryInfo() : user_permission(google_apis::drive::PERMISSION_ROLE_OWNER) {} | |
184 | |
185 google_apis::ChangeResource change_resource; | |
186 GURL share_url; | |
187 std::string content_data; | |
188 | |
189 // Behaves in the same way as "userPermission" described in | |
190 // https://developers.google.com/drive/v2/reference/files | |
191 google_apis::drive::PermissionRole user_permission; | |
192 }; | |
193 | |
194 struct FakeDriveService::UploadSession { | |
195 std::string content_type; | |
196 int64 content_length; | |
197 std::string parent_resource_id; | |
198 std::string resource_id; | |
199 std::string etag; | |
200 std::string title; | |
201 | |
202 int64 uploaded_size; | |
203 | |
204 UploadSession() | |
205 : content_length(0), | |
206 uploaded_size(0) {} | |
207 | |
208 UploadSession( | |
209 std::string content_type, | |
210 int64 content_length, | |
211 std::string parent_resource_id, | |
212 std::string resource_id, | |
213 std::string etag, | |
214 std::string title) | |
215 : content_type(content_type), | |
216 content_length(content_length), | |
217 parent_resource_id(parent_resource_id), | |
218 resource_id(resource_id), | |
219 etag(etag), | |
220 title(title), | |
221 uploaded_size(0) { | |
222 } | |
223 }; | |
224 | |
225 FakeDriveService::FakeDriveService() | |
226 : about_resource_(new AboutResource), | |
227 published_date_seq_(0), | |
228 next_upload_sequence_number_(0), | |
229 default_max_results_(0), | |
230 resource_id_count_(0), | |
231 file_list_load_count_(0), | |
232 change_list_load_count_(0), | |
233 directory_load_count_(0), | |
234 about_resource_load_count_(0), | |
235 app_list_load_count_(0), | |
236 blocked_file_list_load_count_(0), | |
237 offline_(false), | |
238 never_return_all_file_list_(false), | |
239 share_url_base_("https://share_url/"), | |
240 weak_ptr_factory_(this) { | |
241 about_resource_->set_largest_change_id(654321); | |
242 about_resource_->set_quota_bytes_total(9876543210); | |
243 about_resource_->set_quota_bytes_used_aggregate(6789012345); | |
244 about_resource_->set_root_folder_id(GetRootResourceId()); | |
245 } | |
246 | |
247 FakeDriveService::~FakeDriveService() { | |
248 DCHECK(thread_checker_.CalledOnValidThread()); | |
249 STLDeleteValues(&entries_); | |
250 } | |
251 | |
252 bool FakeDriveService::LoadAppListForDriveApi( | |
253 const std::string& relative_path) { | |
254 DCHECK(thread_checker_.CalledOnValidThread()); | |
255 | |
256 // Load JSON data, which must be a dictionary. | |
257 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); | |
258 CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); | |
259 app_info_value_.reset( | |
260 static_cast<base::DictionaryValue*>(value.release())); | |
261 return app_info_value_; | |
262 } | |
263 | |
264 void FakeDriveService::AddApp(const std::string& app_id, | |
265 const std::string& app_name, | |
266 const std::string& product_id, | |
267 const std::string& create_url, | |
268 bool is_removable) { | |
269 if (app_json_template_.empty()) { | |
270 base::FilePath path = | |
271 test_util::GetTestFilePath("drive/applist_app_template.json"); | |
272 CHECK(base::ReadFileToString(path, &app_json_template_)); | |
273 } | |
274 | |
275 std::string app_json = app_json_template_; | |
276 base::ReplaceSubstringsAfterOffset(&app_json, 0, "$AppId", app_id); | |
277 base::ReplaceSubstringsAfterOffset(&app_json, 0, "$AppName", app_name); | |
278 base::ReplaceSubstringsAfterOffset(&app_json, 0, "$ProductId", product_id); | |
279 base::ReplaceSubstringsAfterOffset(&app_json, 0, "$CreateUrl", create_url); | |
280 base::ReplaceSubstringsAfterOffset( | |
281 &app_json, 0, "$Removable", is_removable ? "true" : "false"); | |
282 | |
283 JSONStringValueDeserializer json(app_json); | |
284 std::string error_message; | |
285 scoped_ptr<base::Value> value(json.Deserialize(NULL, &error_message)); | |
286 CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); | |
287 | |
288 base::ListValue* item_list; | |
289 CHECK(app_info_value_->GetListWithoutPathExpansion("items", &item_list)); | |
290 item_list->Append(value.release()); | |
291 } | |
292 | |
293 void FakeDriveService::RemoveAppByProductId(const std::string& product_id) { | |
294 base::ListValue* item_list; | |
295 CHECK(app_info_value_->GetListWithoutPathExpansion("items", &item_list)); | |
296 for (size_t i = 0; i < item_list->GetSize(); ++i) { | |
297 base::DictionaryValue* item; | |
298 CHECK(item_list->GetDictionary(i, &item)); | |
299 const char kKeyProductId[] = "productId"; | |
300 std::string item_product_id; | |
301 if (item->GetStringWithoutPathExpansion(kKeyProductId, &item_product_id) && | |
302 product_id == item_product_id) { | |
303 item_list->Remove(i, NULL); | |
304 return; | |
305 } | |
306 } | |
307 } | |
308 | |
309 bool FakeDriveService::HasApp(const std::string& app_id) const { | |
310 base::ListValue* item_list; | |
311 CHECK(app_info_value_->GetListWithoutPathExpansion("items", &item_list)); | |
312 for (size_t i = 0; i < item_list->GetSize(); ++i) { | |
313 base::DictionaryValue* item; | |
314 CHECK(item_list->GetDictionary(i, &item)); | |
315 const char kKeyId[] = "id"; | |
316 std::string item_id; | |
317 if (item->GetStringWithoutPathExpansion(kKeyId, &item_id) && | |
318 item_id == app_id) { | |
319 return true; | |
320 } | |
321 } | |
322 | |
323 return false; | |
324 } | |
325 | |
326 void FakeDriveService::SetQuotaValue(int64 used, int64 total) { | |
327 DCHECK(thread_checker_.CalledOnValidThread()); | |
328 | |
329 about_resource_->set_quota_bytes_used_aggregate(used); | |
330 about_resource_->set_quota_bytes_total(total); | |
331 } | |
332 | |
333 GURL FakeDriveService::GetFakeLinkUrl(const std::string& resource_id) { | |
334 return GURL("https://fake_server/" + net::EscapePath(resource_id)); | |
335 } | |
336 | |
337 void FakeDriveService::Initialize(const std::string& account_id) { | |
338 DCHECK(thread_checker_.CalledOnValidThread()); | |
339 } | |
340 | |
341 void FakeDriveService::AddObserver(DriveServiceObserver* observer) { | |
342 DCHECK(thread_checker_.CalledOnValidThread()); | |
343 } | |
344 | |
345 void FakeDriveService::RemoveObserver(DriveServiceObserver* observer) { | |
346 DCHECK(thread_checker_.CalledOnValidThread()); | |
347 } | |
348 | |
349 bool FakeDriveService::CanSendRequest() const { | |
350 DCHECK(thread_checker_.CalledOnValidThread()); | |
351 return true; | |
352 } | |
353 | |
354 bool FakeDriveService::HasAccessToken() const { | |
355 DCHECK(thread_checker_.CalledOnValidThread()); | |
356 return true; | |
357 } | |
358 | |
359 void FakeDriveService::RequestAccessToken(const AuthStatusCallback& callback) { | |
360 DCHECK(thread_checker_.CalledOnValidThread()); | |
361 DCHECK(!callback.is_null()); | |
362 callback.Run(google_apis::HTTP_NOT_MODIFIED, "fake_access_token"); | |
363 } | |
364 | |
365 bool FakeDriveService::HasRefreshToken() const { | |
366 DCHECK(thread_checker_.CalledOnValidThread()); | |
367 return true; | |
368 } | |
369 | |
370 void FakeDriveService::ClearAccessToken() { | |
371 DCHECK(thread_checker_.CalledOnValidThread()); | |
372 } | |
373 | |
374 void FakeDriveService::ClearRefreshToken() { | |
375 DCHECK(thread_checker_.CalledOnValidThread()); | |
376 } | |
377 | |
378 std::string FakeDriveService::GetRootResourceId() const { | |
379 return "fake_root"; | |
380 } | |
381 | |
382 CancelCallback FakeDriveService::GetAllFileList( | |
383 const FileListCallback& callback) { | |
384 DCHECK(thread_checker_.CalledOnValidThread()); | |
385 DCHECK(!callback.is_null()); | |
386 | |
387 if (never_return_all_file_list_) { | |
388 ++blocked_file_list_load_count_; | |
389 return CancelCallback(); | |
390 } | |
391 | |
392 GetChangeListInternal(0, // start changestamp | |
393 std::string(), // empty search query | |
394 std::string(), // no directory resource id, | |
395 0, // start offset | |
396 default_max_results_, | |
397 &file_list_load_count_, | |
398 base::Bind(&FileListCallbackAdapter, callback)); | |
399 return CancelCallback(); | |
400 } | |
401 | |
402 CancelCallback FakeDriveService::GetFileListInDirectory( | |
403 const std::string& directory_resource_id, | |
404 const FileListCallback& callback) { | |
405 DCHECK(thread_checker_.CalledOnValidThread()); | |
406 DCHECK(!directory_resource_id.empty()); | |
407 DCHECK(!callback.is_null()); | |
408 | |
409 GetChangeListInternal(0, // start changestamp | |
410 std::string(), // empty search query | |
411 directory_resource_id, | |
412 0, // start offset | |
413 default_max_results_, | |
414 &directory_load_count_, | |
415 base::Bind(&FileListCallbackAdapter, callback)); | |
416 return CancelCallback(); | |
417 } | |
418 | |
419 CancelCallback FakeDriveService::Search( | |
420 const std::string& search_query, | |
421 const FileListCallback& callback) { | |
422 DCHECK(thread_checker_.CalledOnValidThread()); | |
423 DCHECK(!search_query.empty()); | |
424 DCHECK(!callback.is_null()); | |
425 | |
426 GetChangeListInternal(0, // start changestamp | |
427 search_query, | |
428 std::string(), // no directory resource id, | |
429 0, // start offset | |
430 default_max_results_, | |
431 NULL, | |
432 base::Bind(&FileListCallbackAdapter, callback)); | |
433 return CancelCallback(); | |
434 } | |
435 | |
436 CancelCallback FakeDriveService::SearchByTitle( | |
437 const std::string& title, | |
438 const std::string& directory_resource_id, | |
439 const FileListCallback& callback) { | |
440 DCHECK(thread_checker_.CalledOnValidThread()); | |
441 DCHECK(!title.empty()); | |
442 DCHECK(!callback.is_null()); | |
443 | |
444 // Note: the search implementation here doesn't support quotation unescape, | |
445 // so don't escape here. | |
446 GetChangeListInternal(0, // start changestamp | |
447 base::StringPrintf("title:'%s'", title.c_str()), | |
448 directory_resource_id, | |
449 0, // start offset | |
450 default_max_results_, | |
451 NULL, | |
452 base::Bind(&FileListCallbackAdapter, callback)); | |
453 return CancelCallback(); | |
454 } | |
455 | |
456 CancelCallback FakeDriveService::GetChangeList( | |
457 int64 start_changestamp, | |
458 const ChangeListCallback& callback) { | |
459 DCHECK(thread_checker_.CalledOnValidThread()); | |
460 DCHECK(!callback.is_null()); | |
461 | |
462 GetChangeListInternal(start_changestamp, | |
463 std::string(), // empty search query | |
464 std::string(), // no directory resource id, | |
465 0, // start offset | |
466 default_max_results_, | |
467 &change_list_load_count_, | |
468 callback); | |
469 return CancelCallback(); | |
470 } | |
471 | |
472 CancelCallback FakeDriveService::GetRemainingChangeList( | |
473 const GURL& next_link, | |
474 const ChangeListCallback& callback) { | |
475 DCHECK(thread_checker_.CalledOnValidThread()); | |
476 DCHECK(!next_link.is_empty()); | |
477 DCHECK(!callback.is_null()); | |
478 | |
479 // "changestamp", "q", "parent" and "start-offset" are parameters to | |
480 // implement "paging" of the result on FakeDriveService. | |
481 // The URL should be the one filled in GetChangeListInternal of the | |
482 // previous method invocation, so it should start with "http://localhost/?". | |
483 // See also GetChangeListInternal. | |
484 DCHECK_EQ(next_link.host(), "localhost"); | |
485 DCHECK_EQ(next_link.path(), "/"); | |
486 | |
487 int64 start_changestamp = 0; | |
488 std::string search_query; | |
489 std::string directory_resource_id; | |
490 int start_offset = 0; | |
491 int max_results = default_max_results_; | |
492 base::StringPairs parameters; | |
493 if (base::SplitStringIntoKeyValuePairs( | |
494 next_link.query(), '=', '&', ¶meters)) { | |
495 for (size_t i = 0; i < parameters.size(); ++i) { | |
496 if (parameters[i].first == "changestamp") { | |
497 base::StringToInt64(parameters[i].second, &start_changestamp); | |
498 } else if (parameters[i].first == "q") { | |
499 search_query = | |
500 net::UnescapeURLComponent(parameters[i].second, | |
501 net::UnescapeRule::URL_SPECIAL_CHARS); | |
502 } else if (parameters[i].first == "parent") { | |
503 directory_resource_id = | |
504 net::UnescapeURLComponent(parameters[i].second, | |
505 net::UnescapeRule::URL_SPECIAL_CHARS); | |
506 } else if (parameters[i].first == "start-offset") { | |
507 base::StringToInt(parameters[i].second, &start_offset); | |
508 } else if (parameters[i].first == "max-results") { | |
509 base::StringToInt(parameters[i].second, &max_results); | |
510 } | |
511 } | |
512 } | |
513 | |
514 GetChangeListInternal(start_changestamp, search_query, directory_resource_id, | |
515 start_offset, max_results, NULL, callback); | |
516 return CancelCallback(); | |
517 } | |
518 | |
519 CancelCallback FakeDriveService::GetRemainingFileList( | |
520 const GURL& next_link, | |
521 const FileListCallback& callback) { | |
522 DCHECK(thread_checker_.CalledOnValidThread()); | |
523 DCHECK(!next_link.is_empty()); | |
524 DCHECK(!callback.is_null()); | |
525 | |
526 return GetRemainingChangeList( | |
527 next_link, base::Bind(&FileListCallbackAdapter, callback)); | |
528 } | |
529 | |
530 CancelCallback FakeDriveService::GetFileResource( | |
531 const std::string& resource_id, | |
532 const FileResourceCallback& callback) { | |
533 DCHECK(thread_checker_.CalledOnValidThread()); | |
534 DCHECK(!callback.is_null()); | |
535 | |
536 if (offline_) { | |
537 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
538 FROM_HERE, | |
539 base::Bind(callback, | |
540 DRIVE_NO_CONNECTION, | |
541 base::Passed(scoped_ptr<FileResource>()))); | |
542 return CancelCallback(); | |
543 } | |
544 | |
545 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
546 if (entry && entry->change_resource.file()) { | |
547 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
548 FROM_HERE, | |
549 base::Bind(callback, HTTP_SUCCESS, base::Passed(make_scoped_ptr( | |
550 new FileResource(*entry->change_resource.file()))))); | |
551 return CancelCallback(); | |
552 } | |
553 | |
554 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
555 FROM_HERE, | |
556 base::Bind(callback, HTTP_NOT_FOUND, | |
557 base::Passed(scoped_ptr<FileResource>()))); | |
558 return CancelCallback(); | |
559 } | |
560 | |
561 CancelCallback FakeDriveService::GetShareUrl( | |
562 const std::string& resource_id, | |
563 const GURL& /* embed_origin */, | |
564 const GetShareUrlCallback& callback) { | |
565 DCHECK(thread_checker_.CalledOnValidThread()); | |
566 DCHECK(!callback.is_null()); | |
567 | |
568 if (offline_) { | |
569 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
570 FROM_HERE, | |
571 base::Bind(callback, | |
572 DRIVE_NO_CONNECTION, | |
573 GURL())); | |
574 return CancelCallback(); | |
575 } | |
576 | |
577 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
578 if (entry) { | |
579 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
580 FROM_HERE, | |
581 base::Bind(callback, HTTP_SUCCESS, entry->share_url)); | |
582 return CancelCallback(); | |
583 } | |
584 | |
585 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
586 FROM_HERE, | |
587 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | |
588 return CancelCallback(); | |
589 } | |
590 | |
591 CancelCallback FakeDriveService::GetAboutResource( | |
592 const AboutResourceCallback& callback) { | |
593 DCHECK(thread_checker_.CalledOnValidThread()); | |
594 DCHECK(!callback.is_null()); | |
595 | |
596 if (offline_) { | |
597 scoped_ptr<AboutResource> null; | |
598 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
599 FROM_HERE, | |
600 base::Bind(callback, | |
601 DRIVE_NO_CONNECTION, base::Passed(&null))); | |
602 return CancelCallback(); | |
603 } | |
604 | |
605 ++about_resource_load_count_; | |
606 scoped_ptr<AboutResource> about_resource(new AboutResource(*about_resource_)); | |
607 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
608 FROM_HERE, | |
609 base::Bind(callback, | |
610 HTTP_SUCCESS, base::Passed(&about_resource))); | |
611 return CancelCallback(); | |
612 } | |
613 | |
614 CancelCallback FakeDriveService::GetAppList(const AppListCallback& callback) { | |
615 DCHECK(thread_checker_.CalledOnValidThread()); | |
616 DCHECK(!callback.is_null()); | |
617 DCHECK(app_info_value_); | |
618 | |
619 if (offline_) { | |
620 scoped_ptr<AppList> null; | |
621 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
622 FROM_HERE, | |
623 base::Bind(callback, | |
624 DRIVE_NO_CONNECTION, | |
625 base::Passed(&null))); | |
626 return CancelCallback(); | |
627 } | |
628 | |
629 ++app_list_load_count_; | |
630 scoped_ptr<AppList> app_list(AppList::CreateFrom(*app_info_value_)); | |
631 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
632 FROM_HERE, | |
633 base::Bind(callback, HTTP_SUCCESS, base::Passed(&app_list))); | |
634 return CancelCallback(); | |
635 } | |
636 | |
637 CancelCallback FakeDriveService::DeleteResource( | |
638 const std::string& resource_id, | |
639 const std::string& etag, | |
640 const EntryActionCallback& callback) { | |
641 DCHECK(thread_checker_.CalledOnValidThread()); | |
642 DCHECK(!callback.is_null()); | |
643 | |
644 if (offline_) { | |
645 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
646 FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION)); | |
647 return CancelCallback(); | |
648 } | |
649 | |
650 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
651 if (!entry) { | |
652 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
653 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
654 return CancelCallback(); | |
655 } | |
656 | |
657 ChangeResource* change = &entry->change_resource; | |
658 const FileResource* file = change->file(); | |
659 if (change->is_deleted()) { | |
660 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
661 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
662 return CancelCallback(); | |
663 } | |
664 | |
665 if (!etag.empty() && etag != file->etag()) { | |
666 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
667 FROM_HERE, base::Bind(callback, HTTP_PRECONDITION)); | |
668 return CancelCallback(); | |
669 } | |
670 | |
671 if (entry->user_permission != google_apis::drive::PERMISSION_ROLE_OWNER) { | |
672 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
673 FROM_HERE, base::Bind(callback, HTTP_FORBIDDEN)); | |
674 return CancelCallback(); | |
675 } | |
676 | |
677 change->set_deleted(true); | |
678 AddNewChangestamp(change); | |
679 change->set_file(scoped_ptr<FileResource>()); | |
680 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
681 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); | |
682 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
683 FROM_HERE, | |
684 base::Bind(&FakeDriveService::NotifyObservers, | |
685 weak_ptr_factory_.GetWeakPtr())); | |
686 return CancelCallback(); | |
687 } | |
688 | |
689 CancelCallback FakeDriveService::TrashResource( | |
690 const std::string& resource_id, | |
691 const EntryActionCallback& callback) { | |
692 DCHECK(thread_checker_.CalledOnValidThread()); | |
693 DCHECK(!callback.is_null()); | |
694 | |
695 if (offline_) { | |
696 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
697 FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION)); | |
698 return CancelCallback(); | |
699 } | |
700 | |
701 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
702 if (!entry) { | |
703 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
704 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
705 return CancelCallback(); | |
706 } | |
707 | |
708 ChangeResource* change = &entry->change_resource; | |
709 FileResource* file = change->mutable_file(); | |
710 if (change->is_deleted() || file->labels().is_trashed()) { | |
711 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
712 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
713 return CancelCallback(); | |
714 } | |
715 | |
716 if (entry->user_permission != google_apis::drive::PERMISSION_ROLE_OWNER) { | |
717 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
718 FROM_HERE, base::Bind(callback, HTTP_FORBIDDEN)); | |
719 return CancelCallback(); | |
720 } | |
721 | |
722 file->mutable_labels()->set_trashed(true); | |
723 AddNewChangestamp(change); | |
724 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
725 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); | |
726 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
727 FROM_HERE, | |
728 base::Bind(&FakeDriveService::NotifyObservers, | |
729 weak_ptr_factory_.GetWeakPtr())); | |
730 return CancelCallback(); | |
731 } | |
732 | |
733 CancelCallback FakeDriveService::DownloadFile( | |
734 const base::FilePath& local_cache_path, | |
735 const std::string& resource_id, | |
736 const DownloadActionCallback& download_action_callback, | |
737 const GetContentCallback& get_content_callback, | |
738 const ProgressCallback& progress_callback) { | |
739 DCHECK(thread_checker_.CalledOnValidThread()); | |
740 DCHECK(!download_action_callback.is_null()); | |
741 | |
742 if (offline_) { | |
743 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
744 FROM_HERE, | |
745 base::Bind(download_action_callback, | |
746 DRIVE_NO_CONNECTION, | |
747 base::FilePath())); | |
748 return CancelCallback(); | |
749 } | |
750 | |
751 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
752 if (!entry || entry->change_resource.file()->IsHostedDocument()) { | |
753 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
754 FROM_HERE, | |
755 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); | |
756 return CancelCallback(); | |
757 } | |
758 | |
759 const FileResource* file = entry->change_resource.file(); | |
760 const std::string& content_data = entry->content_data; | |
761 int64 file_size = file->file_size(); | |
762 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); | |
763 | |
764 if (!get_content_callback.is_null()) { | |
765 const int64 kBlockSize = 5; | |
766 for (int64 i = 0; i < file_size; i += kBlockSize) { | |
767 const int64 size = std::min(kBlockSize, file_size - i); | |
768 scoped_ptr<std::string> content_for_callback( | |
769 new std::string(content_data.substr(i, size))); | |
770 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
771 FROM_HERE, | |
772 base::Bind(get_content_callback, HTTP_SUCCESS, | |
773 base::Passed(&content_for_callback))); | |
774 } | |
775 } | |
776 | |
777 if (!test_util::WriteStringToFile(local_cache_path, content_data)) { | |
778 // Failed to write the content. | |
779 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
780 FROM_HERE, | |
781 base::Bind(download_action_callback, | |
782 DRIVE_FILE_ERROR, base::FilePath())); | |
783 return CancelCallback(); | |
784 } | |
785 | |
786 if (!progress_callback.is_null()) { | |
787 // See also the comment in ResumeUpload(). For testing that clients | |
788 // can handle the case progress_callback is called multiple times, | |
789 // here we invoke the callback twice. | |
790 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
791 FROM_HERE, | |
792 base::Bind(progress_callback, file_size / 2, file_size)); | |
793 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
794 FROM_HERE, | |
795 base::Bind(progress_callback, file_size, file_size)); | |
796 } | |
797 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
798 FROM_HERE, | |
799 base::Bind(download_action_callback, | |
800 HTTP_SUCCESS, | |
801 local_cache_path)); | |
802 return CancelCallback(); | |
803 } | |
804 | |
805 CancelCallback FakeDriveService::CopyResource( | |
806 const std::string& resource_id, | |
807 const std::string& in_parent_resource_id, | |
808 const std::string& new_title, | |
809 const base::Time& last_modified, | |
810 const FileResourceCallback& callback) { | |
811 DCHECK(thread_checker_.CalledOnValidThread()); | |
812 DCHECK(!callback.is_null()); | |
813 | |
814 if (offline_) { | |
815 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
816 FROM_HERE, | |
817 base::Bind(callback, | |
818 DRIVE_NO_CONNECTION, | |
819 base::Passed(scoped_ptr<FileResource>()))); | |
820 return CancelCallback(); | |
821 } | |
822 | |
823 const std::string& parent_resource_id = in_parent_resource_id.empty() ? | |
824 GetRootResourceId() : in_parent_resource_id; | |
825 | |
826 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
827 if (!entry) { | |
828 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
829 FROM_HERE, | |
830 base::Bind(callback, HTTP_NOT_FOUND, | |
831 base::Passed(scoped_ptr<FileResource>()))); | |
832 return CancelCallback(); | |
833 } | |
834 | |
835 // Make a copy and set the new resource ID and the new title. | |
836 scoped_ptr<EntryInfo> copied_entry(new EntryInfo); | |
837 copied_entry->content_data = entry->content_data; | |
838 copied_entry->share_url = entry->share_url; | |
839 copied_entry->change_resource.set_file( | |
840 make_scoped_ptr(new FileResource(*entry->change_resource.file()))); | |
841 | |
842 ChangeResource* new_change = &copied_entry->change_resource; | |
843 FileResource* new_file = new_change->mutable_file(); | |
844 const std::string new_resource_id = GetNewResourceId(); | |
845 new_change->set_file_id(new_resource_id); | |
846 new_file->set_file_id(new_resource_id); | |
847 new_file->set_title(new_title); | |
848 | |
849 ParentReference parent; | |
850 parent.set_file_id(parent_resource_id); | |
851 parent.set_parent_link(GetFakeLinkUrl(parent_resource_id)); | |
852 std::vector<ParentReference> parents; | |
853 parents.push_back(parent); | |
854 *new_file->mutable_parents() = parents; | |
855 | |
856 if (!last_modified.is_null()) | |
857 new_file->set_modified_date(last_modified); | |
858 | |
859 AddNewChangestamp(new_change); | |
860 UpdateETag(new_file); | |
861 | |
862 // Add the new entry to the map. | |
863 entries_[new_resource_id] = copied_entry.release(); | |
864 | |
865 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
866 FROM_HERE, | |
867 base::Bind(callback, | |
868 HTTP_SUCCESS, | |
869 base::Passed(make_scoped_ptr(new FileResource(*new_file))))); | |
870 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
871 FROM_HERE, | |
872 base::Bind(&FakeDriveService::NotifyObservers, | |
873 weak_ptr_factory_.GetWeakPtr())); | |
874 return CancelCallback(); | |
875 } | |
876 | |
877 CancelCallback FakeDriveService::UpdateResource( | |
878 const std::string& resource_id, | |
879 const std::string& parent_resource_id, | |
880 const std::string& new_title, | |
881 const base::Time& last_modified, | |
882 const base::Time& last_viewed_by_me, | |
883 const google_apis::drive::Properties& properties, | |
884 const google_apis::FileResourceCallback& callback) { | |
885 DCHECK(thread_checker_.CalledOnValidThread()); | |
886 DCHECK(!callback.is_null()); | |
887 | |
888 if (offline_) { | |
889 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
890 FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION, | |
891 base::Passed(scoped_ptr<FileResource>()))); | |
892 return CancelCallback(); | |
893 } | |
894 | |
895 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
896 if (!entry) { | |
897 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
898 FROM_HERE, | |
899 base::Bind(callback, HTTP_NOT_FOUND, | |
900 base::Passed(scoped_ptr<FileResource>()))); | |
901 return CancelCallback(); | |
902 } | |
903 | |
904 if (!UserHasWriteAccess(entry->user_permission)) { | |
905 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
906 FROM_HERE, | |
907 base::Bind(callback, HTTP_FORBIDDEN, | |
908 base::Passed(scoped_ptr<FileResource>()))); | |
909 return CancelCallback(); | |
910 } | |
911 | |
912 ChangeResource* change = &entry->change_resource; | |
913 FileResource* file = change->mutable_file(); | |
914 | |
915 if (!new_title.empty()) | |
916 file->set_title(new_title); | |
917 | |
918 // Set parent if necessary. | |
919 if (!parent_resource_id.empty()) { | |
920 ParentReference parent; | |
921 parent.set_file_id(parent_resource_id); | |
922 parent.set_parent_link(GetFakeLinkUrl(parent_resource_id)); | |
923 | |
924 std::vector<ParentReference> parents; | |
925 parents.push_back(parent); | |
926 *file->mutable_parents() = parents; | |
927 } | |
928 | |
929 if (!last_modified.is_null()) | |
930 file->set_modified_date(last_modified); | |
931 | |
932 if (!last_viewed_by_me.is_null()) | |
933 file->set_last_viewed_by_me_date(last_viewed_by_me); | |
934 | |
935 AddNewChangestamp(change); | |
936 UpdateETag(file); | |
937 | |
938 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
939 FROM_HERE, | |
940 base::Bind(callback, HTTP_SUCCESS, | |
941 base::Passed(make_scoped_ptr(new FileResource(*file))))); | |
942 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
943 FROM_HERE, | |
944 base::Bind(&FakeDriveService::NotifyObservers, | |
945 weak_ptr_factory_.GetWeakPtr())); | |
946 return CancelCallback(); | |
947 } | |
948 | |
949 CancelCallback FakeDriveService::AddResourceToDirectory( | |
950 const std::string& parent_resource_id, | |
951 const std::string& resource_id, | |
952 const EntryActionCallback& callback) { | |
953 DCHECK(thread_checker_.CalledOnValidThread()); | |
954 DCHECK(!callback.is_null()); | |
955 | |
956 if (offline_) { | |
957 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
958 FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION)); | |
959 return CancelCallback(); | |
960 } | |
961 | |
962 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
963 if (!entry) { | |
964 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
965 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
966 return CancelCallback(); | |
967 } | |
968 | |
969 ChangeResource* change = &entry->change_resource; | |
970 // On the real Drive server, resources do not necessary shape a tree | |
971 // structure. That is, each resource can have multiple parent. | |
972 // We mimic the behavior here; AddResourceToDirectoy just adds | |
973 // one more parent, not overwriting old ones. | |
974 ParentReference parent; | |
975 parent.set_file_id(parent_resource_id); | |
976 parent.set_parent_link(GetFakeLinkUrl(parent_resource_id)); | |
977 change->mutable_file()->mutable_parents()->push_back(parent); | |
978 | |
979 AddNewChangestamp(change); | |
980 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
981 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); | |
982 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
983 FROM_HERE, | |
984 base::Bind(&FakeDriveService::NotifyObservers, | |
985 weak_ptr_factory_.GetWeakPtr())); | |
986 return CancelCallback(); | |
987 } | |
988 | |
989 CancelCallback FakeDriveService::RemoveResourceFromDirectory( | |
990 const std::string& parent_resource_id, | |
991 const std::string& resource_id, | |
992 const EntryActionCallback& callback) { | |
993 DCHECK(thread_checker_.CalledOnValidThread()); | |
994 DCHECK(!callback.is_null()); | |
995 | |
996 if (offline_) { | |
997 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
998 FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION)); | |
999 return CancelCallback(); | |
1000 } | |
1001 | |
1002 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
1003 if (!entry) { | |
1004 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1005 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
1006 return CancelCallback(); | |
1007 } | |
1008 | |
1009 ChangeResource* change = &entry->change_resource; | |
1010 FileResource* file = change->mutable_file(); | |
1011 std::vector<ParentReference>* parents = file->mutable_parents(); | |
1012 for (size_t i = 0; i < parents->size(); ++i) { | |
1013 if ((*parents)[i].file_id() == parent_resource_id) { | |
1014 parents->erase(parents->begin() + i); | |
1015 AddNewChangestamp(change); | |
1016 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1017 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); | |
1018 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1019 FROM_HERE, | |
1020 base::Bind(&FakeDriveService::NotifyObservers, | |
1021 weak_ptr_factory_.GetWeakPtr())); | |
1022 return CancelCallback(); | |
1023 } | |
1024 } | |
1025 | |
1026 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1027 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
1028 return CancelCallback(); | |
1029 } | |
1030 | |
1031 CancelCallback FakeDriveService::AddNewDirectory( | |
1032 const std::string& parent_resource_id, | |
1033 const std::string& directory_title, | |
1034 const AddNewDirectoryOptions& options, | |
1035 const FileResourceCallback& callback) { | |
1036 return AddNewDirectoryWithResourceId( | |
1037 "", | |
1038 parent_resource_id.empty() ? GetRootResourceId() : parent_resource_id, | |
1039 directory_title, | |
1040 options, | |
1041 callback); | |
1042 } | |
1043 | |
1044 CancelCallback FakeDriveService::InitiateUploadNewFile( | |
1045 const std::string& content_type, | |
1046 int64 content_length, | |
1047 const std::string& parent_resource_id, | |
1048 const std::string& title, | |
1049 const UploadNewFileOptions& options, | |
1050 const InitiateUploadCallback& callback) { | |
1051 DCHECK(thread_checker_.CalledOnValidThread()); | |
1052 DCHECK(!callback.is_null()); | |
1053 | |
1054 if (offline_) { | |
1055 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1056 FROM_HERE, | |
1057 base::Bind(callback, DRIVE_NO_CONNECTION, GURL())); | |
1058 return CancelCallback(); | |
1059 } | |
1060 | |
1061 if (parent_resource_id != GetRootResourceId() && | |
1062 !entries_.count(parent_resource_id)) { | |
1063 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1064 FROM_HERE, | |
1065 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | |
1066 return CancelCallback(); | |
1067 } | |
1068 | |
1069 GURL session_url = GetNewUploadSessionUrl(); | |
1070 upload_sessions_[session_url] = | |
1071 UploadSession(content_type, content_length, | |
1072 parent_resource_id, | |
1073 "", // resource_id | |
1074 "", // etag | |
1075 title); | |
1076 | |
1077 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1078 FROM_HERE, | |
1079 base::Bind(callback, HTTP_SUCCESS, session_url)); | |
1080 return CancelCallback(); | |
1081 } | |
1082 | |
1083 CancelCallback FakeDriveService::InitiateUploadExistingFile( | |
1084 const std::string& content_type, | |
1085 int64 content_length, | |
1086 const std::string& resource_id, | |
1087 const UploadExistingFileOptions& options, | |
1088 const InitiateUploadCallback& callback) { | |
1089 DCHECK(thread_checker_.CalledOnValidThread()); | |
1090 DCHECK(!callback.is_null()); | |
1091 | |
1092 if (offline_) { | |
1093 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1094 FROM_HERE, | |
1095 base::Bind(callback, DRIVE_NO_CONNECTION, GURL())); | |
1096 return CancelCallback(); | |
1097 } | |
1098 | |
1099 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
1100 if (!entry) { | |
1101 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1102 FROM_HERE, | |
1103 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | |
1104 return CancelCallback(); | |
1105 } | |
1106 | |
1107 if (!UserHasWriteAccess(entry->user_permission)) { | |
1108 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1109 FROM_HERE, | |
1110 base::Bind(callback, HTTP_FORBIDDEN, GURL())); | |
1111 return CancelCallback(); | |
1112 } | |
1113 | |
1114 FileResource* file = entry->change_resource.mutable_file(); | |
1115 if (!options.etag.empty() && options.etag != file->etag()) { | |
1116 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1117 FROM_HERE, | |
1118 base::Bind(callback, HTTP_PRECONDITION, GURL())); | |
1119 return CancelCallback(); | |
1120 } | |
1121 // TODO(hashimoto): Update |file|'s metadata with |options|. | |
1122 | |
1123 GURL session_url = GetNewUploadSessionUrl(); | |
1124 upload_sessions_[session_url] = | |
1125 UploadSession(content_type, content_length, | |
1126 "", // parent_resource_id | |
1127 resource_id, | |
1128 file->etag(), | |
1129 "" /* title */); | |
1130 | |
1131 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1132 FROM_HERE, | |
1133 base::Bind(callback, HTTP_SUCCESS, session_url)); | |
1134 return CancelCallback(); | |
1135 } | |
1136 | |
1137 CancelCallback FakeDriveService::GetUploadStatus( | |
1138 const GURL& upload_url, | |
1139 int64 content_length, | |
1140 const UploadRangeCallback& callback) { | |
1141 DCHECK(thread_checker_.CalledOnValidThread()); | |
1142 DCHECK(!callback.is_null()); | |
1143 return CancelCallback(); | |
1144 } | |
1145 | |
1146 CancelCallback FakeDriveService::ResumeUpload( | |
1147 const GURL& upload_url, | |
1148 int64 start_position, | |
1149 int64 end_position, | |
1150 int64 content_length, | |
1151 const std::string& content_type, | |
1152 const base::FilePath& local_file_path, | |
1153 const UploadRangeCallback& callback, | |
1154 const ProgressCallback& progress_callback) { | |
1155 DCHECK(thread_checker_.CalledOnValidThread()); | |
1156 DCHECK(!callback.is_null()); | |
1157 | |
1158 FileResourceCallback completion_callback | |
1159 = base::Bind(&ScheduleUploadRangeCallback, | |
1160 callback, start_position, end_position); | |
1161 | |
1162 if (offline_) { | |
1163 completion_callback.Run(DRIVE_NO_CONNECTION, scoped_ptr<FileResource>()); | |
1164 return CancelCallback(); | |
1165 } | |
1166 | |
1167 if (!upload_sessions_.count(upload_url)) { | |
1168 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<FileResource>()); | |
1169 return CancelCallback(); | |
1170 } | |
1171 | |
1172 UploadSession* session = &upload_sessions_[upload_url]; | |
1173 | |
1174 // Chunks are required to be sent in such a ways that they fill from the start | |
1175 // of the not-yet-uploaded part with no gaps nor overlaps. | |
1176 if (session->uploaded_size != start_position) { | |
1177 completion_callback.Run(HTTP_BAD_REQUEST, scoped_ptr<FileResource>()); | |
1178 return CancelCallback(); | |
1179 } | |
1180 | |
1181 if (!progress_callback.is_null()) { | |
1182 // In the real GDataWapi/Drive DriveService, progress is reported in | |
1183 // nondeterministic timing. In this fake implementation, we choose to call | |
1184 // it twice per one ResumeUpload. This is for making sure that client code | |
1185 // works fine even if the callback is invoked more than once; it is the | |
1186 // crucial difference of the progress callback from others. | |
1187 // Note that progress is notified in the relative offset in each chunk. | |
1188 const int64 chunk_size = end_position - start_position; | |
1189 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1190 FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size)); | |
1191 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1192 FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size)); | |
1193 } | |
1194 | |
1195 if (content_length != end_position) { | |
1196 session->uploaded_size = end_position; | |
1197 completion_callback.Run(HTTP_RESUME_INCOMPLETE, scoped_ptr<FileResource>()); | |
1198 return CancelCallback(); | |
1199 } | |
1200 | |
1201 std::string content_data; | |
1202 if (!base::ReadFileToString(local_file_path, &content_data)) { | |
1203 session->uploaded_size = end_position; | |
1204 completion_callback.Run(DRIVE_FILE_ERROR, scoped_ptr<FileResource>()); | |
1205 return CancelCallback(); | |
1206 } | |
1207 session->uploaded_size = end_position; | |
1208 | |
1209 // |resource_id| is empty if the upload is for new file. | |
1210 if (session->resource_id.empty()) { | |
1211 DCHECK(!session->parent_resource_id.empty()); | |
1212 DCHECK(!session->title.empty()); | |
1213 const EntryInfo* new_entry = AddNewEntry( | |
1214 "", // auto generate resource id. | |
1215 session->content_type, | |
1216 content_data, | |
1217 session->parent_resource_id, | |
1218 session->title, | |
1219 false); // shared_with_me | |
1220 if (!new_entry) { | |
1221 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<FileResource>()); | |
1222 return CancelCallback(); | |
1223 } | |
1224 | |
1225 completion_callback.Run(HTTP_CREATED, make_scoped_ptr( | |
1226 new FileResource(*new_entry->change_resource.file()))); | |
1227 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1228 FROM_HERE, | |
1229 base::Bind(&FakeDriveService::NotifyObservers, | |
1230 weak_ptr_factory_.GetWeakPtr())); | |
1231 return CancelCallback(); | |
1232 } | |
1233 | |
1234 EntryInfo* entry = FindEntryByResourceId(session->resource_id); | |
1235 if (!entry) { | |
1236 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<FileResource>()); | |
1237 return CancelCallback(); | |
1238 } | |
1239 | |
1240 ChangeResource* change = &entry->change_resource; | |
1241 FileResource* file = change->mutable_file(); | |
1242 if (file->etag().empty() || session->etag != file->etag()) { | |
1243 completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<FileResource>()); | |
1244 return CancelCallback(); | |
1245 } | |
1246 | |
1247 file->set_md5_checksum(base::MD5String(content_data)); | |
1248 entry->content_data = content_data; | |
1249 file->set_file_size(end_position); | |
1250 AddNewChangestamp(change); | |
1251 UpdateETag(file); | |
1252 | |
1253 completion_callback.Run(HTTP_SUCCESS, make_scoped_ptr( | |
1254 new FileResource(*file))); | |
1255 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1256 FROM_HERE, | |
1257 base::Bind(&FakeDriveService::NotifyObservers, | |
1258 weak_ptr_factory_.GetWeakPtr())); | |
1259 return CancelCallback(); | |
1260 } | |
1261 | |
1262 CancelCallback FakeDriveService::MultipartUploadNewFile( | |
1263 const std::string& content_type, | |
1264 int64 content_length, | |
1265 const std::string& parent_resource_id, | |
1266 const std::string& title, | |
1267 const base::FilePath& local_file_path, | |
1268 const UploadNewFileOptions& options, | |
1269 const FileResourceCallback& callback, | |
1270 const ProgressCallback& progress_callback) { | |
1271 CallResumeUpload* const call_resume_upload = new CallResumeUpload(); | |
1272 call_resume_upload->service = weak_ptr_factory_.GetWeakPtr(); | |
1273 call_resume_upload->content_type = content_type; | |
1274 call_resume_upload->content_length = content_length; | |
1275 call_resume_upload->local_file_path = local_file_path; | |
1276 call_resume_upload->callback = callback; | |
1277 call_resume_upload->progress_callback = progress_callback; | |
1278 InitiateUploadNewFile( | |
1279 content_type, | |
1280 content_length, | |
1281 parent_resource_id, | |
1282 title, | |
1283 options, | |
1284 base::Bind(&CallResumeUpload::Run, base::Owned(call_resume_upload))); | |
1285 return CancelCallback(); | |
1286 } | |
1287 | |
1288 CancelCallback FakeDriveService::MultipartUploadExistingFile( | |
1289 const std::string& content_type, | |
1290 int64 content_length, | |
1291 const std::string& resource_id, | |
1292 const base::FilePath& local_file_path, | |
1293 const UploadExistingFileOptions& options, | |
1294 const FileResourceCallback& callback, | |
1295 const ProgressCallback& progress_callback) { | |
1296 CallResumeUpload* const call_resume_upload = new CallResumeUpload(); | |
1297 call_resume_upload->service = weak_ptr_factory_.GetWeakPtr(); | |
1298 call_resume_upload->content_type = content_type; | |
1299 call_resume_upload->content_length = content_length; | |
1300 call_resume_upload->local_file_path = local_file_path; | |
1301 call_resume_upload->callback = callback; | |
1302 call_resume_upload->progress_callback = progress_callback; | |
1303 InitiateUploadExistingFile( | |
1304 content_type, | |
1305 content_length, | |
1306 resource_id, | |
1307 options, | |
1308 base::Bind(&CallResumeUpload::Run, base::Owned(call_resume_upload))); | |
1309 return CancelCallback(); | |
1310 } | |
1311 | |
1312 CancelCallback FakeDriveService::AuthorizeApp( | |
1313 const std::string& resource_id, | |
1314 const std::string& app_id, | |
1315 const AuthorizeAppCallback& callback) { | |
1316 DCHECK(thread_checker_.CalledOnValidThread()); | |
1317 DCHECK(!callback.is_null()); | |
1318 | |
1319 if (entries_.count(resource_id) == 0) { | |
1320 callback.Run(google_apis::HTTP_NOT_FOUND, GURL()); | |
1321 return CancelCallback(); | |
1322 } | |
1323 | |
1324 callback.Run(HTTP_SUCCESS, | |
1325 GURL(base::StringPrintf(open_url_format_.c_str(), | |
1326 resource_id.c_str(), | |
1327 app_id.c_str()))); | |
1328 return CancelCallback(); | |
1329 } | |
1330 | |
1331 CancelCallback FakeDriveService::UninstallApp( | |
1332 const std::string& app_id, | |
1333 const google_apis::EntryActionCallback& callback) { | |
1334 DCHECK(thread_checker_.CalledOnValidThread()); | |
1335 DCHECK(!callback.is_null()); | |
1336 | |
1337 if (offline_) { | |
1338 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1339 FROM_HERE, | |
1340 base::Bind(callback, google_apis::DRIVE_NO_CONNECTION)); | |
1341 return CancelCallback(); | |
1342 } | |
1343 | |
1344 // Find app_id from app_info_value_ and delete. | |
1345 base::ListValue* items = NULL; | |
1346 if (!app_info_value_->GetList("items", &items)) { | |
1347 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1348 FROM_HERE, | |
1349 base::Bind(callback, google_apis::HTTP_NOT_FOUND)); | |
1350 return CancelCallback(); | |
1351 } | |
1352 | |
1353 for (size_t i = 0; i < items->GetSize(); ++i) { | |
1354 base::DictionaryValue* item = NULL; | |
1355 std::string id; | |
1356 if (items->GetDictionary(i, &item) && item->GetString("id", &id) && | |
1357 id == app_id) { | |
1358 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1359 FROM_HERE, | |
1360 base::Bind(callback, | |
1361 items->Remove(i, NULL) ? google_apis::HTTP_NO_CONTENT | |
1362 : google_apis::HTTP_NOT_FOUND)); | |
1363 return CancelCallback(); | |
1364 } | |
1365 } | |
1366 | |
1367 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1368 FROM_HERE, | |
1369 base::Bind(callback, google_apis::HTTP_NOT_FOUND)); | |
1370 return CancelCallback(); | |
1371 } | |
1372 | |
1373 void FakeDriveService::AddNewFile(const std::string& content_type, | |
1374 const std::string& content_data, | |
1375 const std::string& parent_resource_id, | |
1376 const std::string& title, | |
1377 bool shared_with_me, | |
1378 const FileResourceCallback& callback) { | |
1379 AddNewFileWithResourceId("", content_type, content_data, parent_resource_id, | |
1380 title, shared_with_me, callback); | |
1381 } | |
1382 | |
1383 void FakeDriveService::AddNewFileWithResourceId( | |
1384 const std::string& resource_id, | |
1385 const std::string& content_type, | |
1386 const std::string& content_data, | |
1387 const std::string& parent_resource_id, | |
1388 const std::string& title, | |
1389 bool shared_with_me, | |
1390 const FileResourceCallback& callback) { | |
1391 DCHECK(thread_checker_.CalledOnValidThread()); | |
1392 DCHECK(!callback.is_null()); | |
1393 | |
1394 if (offline_) { | |
1395 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1396 FROM_HERE, | |
1397 base::Bind(callback, | |
1398 DRIVE_NO_CONNECTION, | |
1399 base::Passed(scoped_ptr<FileResource>()))); | |
1400 return; | |
1401 } | |
1402 | |
1403 const EntryInfo* new_entry = AddNewEntry(resource_id, | |
1404 content_type, | |
1405 content_data, | |
1406 parent_resource_id, | |
1407 title, | |
1408 shared_with_me); | |
1409 if (!new_entry) { | |
1410 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1411 FROM_HERE, | |
1412 base::Bind(callback, HTTP_NOT_FOUND, | |
1413 base::Passed(scoped_ptr<FileResource>()))); | |
1414 return; | |
1415 } | |
1416 | |
1417 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1418 FROM_HERE, | |
1419 base::Bind(callback, HTTP_CREATED, | |
1420 base::Passed(make_scoped_ptr( | |
1421 new FileResource(*new_entry->change_resource.file()))))); | |
1422 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1423 FROM_HERE, | |
1424 base::Bind(&FakeDriveService::NotifyObservers, | |
1425 weak_ptr_factory_.GetWeakPtr())); | |
1426 } | |
1427 | |
1428 CancelCallback FakeDriveService::AddNewDirectoryWithResourceId( | |
1429 const std::string& resource_id, | |
1430 const std::string& parent_resource_id, | |
1431 const std::string& directory_title, | |
1432 const AddNewDirectoryOptions& options, | |
1433 const FileResourceCallback& callback) { | |
1434 DCHECK(thread_checker_.CalledOnValidThread()); | |
1435 DCHECK(!callback.is_null()); | |
1436 | |
1437 if (offline_) { | |
1438 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1439 FROM_HERE, | |
1440 base::Bind(callback, | |
1441 DRIVE_NO_CONNECTION, | |
1442 base::Passed(scoped_ptr<FileResource>()))); | |
1443 return CancelCallback(); | |
1444 } | |
1445 | |
1446 const EntryInfo* new_entry = AddNewEntry(resource_id, | |
1447 util::kDriveFolderMimeType, | |
1448 "", // content_data | |
1449 parent_resource_id, | |
1450 directory_title, | |
1451 false); // shared_with_me | |
1452 if (!new_entry) { | |
1453 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1454 FROM_HERE, | |
1455 base::Bind(callback, HTTP_NOT_FOUND, | |
1456 base::Passed(scoped_ptr<FileResource>()))); | |
1457 return CancelCallback(); | |
1458 } | |
1459 | |
1460 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1461 FROM_HERE, | |
1462 base::Bind(callback, HTTP_CREATED, | |
1463 base::Passed(make_scoped_ptr( | |
1464 new FileResource(*new_entry->change_resource.file()))))); | |
1465 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1466 FROM_HERE, | |
1467 base::Bind(&FakeDriveService::NotifyObservers, | |
1468 weak_ptr_factory_.GetWeakPtr())); | |
1469 return CancelCallback(); | |
1470 } | |
1471 | |
1472 void FakeDriveService::SetLastModifiedTime( | |
1473 const std::string& resource_id, | |
1474 const base::Time& last_modified_time, | |
1475 const FileResourceCallback& callback) { | |
1476 DCHECK(thread_checker_.CalledOnValidThread()); | |
1477 DCHECK(!callback.is_null()); | |
1478 | |
1479 if (offline_) { | |
1480 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1481 FROM_HERE, | |
1482 base::Bind(callback, | |
1483 DRIVE_NO_CONNECTION, | |
1484 base::Passed(scoped_ptr<FileResource>()))); | |
1485 return; | |
1486 } | |
1487 | |
1488 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
1489 if (!entry) { | |
1490 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1491 FROM_HERE, | |
1492 base::Bind(callback, HTTP_NOT_FOUND, | |
1493 base::Passed(scoped_ptr<FileResource>()))); | |
1494 return; | |
1495 } | |
1496 | |
1497 ChangeResource* change = &entry->change_resource; | |
1498 FileResource* file = change->mutable_file(); | |
1499 file->set_modified_date(last_modified_time); | |
1500 | |
1501 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1502 FROM_HERE, | |
1503 base::Bind(callback, HTTP_SUCCESS, | |
1504 base::Passed(make_scoped_ptr(new FileResource(*file))))); | |
1505 } | |
1506 | |
1507 google_apis::DriveApiErrorCode FakeDriveService::SetUserPermission( | |
1508 const std::string& resource_id, | |
1509 google_apis::drive::PermissionRole user_permission) { | |
1510 DCHECK(thread_checker_.CalledOnValidThread()); | |
1511 | |
1512 EntryInfo* entry = FindEntryByResourceId(resource_id); | |
1513 if (!entry) | |
1514 return HTTP_NOT_FOUND; | |
1515 | |
1516 entry->user_permission = user_permission; | |
1517 return HTTP_SUCCESS; | |
1518 } | |
1519 | |
1520 void FakeDriveService::AddChangeObserver(ChangeObserver* change_observer) { | |
1521 change_observers_.AddObserver(change_observer); | |
1522 } | |
1523 | |
1524 void FakeDriveService::RemoveChangeObserver(ChangeObserver* change_observer) { | |
1525 change_observers_.RemoveObserver(change_observer); | |
1526 } | |
1527 | |
1528 FakeDriveService::EntryInfo* FakeDriveService::FindEntryByResourceId( | |
1529 const std::string& resource_id) { | |
1530 DCHECK(thread_checker_.CalledOnValidThread()); | |
1531 | |
1532 EntryInfoMap::iterator it = entries_.find(resource_id); | |
1533 // Deleted entries don't have FileResource. | |
1534 return it != entries_.end() && it->second->change_resource.file() ? | |
1535 it->second : NULL; | |
1536 } | |
1537 | |
1538 std::string FakeDriveService::GetNewResourceId() { | |
1539 DCHECK(thread_checker_.CalledOnValidThread()); | |
1540 | |
1541 ++resource_id_count_; | |
1542 return base::StringPrintf("resource_id_%d", resource_id_count_); | |
1543 } | |
1544 | |
1545 void FakeDriveService::UpdateETag(google_apis::FileResource* file) { | |
1546 file->set_etag( | |
1547 "etag_" + base::Int64ToString(about_resource_->largest_change_id())); | |
1548 } | |
1549 | |
1550 void FakeDriveService::AddNewChangestamp(google_apis::ChangeResource* change) { | |
1551 about_resource_->set_largest_change_id( | |
1552 about_resource_->largest_change_id() + 1); | |
1553 change->set_change_id(about_resource_->largest_change_id()); | |
1554 } | |
1555 | |
1556 const FakeDriveService::EntryInfo* FakeDriveService::AddNewEntry( | |
1557 const std::string& given_resource_id, | |
1558 const std::string& content_type, | |
1559 const std::string& content_data, | |
1560 const std::string& parent_resource_id, | |
1561 const std::string& title, | |
1562 bool shared_with_me) { | |
1563 DCHECK(thread_checker_.CalledOnValidThread()); | |
1564 | |
1565 if (!parent_resource_id.empty() && | |
1566 parent_resource_id != GetRootResourceId() && | |
1567 !entries_.count(parent_resource_id)) { | |
1568 return NULL; | |
1569 } | |
1570 | |
1571 const std::string resource_id = | |
1572 given_resource_id.empty() ? GetNewResourceId() : given_resource_id; | |
1573 if (entries_.count(resource_id)) | |
1574 return NULL; | |
1575 GURL upload_url = GURL("https://xxx/upload/" + resource_id); | |
1576 | |
1577 scoped_ptr<EntryInfo> new_entry(new EntryInfo); | |
1578 ChangeResource* new_change = &new_entry->change_resource; | |
1579 FileResource* new_file = new FileResource; | |
1580 new_change->set_file(make_scoped_ptr(new_file)); | |
1581 | |
1582 // Set the resource ID and the title | |
1583 new_change->set_file_id(resource_id); | |
1584 new_file->set_file_id(resource_id); | |
1585 new_file->set_title(title); | |
1586 // Set the contents, size and MD5 for a file. | |
1587 if (content_type != util::kDriveFolderMimeType && | |
1588 !util::IsKnownHostedDocumentMimeType(content_type)) { | |
1589 new_entry->content_data = content_data; | |
1590 new_file->set_file_size(content_data.size()); | |
1591 new_file->set_md5_checksum(base::MD5String(content_data)); | |
1592 } | |
1593 | |
1594 if (shared_with_me) { | |
1595 // Set current time to mark the file as shared_with_me. | |
1596 new_file->set_shared_with_me_date(base::Time::Now()); | |
1597 } | |
1598 | |
1599 std::string escaped_resource_id = net::EscapePath(resource_id); | |
1600 | |
1601 // Set mime type. | |
1602 new_file->set_mime_type(content_type); | |
1603 | |
1604 // Set alternate link if needed. | |
1605 if (content_type == util::kGoogleDocumentMimeType) | |
1606 new_file->set_alternate_link(GURL("https://document_alternate_link")); | |
1607 | |
1608 // Set parents. | |
1609 if (!parent_resource_id.empty()) { | |
1610 ParentReference parent; | |
1611 parent.set_file_id(parent_resource_id); | |
1612 parent.set_parent_link(GetFakeLinkUrl(parent.file_id())); | |
1613 std::vector<ParentReference> parents; | |
1614 parents.push_back(parent); | |
1615 *new_file->mutable_parents() = parents; | |
1616 } | |
1617 | |
1618 new_entry->share_url = net::AppendOrReplaceQueryParameter( | |
1619 share_url_base_, "name", title); | |
1620 | |
1621 AddNewChangestamp(new_change); | |
1622 UpdateETag(new_file); | |
1623 | |
1624 base::Time published_date = | |
1625 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); | |
1626 new_file->set_created_date(published_date); | |
1627 | |
1628 EntryInfo* raw_new_entry = new_entry.release(); | |
1629 entries_[resource_id] = raw_new_entry; | |
1630 return raw_new_entry; | |
1631 } | |
1632 | |
1633 void FakeDriveService::GetChangeListInternal( | |
1634 int64 start_changestamp, | |
1635 const std::string& search_query, | |
1636 const std::string& directory_resource_id, | |
1637 int start_offset, | |
1638 int max_results, | |
1639 int* load_counter, | |
1640 const ChangeListCallback& callback) { | |
1641 if (offline_) { | |
1642 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1643 FROM_HERE, | |
1644 base::Bind(callback, | |
1645 DRIVE_NO_CONNECTION, | |
1646 base::Passed(scoped_ptr<ChangeList>()))); | |
1647 return; | |
1648 } | |
1649 | |
1650 // Filter out entries per parameters like |directory_resource_id| and | |
1651 // |search_query|. | |
1652 ScopedVector<ChangeResource> entries; | |
1653 int num_entries_matched = 0; | |
1654 for (EntryInfoMap::iterator it = entries_.begin(); it != entries_.end(); | |
1655 ++it) { | |
1656 const ChangeResource& entry = it->second->change_resource; | |
1657 bool should_exclude = false; | |
1658 | |
1659 // If |directory_resource_id| is set, exclude the entry if it's not in | |
1660 // the target directory. | |
1661 if (!directory_resource_id.empty()) { | |
1662 // Get the parent resource ID of the entry. | |
1663 std::string parent_resource_id; | |
1664 if (entry.file() && !entry.file()->parents().empty()) | |
1665 parent_resource_id = entry.file()->parents()[0].file_id(); | |
1666 | |
1667 if (directory_resource_id != parent_resource_id) | |
1668 should_exclude = true; | |
1669 } | |
1670 | |
1671 // If |search_query| is set, exclude the entry if it does not contain the | |
1672 // search query in the title. | |
1673 if (!should_exclude && !search_query.empty() && | |
1674 !EntryMatchWithQuery(entry, search_query)) { | |
1675 should_exclude = true; | |
1676 } | |
1677 | |
1678 // If |start_changestamp| is set, exclude the entry if the | |
1679 // changestamp is older than |largest_changestamp|. | |
1680 // See https://developers.google.com/google-apps/documents-list/ | |
1681 // #retrieving_all_changes_since_a_given_changestamp | |
1682 if (start_changestamp > 0 && entry.change_id() < start_changestamp) | |
1683 should_exclude = true; | |
1684 | |
1685 // If the caller requests other list than change list by specifying | |
1686 // zero-|start_changestamp|, exclude deleted entry from the result. | |
1687 const bool deleted = entry.is_deleted() || | |
1688 (entry.file() && entry.file()->labels().is_trashed()); | |
1689 if (!start_changestamp && deleted) | |
1690 should_exclude = true; | |
1691 | |
1692 // The entry matched the criteria for inclusion. | |
1693 if (!should_exclude) | |
1694 ++num_entries_matched; | |
1695 | |
1696 // If |start_offset| is set, exclude the entry if the entry is before the | |
1697 // start index. <= instead of < as |num_entries_matched| was | |
1698 // already incremented. | |
1699 if (start_offset > 0 && num_entries_matched <= start_offset) | |
1700 should_exclude = true; | |
1701 | |
1702 if (!should_exclude) { | |
1703 scoped_ptr<ChangeResource> entry_copied(new ChangeResource); | |
1704 entry_copied->set_change_id(entry.change_id()); | |
1705 entry_copied->set_file_id(entry.file_id()); | |
1706 entry_copied->set_deleted(entry.is_deleted()); | |
1707 if (entry.file()) { | |
1708 entry_copied->set_file( | |
1709 make_scoped_ptr(new FileResource(*entry.file()))); | |
1710 } | |
1711 entry_copied->set_modification_date(entry.modification_date()); | |
1712 entries.push_back(entry_copied.release()); | |
1713 } | |
1714 } | |
1715 | |
1716 scoped_ptr<ChangeList> change_list(new ChangeList); | |
1717 if (start_changestamp > 0 && start_offset == 0) { | |
1718 change_list->set_largest_change_id(about_resource_->largest_change_id()); | |
1719 } | |
1720 | |
1721 // If |max_results| is set, trim the entries if the number exceeded the max | |
1722 // results. | |
1723 if (max_results > 0 && entries.size() > static_cast<size_t>(max_results)) { | |
1724 entries.erase(entries.begin() + max_results, entries.end()); | |
1725 // Adds the next URL. | |
1726 // Here, we embed information which is needed for continuing the | |
1727 // GetChangeList request in the next invocation into url query | |
1728 // parameters. | |
1729 GURL next_url(base::StringPrintf( | |
1730 "http://localhost/?start-offset=%d&max-results=%d", | |
1731 start_offset + max_results, | |
1732 max_results)); | |
1733 if (start_changestamp > 0) { | |
1734 next_url = net::AppendOrReplaceQueryParameter( | |
1735 next_url, "changestamp", | |
1736 base::Int64ToString(start_changestamp).c_str()); | |
1737 } | |
1738 if (!search_query.empty()) { | |
1739 next_url = net::AppendOrReplaceQueryParameter( | |
1740 next_url, "q", search_query); | |
1741 } | |
1742 if (!directory_resource_id.empty()) { | |
1743 next_url = net::AppendOrReplaceQueryParameter( | |
1744 next_url, "parent", directory_resource_id); | |
1745 } | |
1746 | |
1747 change_list->set_next_link(next_url); | |
1748 } | |
1749 *change_list->mutable_items() = entries.Pass(); | |
1750 | |
1751 if (load_counter) | |
1752 *load_counter += 1; | |
1753 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1754 FROM_HERE, | |
1755 base::Bind(callback, HTTP_SUCCESS, base::Passed(&change_list))); | |
1756 } | |
1757 | |
1758 GURL FakeDriveService::GetNewUploadSessionUrl() { | |
1759 return GURL("https://upload_session_url/" + | |
1760 base::Int64ToString(next_upload_sequence_number_++)); | |
1761 } | |
1762 | |
1763 google_apis::CancelCallback FakeDriveService::AddPermission( | |
1764 const std::string& resource_id, | |
1765 const std::string& email, | |
1766 google_apis::drive::PermissionRole role, | |
1767 const google_apis::EntryActionCallback& callback) { | |
1768 DCHECK(thread_checker_.CalledOnValidThread()); | |
1769 DCHECK(!callback.is_null()); | |
1770 | |
1771 NOTREACHED(); | |
1772 return CancelCallback(); | |
1773 } | |
1774 | |
1775 scoped_ptr<BatchRequestConfiguratorInterface> | |
1776 FakeDriveService::StartBatchRequest() { | |
1777 DCHECK(thread_checker_.CalledOnValidThread()); | |
1778 | |
1779 NOTREACHED(); | |
1780 return scoped_ptr<BatchRequestConfiguratorInterface>(); | |
1781 } | |
1782 | |
1783 void FakeDriveService::NotifyObservers() { | |
1784 FOR_EACH_OBSERVER(ChangeObserver, change_observers_, OnNewChangeAvailable()); | |
1785 } | |
1786 | |
1787 } // namespace drive | |
OLD | NEW |