| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/drive/fake_drive_service.h" | 5 #include "chrome/browser/drive/fake_drive_service.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 using content::BrowserThread; | 28 using content::BrowserThread; |
| 29 using google_apis::AboutResource; | 29 using google_apis::AboutResource; |
| 30 using google_apis::AboutResourceCallback; | 30 using google_apis::AboutResourceCallback; |
| 31 using google_apis::AccountMetadata; | 31 using google_apis::AccountMetadata; |
| 32 using google_apis::AppList; | 32 using google_apis::AppList; |
| 33 using google_apis::AppListCallback; | 33 using google_apis::AppListCallback; |
| 34 using google_apis::AuthStatusCallback; | 34 using google_apis::AuthStatusCallback; |
| 35 using google_apis::AuthorizeAppCallback; | 35 using google_apis::AuthorizeAppCallback; |
| 36 using google_apis::CancelCallback; | 36 using google_apis::CancelCallback; |
| 37 using google_apis::ChangeResource; |
| 37 using google_apis::DownloadActionCallback; | 38 using google_apis::DownloadActionCallback; |
| 38 using google_apis::EntryActionCallback; | 39 using google_apis::EntryActionCallback; |
| 40 using google_apis::FileResource; |
| 39 using google_apis::GDATA_FILE_ERROR; | 41 using google_apis::GDATA_FILE_ERROR; |
| 40 using google_apis::GDATA_NO_CONNECTION; | 42 using google_apis::GDATA_NO_CONNECTION; |
| 41 using google_apis::GDATA_OTHER_ERROR; | 43 using google_apis::GDATA_OTHER_ERROR; |
| 42 using google_apis::GDataErrorCode; | 44 using google_apis::GDataErrorCode; |
| 43 using google_apis::GetContentCallback; | 45 using google_apis::GetContentCallback; |
| 44 using google_apis::GetResourceEntryCallback; | 46 using google_apis::GetResourceEntryCallback; |
| 45 using google_apis::GetResourceListCallback; | 47 using google_apis::GetResourceListCallback; |
| 46 using google_apis::GetShareUrlCallback; | 48 using google_apis::GetShareUrlCallback; |
| 47 using google_apis::HTTP_BAD_REQUEST; | 49 using google_apis::HTTP_BAD_REQUEST; |
| 48 using google_apis::HTTP_CREATED; | 50 using google_apis::HTTP_CREATED; |
| 49 using google_apis::HTTP_NOT_FOUND; | 51 using google_apis::HTTP_NOT_FOUND; |
| 50 using google_apis::HTTP_NO_CONTENT; | 52 using google_apis::HTTP_NO_CONTENT; |
| 51 using google_apis::HTTP_PRECONDITION; | 53 using google_apis::HTTP_PRECONDITION; |
| 52 using google_apis::HTTP_RESUME_INCOMPLETE; | 54 using google_apis::HTTP_RESUME_INCOMPLETE; |
| 53 using google_apis::HTTP_SUCCESS; | 55 using google_apis::HTTP_SUCCESS; |
| 54 using google_apis::InitiateUploadCallback; | 56 using google_apis::InitiateUploadCallback; |
| 55 using google_apis::Link; | 57 using google_apis::Link; |
| 58 using google_apis::ParentReference; |
| 56 using google_apis::ProgressCallback; | 59 using google_apis::ProgressCallback; |
| 57 using google_apis::ResourceEntry; | 60 using google_apis::ResourceEntry; |
| 58 using google_apis::ResourceList; | 61 using google_apis::ResourceList; |
| 59 using google_apis::UploadRangeCallback; | 62 using google_apis::UploadRangeCallback; |
| 60 using google_apis::UploadRangeResponse; | 63 using google_apis::UploadRangeResponse; |
| 61 namespace test_util = google_apis::test_util; | 64 namespace test_util = google_apis::test_util; |
| 62 | 65 |
| 63 namespace drive { | 66 namespace drive { |
| 64 namespace { | 67 namespace { |
| 65 | 68 |
| 66 // Rel property of an upload link in the entries dictionary value. | 69 // Mime type of directories. |
| 67 const char kUploadUrlRel[] = | 70 const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder"; |
| 68 "http://schemas.google.com/g/2005#resumable-create-media"; | |
| 69 | |
| 70 // Rel property of a share link in the entries dictionary value. | |
| 71 const char kShareUrlRel[] = | |
| 72 "http://schemas.google.com/docs/2007#share"; | |
| 73 | 71 |
| 74 // Returns true if a resource entry matches with the search query. | 72 // Returns true if a resource entry matches with the search query. |
| 75 // Supports queries consist of following format. | 73 // Supports queries consist of following format. |
| 76 // - Phrases quoted by double/single quotes | 74 // - Phrases quoted by double/single quotes |
| 77 // - AND search for multiple words/phrases segmented by space | 75 // - AND search for multiple words/phrases segmented by space |
| 78 // - Limited attribute search. Only "title:" is supported. | 76 // - Limited attribute search. Only "title:" is supported. |
| 79 bool EntryMatchWithQuery(const ResourceEntry& entry, | 77 bool EntryMatchWithQuery(const ResourceEntry& entry, |
| 80 const std::string& query) { | 78 const std::string& query) { |
| 81 base::StringTokenizer tokenizer(query, " "); | 79 base::StringTokenizer tokenizer(query, " "); |
| 82 tokenizer.set_quote_chars("\"'"); | 80 tokenizer.set_quote_chars("\"'"); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 end_position), | 117 end_position), |
| 120 base::Passed(&entry))); | 118 base::Passed(&entry))); |
| 121 } | 119 } |
| 122 | 120 |
| 123 void EntryActionCallbackAdapter( | 121 void EntryActionCallbackAdapter( |
| 124 const EntryActionCallback& callback, | 122 const EntryActionCallback& callback, |
| 125 GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) { | 123 GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) { |
| 126 callback.Run(error); | 124 callback.Run(error); |
| 127 } | 125 } |
| 128 | 126 |
| 129 void ClearPropatiesForPermanentDelete(base::DictionaryValue* entry) { | |
| 130 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue); | |
| 131 const char* kPreservedProperties[] = { | |
| 132 "docs$removed", "docs$changestamp", "gd$resourceId", "id", "updated" | |
| 133 }; | |
| 134 | |
| 135 for (size_t i = 0; i < arraysize(kPreservedProperties); ++i) { | |
| 136 const char* key = kPreservedProperties[i]; | |
| 137 scoped_ptr<base::Value> value; | |
| 138 if (entry->Remove(key, &value)) | |
| 139 new_entry->Set(key, value.release()); | |
| 140 } | |
| 141 | |
| 142 entry->Swap(new_entry.get()); | |
| 143 } | |
| 144 | |
| 145 } // namespace | 127 } // namespace |
| 146 | 128 |
| 129 struct FakeDriveService::EntryInfo { |
| 130 google_apis::ChangeResource change_resource; |
| 131 GURL share_url; |
| 132 std::string content_data; |
| 133 }; |
| 134 |
| 147 struct FakeDriveService::UploadSession { | 135 struct FakeDriveService::UploadSession { |
| 148 std::string content_type; | 136 std::string content_type; |
| 149 int64 content_length; | 137 int64 content_length; |
| 150 std::string parent_resource_id; | 138 std::string parent_resource_id; |
| 151 std::string resource_id; | 139 std::string resource_id; |
| 152 std::string etag; | 140 std::string etag; |
| 153 std::string title; | 141 std::string title; |
| 154 | 142 |
| 155 int64 uploaded_size; | 143 int64 uploaded_size; |
| 156 | 144 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 187 about_resource_load_count_(0), | 175 about_resource_load_count_(0), |
| 188 app_list_load_count_(0), | 176 app_list_load_count_(0), |
| 189 blocked_resource_list_load_count_(0), | 177 blocked_resource_list_load_count_(0), |
| 190 offline_(false), | 178 offline_(false), |
| 191 never_return_all_resource_list_(false) { | 179 never_return_all_resource_list_(false) { |
| 192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 193 } | 181 } |
| 194 | 182 |
| 195 FakeDriveService::~FakeDriveService() { | 183 FakeDriveService::~FakeDriveService() { |
| 196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 185 STLDeleteValues(&entries_); |
| 197 } | 186 } |
| 198 | 187 |
| 199 bool FakeDriveService::LoadResourceListForWapi( | 188 bool FakeDriveService::LoadResourceListForWapi( |
| 200 const std::string& relative_path) { | 189 const std::string& relative_path) { |
| 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 202 scoped_ptr<base::Value> raw_value = test_util::LoadJSONFile(relative_path); | 191 scoped_ptr<base::Value> raw_value = test_util::LoadJSONFile(relative_path); |
| 203 base::DictionaryValue* as_dict = NULL; | 192 base::DictionaryValue* as_dict = NULL; |
| 204 scoped_ptr<base::Value> feed; | 193 scoped_ptr<base::Value> feed; |
| 205 base::DictionaryValue* feed_as_dict = NULL; | 194 base::DictionaryValue* feed_as_dict = NULL; |
| 206 | 195 |
| 207 // Extract the "feed" from the raw value and take the ownership. | 196 // Extract the "feed" from the raw value and take the ownership. |
| 208 // Note that Remove() transfers the ownership to |feed|. | 197 // Note that Remove() transfers the ownership to |feed|. |
| 209 if (raw_value->GetAsDictionary(&as_dict) && | 198 if (raw_value->GetAsDictionary(&as_dict) && |
| 210 as_dict->Remove("feed", &feed) && | 199 as_dict->Remove("feed", &feed) && |
| 211 feed->GetAsDictionary(&feed_as_dict)) { | 200 feed->GetAsDictionary(&feed_as_dict)) { |
| 212 ignore_result(feed.release()); | |
| 213 resource_list_value_.reset(feed_as_dict); | |
| 214 | |
| 215 // Go through entries and convert test$data from a string to a binary blob. | |
| 216 base::ListValue* entries = NULL; | 201 base::ListValue* entries = NULL; |
| 217 if (feed_as_dict->GetList("entry", &entries)) { | 202 if (feed_as_dict->GetList("entry", &entries)) { |
| 218 for (size_t i = 0; i < entries->GetSize(); ++i) { | 203 for (size_t i = 0; i < entries->GetSize(); ++i) { |
| 219 base::DictionaryValue* entry = NULL; | 204 base::DictionaryValue* entry = NULL; |
| 220 std::string content_data; | 205 if (entries->GetDictionary(i, &entry)) { |
| 221 if (entries->GetDictionary(i, &entry) && | 206 scoped_ptr<ResourceEntry> resource_entry = |
| 222 entry->GetString("test$data", &content_data)) { | 207 ResourceEntry::CreateFrom(*entry); |
| 223 entry->Set("test$data", | 208 |
| 224 base::BinaryValue::CreateWithCopiedBuffer( | 209 const std::string resource_id = resource_entry->resource_id(); |
| 225 content_data.c_str(), content_data.size())); | 210 EntryInfoMap::iterator it = entries_.find(resource_id); |
| 211 if (it == entries_.end()) { |
| 212 it = entries_.insert( |
| 213 std::make_pair(resource_id, new EntryInfo)).first; |
| 214 } |
| 215 EntryInfo* new_entry = it->second; |
| 216 |
| 217 ChangeResource* change = &new_entry->change_resource; |
| 218 change->set_change_id(resource_entry->changestamp()); |
| 219 change->set_file_id(resource_id); |
| 220 change->set_file( |
| 221 util::ConvertResourceEntryToFileResource(*resource_entry)); |
| 222 |
| 223 const Link* share_url = |
| 224 resource_entry->GetLinkByType(Link::LINK_SHARE); |
| 225 if (share_url) |
| 226 new_entry->share_url = share_url->href(); |
| 227 |
| 228 entry->GetString("test$data", &new_entry->content_data); |
| 226 } | 229 } |
| 227 } | 230 } |
| 228 } | 231 } |
| 229 } | 232 } |
| 230 | 233 |
| 231 return resource_list_value_; | 234 return feed_as_dict; |
| 232 } | 235 } |
| 233 | 236 |
| 234 bool FakeDriveService::LoadAccountMetadataForWapi( | 237 bool FakeDriveService::LoadAccountMetadataForWapi( |
| 235 const std::string& relative_path) { | 238 const std::string& relative_path) { |
| 236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 237 | 240 |
| 238 // Load JSON data, which must be a dictionary. | 241 // Load JSON data, which must be a dictionary. |
| 239 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); | 242 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); |
| 240 CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); | 243 CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); |
| 241 account_metadata_value_.reset( | 244 account_metadata_value_.reset( |
| 242 static_cast<base::DictionaryValue*>(value.release())); | 245 static_cast<base::DictionaryValue*>(value.release())); |
| 243 | 246 |
| 244 // Update the largest_changestamp_. | 247 // Update the largest_changestamp_. |
| 245 scoped_ptr<AccountMetadata> account_metadata = | 248 scoped_ptr<AccountMetadata> account_metadata = |
| 246 AccountMetadata::CreateFrom(*account_metadata_value_); | 249 AccountMetadata::CreateFrom(*account_metadata_value_); |
| 247 largest_changestamp_ = account_metadata->largest_changestamp(); | 250 largest_changestamp_ = account_metadata->largest_changestamp(); |
| 248 | 251 |
| 249 // Add the largest changestamp to the existing entries. | 252 // Add the largest changestamp to the existing entries. |
| 250 // This will be used to generate change lists in GetResourceList(). | 253 // This will be used to generate change lists in GetResourceList(). |
| 251 if (resource_list_value_) { | 254 for (EntryInfoMap::iterator it = entries_.begin(); it != entries_.end(); ++it) |
| 252 base::ListValue* entries = NULL; | 255 it->second->change_resource.set_change_id(largest_changestamp_); |
| 253 if (resource_list_value_->GetList("entry", &entries)) { | |
| 254 for (size_t i = 0; i < entries->GetSize(); ++i) { | |
| 255 base::DictionaryValue* entry = NULL; | |
| 256 if (entries->GetDictionary(i, &entry)) { | |
| 257 entry->SetString("docs$changestamp.value", | |
| 258 base::Int64ToString(largest_changestamp_)); | |
| 259 } | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 | 256 |
| 264 return account_metadata_value_; | 257 return account_metadata_value_; |
| 265 } | 258 } |
| 266 | 259 |
| 267 bool FakeDriveService::LoadAppListForDriveApi( | 260 bool FakeDriveService::LoadAppListForDriveApi( |
| 268 const std::string& relative_path) { | 261 const std::string& relative_path) { |
| 269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 270 | 263 |
| 271 // Load JSON data, which must be a dictionary. | 264 // Load JSON data, which must be a dictionary. |
| 272 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); | 265 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 if (offline_) { | 451 if (offline_) { |
| 459 scoped_ptr<ResourceEntry> null; | 452 scoped_ptr<ResourceEntry> null; |
| 460 base::MessageLoop::current()->PostTask( | 453 base::MessageLoop::current()->PostTask( |
| 461 FROM_HERE, | 454 FROM_HERE, |
| 462 base::Bind(callback, | 455 base::Bind(callback, |
| 463 GDATA_NO_CONNECTION, | 456 GDATA_NO_CONNECTION, |
| 464 base::Passed(&null))); | 457 base::Passed(&null))); |
| 465 return CancelCallback(); | 458 return CancelCallback(); |
| 466 } | 459 } |
| 467 | 460 |
| 468 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 461 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 469 if (entry) { | 462 if (entry) { |
| 470 scoped_ptr<ResourceEntry> resource_entry = | 463 scoped_ptr<ResourceEntry> resource_entry = |
| 471 ResourceEntry::CreateFrom(*entry); | 464 util::ConvertChangeResourceToResourceEntry(entry->change_resource); |
| 472 base::MessageLoop::current()->PostTask( | 465 base::MessageLoop::current()->PostTask( |
| 473 FROM_HERE, | 466 FROM_HERE, |
| 474 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); | 467 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); |
| 475 return CancelCallback(); | 468 return CancelCallback(); |
| 476 } | 469 } |
| 477 | 470 |
| 478 scoped_ptr<ResourceEntry> null; | 471 scoped_ptr<ResourceEntry> null; |
| 479 base::MessageLoop::current()->PostTask( | 472 base::MessageLoop::current()->PostTask( |
| 480 FROM_HERE, | 473 FROM_HERE, |
| 481 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 474 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 492 if (offline_) { | 485 if (offline_) { |
| 493 scoped_ptr<ResourceEntry> null; | 486 scoped_ptr<ResourceEntry> null; |
| 494 base::MessageLoop::current()->PostTask( | 487 base::MessageLoop::current()->PostTask( |
| 495 FROM_HERE, | 488 FROM_HERE, |
| 496 base::Bind(callback, | 489 base::Bind(callback, |
| 497 GDATA_NO_CONNECTION, | 490 GDATA_NO_CONNECTION, |
| 498 GURL())); | 491 GURL())); |
| 499 return CancelCallback(); | 492 return CancelCallback(); |
| 500 } | 493 } |
| 501 | 494 |
| 502 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 495 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 503 if (entry) { | 496 if (entry) { |
| 504 // Share urls are stored in the resource entry, and they do not rely on the | 497 base::MessageLoop::current()->PostTask( |
| 505 // embedding origin. | 498 FROM_HERE, |
| 506 scoped_ptr<ResourceEntry> resource_entry = | 499 base::Bind(callback, HTTP_SUCCESS, entry->share_url)); |
| 507 ResourceEntry::CreateFrom(*entry); | |
| 508 const Link* share_url = resource_entry->GetLinkByType(Link::LINK_SHARE); | |
| 509 if (share_url) { | |
| 510 base::MessageLoop::current()->PostTask( | |
| 511 FROM_HERE, | |
| 512 base::Bind(callback, HTTP_SUCCESS, share_url->href())); | |
| 513 } else { | |
| 514 base::MessageLoop::current()->PostTask( | |
| 515 FROM_HERE, | |
| 516 base::Bind(callback, HTTP_SUCCESS, GURL())); | |
| 517 } | |
| 518 return CancelCallback(); | 500 return CancelCallback(); |
| 519 } | 501 } |
| 520 | 502 |
| 521 scoped_ptr<ResourceEntry> null; | |
| 522 base::MessageLoop::current()->PostTask( | 503 base::MessageLoop::current()->PostTask( |
| 523 FROM_HERE, | 504 FROM_HERE, |
| 524 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | 505 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
| 525 return CancelCallback(); | 506 return CancelCallback(); |
| 526 } | 507 } |
| 527 | 508 |
| 528 CancelCallback FakeDriveService::GetAboutResource( | 509 CancelCallback FakeDriveService::GetAboutResource( |
| 529 const AboutResourceCallback& callback) { | 510 const AboutResourceCallback& callback) { |
| 530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 531 DCHECK(!callback.is_null()); | 512 DCHECK(!callback.is_null()); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 const EntryActionCallback& callback) { | 563 const EntryActionCallback& callback) { |
| 583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 584 DCHECK(!callback.is_null()); | 565 DCHECK(!callback.is_null()); |
| 585 | 566 |
| 586 if (offline_) { | 567 if (offline_) { |
| 587 base::MessageLoop::current()->PostTask( | 568 base::MessageLoop::current()->PostTask( |
| 588 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 569 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
| 589 return CancelCallback(); | 570 return CancelCallback(); |
| 590 } | 571 } |
| 591 | 572 |
| 592 base::ListValue* entries = NULL; | 573 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 593 if (resource_list_value_->GetList("entry", &entries)) { | 574 if (entry) { |
| 594 for (size_t i = 0; i < entries->GetSize(); ++i) { | 575 ChangeResource* change = &entry->change_resource; |
| 595 base::DictionaryValue* entry = NULL; | 576 const FileResource* file = change->file(); |
| 596 std::string current_resource_id; | 577 if (change->is_deleted()) { |
| 597 if (entries->GetDictionary(i, &entry) && | 578 base::MessageLoop::current()->PostTask( |
| 598 entry->GetString("gd$resourceId.$t", ¤t_resource_id) && | 579 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
| 599 resource_id == current_resource_id) { | 580 return CancelCallback(); |
| 600 if (entry->HasKey("docs$removed")) { | 581 } |
| 601 base::MessageLoop::current()->PostTask( | |
| 602 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
| 603 return CancelCallback(); | |
| 604 } | |
| 605 | 582 |
| 606 std::string entry_etag; | 583 if (!etag.empty() && etag != file->etag()) { |
| 607 entry->GetString("gd$etag", &entry_etag); | 584 base::MessageLoop::current()->PostTask( |
| 608 if (!etag.empty() && entry_etag != etag) { | 585 FROM_HERE, base::Bind(callback, HTTP_PRECONDITION)); |
| 609 base::MessageLoop::current()->PostTask( | 586 return CancelCallback(); |
| 610 FROM_HERE, base::Bind(callback, HTTP_PRECONDITION)); | 587 } |
| 611 return CancelCallback(); | |
| 612 } | |
| 613 | 588 |
| 614 entry->Set("docs$removed", new base::DictionaryValue); | 589 change->set_deleted(true); |
| 615 AddNewChangestamp(entry); | 590 AddNewChangestamp(change); |
| 616 ClearPropatiesForPermanentDelete(entry); | 591 change->set_file(scoped_ptr<FileResource>()); |
| 617 base::MessageLoop::current()->PostTask( | 592 base::MessageLoop::current()->PostTask( |
| 618 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); | 593 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); |
| 619 return CancelCallback(); | 594 return CancelCallback(); |
| 620 } | |
| 621 } | |
| 622 } | 595 } |
| 623 | 596 |
| 624 base::MessageLoop::current()->PostTask( | 597 base::MessageLoop::current()->PostTask( |
| 625 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 598 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
| 626 return CancelCallback(); | 599 return CancelCallback(); |
| 627 } | 600 } |
| 628 | 601 |
| 629 CancelCallback FakeDriveService::TrashResource( | 602 CancelCallback FakeDriveService::TrashResource( |
| 630 const std::string& resource_id, | 603 const std::string& resource_id, |
| 631 const EntryActionCallback& callback) { | 604 const EntryActionCallback& callback) { |
| 632 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 633 DCHECK(!callback.is_null()); | 606 DCHECK(!callback.is_null()); |
| 634 | 607 |
| 635 if (offline_) { | 608 if (offline_) { |
| 636 base::MessageLoop::current()->PostTask( | 609 base::MessageLoop::current()->PostTask( |
| 637 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 610 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
| 638 return CancelCallback(); | 611 return CancelCallback(); |
| 639 } | 612 } |
| 640 | 613 |
| 641 base::ListValue* entries = NULL; | 614 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 642 // Go through entries and remove the one that matches |resource_id|. | 615 if (entry) { |
| 643 if (resource_list_value_->GetList("entry", &entries)) { | 616 ChangeResource* change = &entry->change_resource; |
| 644 for (size_t i = 0; i < entries->GetSize(); ++i) { | 617 FileResource* file = change->mutable_file(); |
| 645 base::DictionaryValue* entry = NULL; | 618 GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; |
| 646 std::string current_resource_id; | 619 if (change->is_deleted() || file->labels().is_trashed()) { |
| 647 if (entries->GetDictionary(i, &entry) && | 620 error = HTTP_NOT_FOUND; |
| 648 entry->GetString("gd$resourceId.$t", ¤t_resource_id) && | 621 } else { |
| 649 resource_id == current_resource_id) { | 622 file->mutable_labels()->set_trashed(true); |
| 650 GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; | 623 AddNewChangestamp(change); |
| 651 if (entry->HasKey("gd$deleted") || entry->HasKey("docs$removed")) { | 624 error = HTTP_SUCCESS; |
| 652 error = HTTP_NOT_FOUND; | |
| 653 } else { | |
| 654 entry->Set("gd$deleted", new base::DictionaryValue); | |
| 655 AddNewChangestamp(entry); | |
| 656 error = HTTP_SUCCESS; | |
| 657 } | |
| 658 base::MessageLoop::current()->PostTask( | |
| 659 FROM_HERE, base::Bind(callback, error)); | |
| 660 return CancelCallback(); | |
| 661 } | |
| 662 } | 625 } |
| 626 base::MessageLoop::current()->PostTask( |
| 627 FROM_HERE, base::Bind(callback, error)); |
| 628 return CancelCallback(); |
| 663 } | 629 } |
| 664 | 630 |
| 665 base::MessageLoop::current()->PostTask( | 631 base::MessageLoop::current()->PostTask( |
| 666 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 632 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
| 667 return CancelCallback(); | 633 return CancelCallback(); |
| 668 } | 634 } |
| 669 | 635 |
| 670 CancelCallback FakeDriveService::DownloadFile( | 636 CancelCallback FakeDriveService::DownloadFile( |
| 671 const base::FilePath& local_cache_path, | 637 const base::FilePath& local_cache_path, |
| 672 const std::string& resource_id, | 638 const std::string& resource_id, |
| 673 const DownloadActionCallback& download_action_callback, | 639 const DownloadActionCallback& download_action_callback, |
| 674 const GetContentCallback& get_content_callback, | 640 const GetContentCallback& get_content_callback, |
| 675 const ProgressCallback& progress_callback) { | 641 const ProgressCallback& progress_callback) { |
| 676 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 677 DCHECK(!download_action_callback.is_null()); | 643 DCHECK(!download_action_callback.is_null()); |
| 678 | 644 |
| 679 if (offline_) { | 645 if (offline_) { |
| 680 base::MessageLoop::current()->PostTask( | 646 base::MessageLoop::current()->PostTask( |
| 681 FROM_HERE, | 647 FROM_HERE, |
| 682 base::Bind(download_action_callback, | 648 base::Bind(download_action_callback, |
| 683 GDATA_NO_CONNECTION, | 649 GDATA_NO_CONNECTION, |
| 684 base::FilePath())); | 650 base::FilePath())); |
| 685 return CancelCallback(); | 651 return CancelCallback(); |
| 686 } | 652 } |
| 687 | 653 |
| 688 // The field content.src is the URL to download the file. | 654 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 689 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | |
| 690 if (!entry) { | 655 if (!entry) { |
| 691 base::MessageLoopProxy::current()->PostTask( | 656 base::MessageLoopProxy::current()->PostTask( |
| 692 FROM_HERE, | 657 FROM_HERE, |
| 693 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); | 658 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); |
| 694 return CancelCallback(); | 659 return CancelCallback(); |
| 695 } | 660 } |
| 696 | 661 |
| 697 // Write "x"s of the file size specified in the entry. | 662 const FileResource* file = entry->change_resource.file(); |
| 698 std::string file_size_string; | 663 const std::string& content_data = entry->content_data; |
| 699 entry->GetString("docs$size.$t", &file_size_string); | 664 int64 file_size = file->file_size(); |
| 700 int64 file_size = 0; | 665 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); |
| 701 if (base::StringToInt64(file_size_string, &file_size)) { | |
| 702 base::BinaryValue* content_binary_data; | |
| 703 std::string content_data; | |
| 704 if (entry->GetBinary("test$data", &content_binary_data)) { | |
| 705 content_data = std::string(content_binary_data->GetBuffer(), | |
| 706 content_binary_data->GetSize()); | |
| 707 } | |
| 708 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); | |
| 709 | 666 |
| 710 if (!get_content_callback.is_null()) { | 667 if (!get_content_callback.is_null()) { |
| 711 const int64 kBlockSize = 5; | 668 const int64 kBlockSize = 5; |
| 712 for (int64 i = 0; i < file_size; i += kBlockSize) { | 669 for (int64 i = 0; i < file_size; i += kBlockSize) { |
| 713 const int64 size = std::min(kBlockSize, file_size - i); | 670 const int64 size = std::min(kBlockSize, file_size - i); |
| 714 scoped_ptr<std::string> content_for_callback( | 671 scoped_ptr<std::string> content_for_callback( |
| 715 new std::string(content_data.substr(i, size))); | 672 new std::string(content_data.substr(i, size))); |
| 716 base::MessageLoopProxy::current()->PostTask( | |
| 717 FROM_HERE, | |
| 718 base::Bind(get_content_callback, HTTP_SUCCESS, | |
| 719 base::Passed(&content_for_callback))); | |
| 720 } | |
| 721 } | |
| 722 | |
| 723 if (test_util::WriteStringToFile(local_cache_path, content_data)) { | |
| 724 if (!progress_callback.is_null()) { | |
| 725 // See also the comment in ResumeUpload(). For testing that clients | |
| 726 // can handle the case progress_callback is called multiple times, | |
| 727 // here we invoke the callback twice. | |
| 728 base::MessageLoopProxy::current()->PostTask( | |
| 729 FROM_HERE, | |
| 730 base::Bind(progress_callback, file_size / 2, file_size)); | |
| 731 base::MessageLoopProxy::current()->PostTask( | |
| 732 FROM_HERE, | |
| 733 base::Bind(progress_callback, file_size, file_size)); | |
| 734 } | |
| 735 base::MessageLoopProxy::current()->PostTask( | 673 base::MessageLoopProxy::current()->PostTask( |
| 736 FROM_HERE, | 674 FROM_HERE, |
| 737 base::Bind(download_action_callback, | 675 base::Bind(get_content_callback, HTTP_SUCCESS, |
| 738 HTTP_SUCCESS, | 676 base::Passed(&content_for_callback))); |
| 739 local_cache_path)); | |
| 740 return CancelCallback(); | |
| 741 } | 677 } |
| 742 } | 678 } |
| 743 | 679 |
| 680 if (test_util::WriteStringToFile(local_cache_path, content_data)) { |
| 681 if (!progress_callback.is_null()) { |
| 682 // See also the comment in ResumeUpload(). For testing that clients |
| 683 // can handle the case progress_callback is called multiple times, |
| 684 // here we invoke the callback twice. |
| 685 base::MessageLoopProxy::current()->PostTask( |
| 686 FROM_HERE, |
| 687 base::Bind(progress_callback, file_size / 2, file_size)); |
| 688 base::MessageLoopProxy::current()->PostTask( |
| 689 FROM_HERE, |
| 690 base::Bind(progress_callback, file_size, file_size)); |
| 691 } |
| 692 base::MessageLoopProxy::current()->PostTask( |
| 693 FROM_HERE, |
| 694 base::Bind(download_action_callback, |
| 695 HTTP_SUCCESS, |
| 696 local_cache_path)); |
| 697 return CancelCallback(); |
| 698 } |
| 699 |
| 744 // Failed to write the content. | 700 // Failed to write the content. |
| 745 base::MessageLoopProxy::current()->PostTask( | 701 base::MessageLoopProxy::current()->PostTask( |
| 746 FROM_HERE, | 702 FROM_HERE, |
| 747 base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath())); | 703 base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath())); |
| 748 return CancelCallback(); | 704 return CancelCallback(); |
| 749 } | 705 } |
| 750 | 706 |
| 751 CancelCallback FakeDriveService::CopyResource( | 707 CancelCallback FakeDriveService::CopyResource( |
| 752 const std::string& resource_id, | 708 const std::string& resource_id, |
| 753 const std::string& in_parent_resource_id, | 709 const std::string& in_parent_resource_id, |
| 754 const std::string& new_title, | 710 const std::string& new_title, |
| 755 const base::Time& last_modified, | 711 const base::Time& last_modified, |
| 756 const GetResourceEntryCallback& callback) { | 712 const GetResourceEntryCallback& callback) { |
| 757 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 713 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 758 DCHECK(!callback.is_null()); | 714 DCHECK(!callback.is_null()); |
| 759 | 715 |
| 760 if (offline_) { | 716 if (offline_) { |
| 761 scoped_ptr<ResourceEntry> null; | 717 scoped_ptr<ResourceEntry> null; |
| 762 base::MessageLoop::current()->PostTask( | 718 base::MessageLoop::current()->PostTask( |
| 763 FROM_HERE, | 719 FROM_HERE, |
| 764 base::Bind(callback, | 720 base::Bind(callback, |
| 765 GDATA_NO_CONNECTION, | 721 GDATA_NO_CONNECTION, |
| 766 base::Passed(&null))); | 722 base::Passed(&null))); |
| 767 return CancelCallback(); | 723 return CancelCallback(); |
| 768 } | 724 } |
| 769 | 725 |
| 770 const std::string& parent_resource_id = in_parent_resource_id.empty() ? | 726 const std::string& parent_resource_id = in_parent_resource_id.empty() ? |
| 771 GetRootResourceId() : in_parent_resource_id; | 727 GetRootResourceId() : in_parent_resource_id; |
| 772 | 728 |
| 773 base::ListValue* entries = NULL; | 729 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 774 // Go through entries and copy the one that matches |resource_id|. | 730 if (entry) { |
| 775 if (resource_list_value_->GetList("entry", &entries)) { | 731 // Make a copy and set the new resource ID and the new title. |
| 776 for (size_t i = 0; i < entries->GetSize(); ++i) { | 732 scoped_ptr<EntryInfo> copied_entry(new EntryInfo); |
| 777 base::DictionaryValue* entry = NULL; | 733 copied_entry->content_data = entry->content_data; |
| 778 std::string current_resource_id; | 734 copied_entry->share_url = entry->share_url; |
| 779 if (entries->GetDictionary(i, &entry) && | |
| 780 entry->GetString("gd$resourceId.$t", ¤t_resource_id) && | |
| 781 resource_id == current_resource_id) { | |
| 782 // Make a copy and set the new resource ID and the new title. | |
| 783 scoped_ptr<base::DictionaryValue> copied_entry(entry->DeepCopy()); | |
| 784 copied_entry->SetString("gd$resourceId.$t", GetNewResourceId()); | |
| 785 copied_entry->SetString("title.$t", new_title); | |
| 786 | 735 |
| 787 // Reset parent directory. | 736 // TODO(hashimoto): Implement a proper way to copy FileResource. |
| 788 base::ListValue* links = NULL; | 737 scoped_ptr<ResourceEntry> copied_resource_entry = |
| 789 if (!copied_entry->GetList("link", &links)) { | 738 util::ConvertChangeResourceToResourceEntry(entry->change_resource); |
| 790 links = new base::ListValue; | 739 copied_entry->change_resource.set_file( |
| 791 copied_entry->Set("link", links); | 740 util::ConvertResourceEntryToFileResource(*copied_resource_entry)); |
| 792 } | |
| 793 links->Clear(); | |
| 794 | 741 |
| 795 base::DictionaryValue* link = new base::DictionaryValue; | 742 ChangeResource* new_change = &copied_entry->change_resource; |
| 796 link->SetString( | 743 FileResource* new_file = new_change->mutable_file(); |
| 797 "rel", "http://schemas.google.com/docs/2007#parent"); | 744 const std::string new_resource_id = GetNewResourceId(); |
| 798 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); | 745 new_change->set_file_id(new_resource_id); |
| 799 links->Append(link); | 746 new_file->set_file_id(new_resource_id); |
| 747 new_file->set_title(new_title); |
| 800 | 748 |
| 801 if (!last_modified.is_null()) { | 749 scoped_ptr<ParentReference> parent(new ParentReference); |
| 802 copied_entry->SetString( | 750 parent->set_file_id(parent_resource_id); |
| 803 "updated.$t", | 751 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id)); |
| 804 google_apis::util::FormatTimeAsString(last_modified)); | 752 parent->set_is_root(parent_resource_id == GetRootResourceId()); |
| 805 } | 753 ScopedVector<ParentReference> parents; |
| 754 parents.push_back(parent.release()); |
| 755 new_file->set_parents(parents.Pass()); |
| 806 | 756 |
| 807 AddNewChangestamp(copied_entry.get()); | 757 if (!last_modified.is_null()) |
| 808 UpdateETag(copied_entry.get()); | 758 new_file->set_modified_date(last_modified); |
| 809 | 759 |
| 810 // Parse the new entry. | 760 AddNewChangestamp(new_change); |
| 811 scoped_ptr<ResourceEntry> resource_entry = | 761 UpdateETag(new_file); |
| 812 ResourceEntry::CreateFrom(*copied_entry); | |
| 813 // Add it to the resource list. | |
| 814 entries->Append(copied_entry.release()); | |
| 815 | 762 |
| 816 base::MessageLoop::current()->PostTask( | 763 scoped_ptr<ResourceEntry> resource_entry = |
| 817 FROM_HERE, | 764 util::ConvertChangeResourceToResourceEntry(*new_change); |
| 818 base::Bind(callback, | 765 // Add the new entry to the map. |
| 819 HTTP_SUCCESS, | 766 entries_[new_resource_id] = copied_entry.release(); |
| 820 base::Passed(&resource_entry))); | 767 |
| 821 return CancelCallback(); | 768 base::MessageLoop::current()->PostTask( |
| 822 } | 769 FROM_HERE, |
| 823 } | 770 base::Bind(callback, |
| 771 HTTP_SUCCESS, |
| 772 base::Passed(&resource_entry))); |
| 773 return CancelCallback(); |
| 824 } | 774 } |
| 825 | 775 |
| 826 scoped_ptr<ResourceEntry> null; | 776 scoped_ptr<ResourceEntry> null; |
| 827 base::MessageLoop::current()->PostTask( | 777 base::MessageLoop::current()->PostTask( |
| 828 FROM_HERE, | 778 FROM_HERE, |
| 829 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 779 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
| 830 return CancelCallback(); | 780 return CancelCallback(); |
| 831 } | 781 } |
| 832 | 782 |
| 833 CancelCallback FakeDriveService::UpdateResource( | 783 CancelCallback FakeDriveService::UpdateResource( |
| 834 const std::string& resource_id, | 784 const std::string& resource_id, |
| 835 const std::string& parent_resource_id, | 785 const std::string& parent_resource_id, |
| 836 const std::string& new_title, | 786 const std::string& new_title, |
| 837 const base::Time& last_modified, | 787 const base::Time& last_modified, |
| 838 const base::Time& last_viewed_by_me, | 788 const base::Time& last_viewed_by_me, |
| 839 const google_apis::GetResourceEntryCallback& callback) { | 789 const google_apis::GetResourceEntryCallback& callback) { |
| 840 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 790 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 841 DCHECK(!callback.is_null()); | 791 DCHECK(!callback.is_null()); |
| 842 | 792 |
| 843 if (offline_) { | 793 if (offline_) { |
| 844 base::MessageLoop::current()->PostTask( | 794 base::MessageLoop::current()->PostTask( |
| 845 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION, | 795 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION, |
| 846 base::Passed(scoped_ptr<ResourceEntry>()))); | 796 base::Passed(scoped_ptr<ResourceEntry>()))); |
| 847 return CancelCallback(); | 797 return CancelCallback(); |
| 848 } | 798 } |
| 849 | 799 |
| 850 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 800 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 851 if (entry) { | 801 if (entry) { |
| 852 entry->SetString("title.$t", new_title); | 802 ChangeResource* change = &entry->change_resource; |
| 803 FileResource* file = change->mutable_file(); |
| 804 file->set_title(new_title); |
| 853 | 805 |
| 854 // Set parent if necessary. | 806 // Set parent if necessary. |
| 855 if (!parent_resource_id.empty()) { | 807 if (!parent_resource_id.empty()) { |
| 856 base::ListValue* links = NULL; | 808 scoped_ptr<ParentReference> parent(new ParentReference); |
| 857 if (!entry->GetList("link", &links)) { | 809 parent->set_file_id(parent_resource_id); |
| 858 links = new base::ListValue; | 810 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id)); |
| 859 entry->Set("link", links); | 811 parent->set_is_root(parent_resource_id == GetRootResourceId()); |
| 860 } | |
| 861 | 812 |
| 862 // Remove old parent(s). | 813 ScopedVector<ParentReference> parents; |
| 863 for (size_t i = 0; i < links->GetSize(); ) { | 814 parents.push_back(parent.release()); |
| 864 base::DictionaryValue* link = NULL; | 815 file->set_parents(parents.Pass()); |
| 865 std::string rel; | |
| 866 std::string href; | |
| 867 if (links->GetDictionary(i, &link) && | |
| 868 link->GetString("rel", &rel) && | |
| 869 link->GetString("href", &href) && | |
| 870 rel == "http://schemas.google.com/docs/2007#parent") { | |
| 871 links->Remove(i, NULL); | |
| 872 } else { | |
| 873 ++i; | |
| 874 } | |
| 875 } | |
| 876 | |
| 877 base::DictionaryValue* link = new base::DictionaryValue; | |
| 878 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); | |
| 879 link->SetString( | |
| 880 "href", GetFakeLinkUrl(parent_resource_id).spec()); | |
| 881 links->Append(link); | |
| 882 } | 816 } |
| 883 | 817 |
| 884 if (!last_modified.is_null()) { | 818 if (!last_modified.is_null()) |
| 885 entry->SetString( | 819 file->set_modified_date(last_modified); |
| 886 "updated.$t", | |
| 887 google_apis::util::FormatTimeAsString(last_modified)); | |
| 888 } | |
| 889 | 820 |
| 890 if (!last_viewed_by_me.is_null()) { | 821 if (!last_viewed_by_me.is_null()) |
| 891 entry->SetString( | 822 file->set_last_viewed_by_me_date(last_viewed_by_me); |
| 892 "gd$lastViewed.$t", | |
| 893 google_apis::util::FormatTimeAsString(last_viewed_by_me)); | |
| 894 } | |
| 895 | 823 |
| 896 AddNewChangestamp(entry); | 824 AddNewChangestamp(change); |
| 897 UpdateETag(entry); | 825 UpdateETag(file); |
| 898 | 826 |
| 899 // Parse the new entry. | |
| 900 scoped_ptr<ResourceEntry> resource_entry = | 827 scoped_ptr<ResourceEntry> resource_entry = |
| 901 ResourceEntry::CreateFrom(*entry); | 828 util::ConvertChangeResourceToResourceEntry(*change); |
| 902 base::MessageLoop::current()->PostTask( | 829 base::MessageLoop::current()->PostTask( |
| 903 FROM_HERE, | 830 FROM_HERE, |
| 904 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); | 831 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); |
| 905 return CancelCallback(); | 832 return CancelCallback(); |
| 906 } | 833 } |
| 907 | 834 |
| 908 base::MessageLoop::current()->PostTask( | 835 base::MessageLoop::current()->PostTask( |
| 909 FROM_HERE, | 836 FROM_HERE, |
| 910 base::Bind(callback, HTTP_NOT_FOUND, | 837 base::Bind(callback, HTTP_NOT_FOUND, |
| 911 base::Passed(scoped_ptr<ResourceEntry>()))); | 838 base::Passed(scoped_ptr<ResourceEntry>()))); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 930 const EntryActionCallback& callback) { | 857 const EntryActionCallback& callback) { |
| 931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 858 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 932 DCHECK(!callback.is_null()); | 859 DCHECK(!callback.is_null()); |
| 933 | 860 |
| 934 if (offline_) { | 861 if (offline_) { |
| 935 base::MessageLoop::current()->PostTask( | 862 base::MessageLoop::current()->PostTask( |
| 936 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 863 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
| 937 return CancelCallback(); | 864 return CancelCallback(); |
| 938 } | 865 } |
| 939 | 866 |
| 940 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 867 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 941 if (entry) { | 868 if (entry) { |
| 942 base::ListValue* links = NULL; | 869 ChangeResource* change = &entry->change_resource; |
| 943 if (!entry->GetList("link", &links)) { | |
| 944 links = new base::ListValue; | |
| 945 entry->Set("link", links); | |
| 946 } | |
| 947 | |
| 948 // On the real Drive server, resources do not necessary shape a tree | 870 // On the real Drive server, resources do not necessary shape a tree |
| 949 // structure. That is, each resource can have multiple parent. | 871 // structure. That is, each resource can have multiple parent. |
| 950 // We mimic the behavior here; AddResourceToDirectoy just adds | 872 // We mimic the behavior here; AddResourceToDirectoy just adds |
| 951 // one more parent link, not overwriting old links. | 873 // one more parent, not overwriting old ones. |
| 952 base::DictionaryValue* link = new base::DictionaryValue; | 874 scoped_ptr<ParentReference> parent(new ParentReference); |
| 953 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); | 875 parent->set_file_id(parent_resource_id); |
| 954 link->SetString( | 876 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id)); |
| 955 "href", GetFakeLinkUrl(parent_resource_id).spec()); | 877 parent->set_is_root(parent_resource_id == GetRootResourceId()); |
| 956 links->Append(link); | 878 change->mutable_file()->mutable_parents()->push_back(parent.release()); |
| 957 | 879 |
| 958 AddNewChangestamp(entry); | 880 AddNewChangestamp(change); |
| 959 base::MessageLoop::current()->PostTask( | 881 base::MessageLoop::current()->PostTask( |
| 960 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); | 882 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); |
| 961 return CancelCallback(); | 883 return CancelCallback(); |
| 962 } | 884 } |
| 963 | 885 |
| 964 base::MessageLoop::current()->PostTask( | 886 base::MessageLoop::current()->PostTask( |
| 965 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 887 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
| 966 return CancelCallback(); | 888 return CancelCallback(); |
| 967 } | 889 } |
| 968 | 890 |
| 969 CancelCallback FakeDriveService::RemoveResourceFromDirectory( | 891 CancelCallback FakeDriveService::RemoveResourceFromDirectory( |
| 970 const std::string& parent_resource_id, | 892 const std::string& parent_resource_id, |
| 971 const std::string& resource_id, | 893 const std::string& resource_id, |
| 972 const EntryActionCallback& callback) { | 894 const EntryActionCallback& callback) { |
| 973 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 895 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 974 DCHECK(!callback.is_null()); | 896 DCHECK(!callback.is_null()); |
| 975 | 897 |
| 976 if (offline_) { | 898 if (offline_) { |
| 977 base::MessageLoop::current()->PostTask( | 899 base::MessageLoop::current()->PostTask( |
| 978 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 900 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
| 979 return CancelCallback(); | 901 return CancelCallback(); |
| 980 } | 902 } |
| 981 | 903 |
| 982 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 904 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 983 if (entry) { | 905 if (entry) { |
| 984 base::ListValue* links = NULL; | 906 ChangeResource* change = &entry->change_resource; |
| 985 if (entry->GetList("link", &links)) { | 907 FileResource* file = change->mutable_file(); |
| 986 GURL parent_content_url = GetFakeLinkUrl(parent_resource_id); | 908 ScopedVector<ParentReference>* parents = file->mutable_parents(); |
| 987 for (size_t i = 0; i < links->GetSize(); ++i) { | 909 for (size_t i = 0; i < parents->size(); ++i) { |
| 988 base::DictionaryValue* link = NULL; | 910 if ((*parents)[i]->file_id() == parent_resource_id) { |
| 989 std::string rel; | 911 parents->erase(parents->begin() + i); |
| 990 std::string href; | 912 AddNewChangestamp(change); |
| 991 if (links->GetDictionary(i, &link) && | 913 base::MessageLoop::current()->PostTask( |
| 992 link->GetString("rel", &rel) && | 914 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); |
| 993 link->GetString("href", &href) && | 915 return CancelCallback(); |
| 994 rel == "http://schemas.google.com/docs/2007#parent" && | |
| 995 GURL(href) == parent_content_url) { | |
| 996 links->Remove(i, NULL); | |
| 997 AddNewChangestamp(entry); | |
| 998 base::MessageLoop::current()->PostTask( | |
| 999 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); | |
| 1000 return CancelCallback(); | |
| 1001 } | |
| 1002 } | 916 } |
| 1003 } | 917 } |
| 1004 } | 918 } |
| 1005 | 919 |
| 1006 base::MessageLoop::current()->PostTask( | 920 base::MessageLoop::current()->PostTask( |
| 1007 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 921 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
| 1008 return CancelCallback(); | 922 return CancelCallback(); |
| 1009 } | 923 } |
| 1010 | 924 |
| 1011 CancelCallback FakeDriveService::AddNewDirectory( | 925 CancelCallback FakeDriveService::AddNewDirectory( |
| 1012 const std::string& parent_resource_id, | 926 const std::string& parent_resource_id, |
| 1013 const std::string& directory_title, | 927 const std::string& directory_title, |
| 1014 const GetResourceEntryCallback& callback) { | 928 const GetResourceEntryCallback& callback) { |
| 1015 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 929 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1016 DCHECK(!callback.is_null()); | 930 DCHECK(!callback.is_null()); |
| 1017 | 931 |
| 1018 if (offline_) { | 932 if (offline_) { |
| 1019 scoped_ptr<ResourceEntry> null; | 933 scoped_ptr<ResourceEntry> null; |
| 1020 base::MessageLoop::current()->PostTask( | 934 base::MessageLoop::current()->PostTask( |
| 1021 FROM_HERE, | 935 FROM_HERE, |
| 1022 base::Bind(callback, | 936 base::Bind(callback, |
| 1023 GDATA_NO_CONNECTION, | 937 GDATA_NO_CONNECTION, |
| 1024 base::Passed(&null))); | 938 base::Passed(&null))); |
| 1025 return CancelCallback(); | 939 return CancelCallback(); |
| 1026 } | 940 } |
| 1027 | 941 |
| 1028 const char kContentType[] = "application/atom+xml;type=feed"; | 942 const EntryInfo* new_entry = AddNewEntry(kDriveFolderMimeType, |
| 1029 const base::DictionaryValue* new_entry = AddNewEntry(kContentType, | 943 "", // content_data |
| 1030 "", // content_data | 944 parent_resource_id, |
| 1031 parent_resource_id, | 945 directory_title, |
| 1032 directory_title, | 946 false); // shared_with_me |
| 1033 false, // shared_with_me | |
| 1034 "folder"); | |
| 1035 if (!new_entry) { | 947 if (!new_entry) { |
| 1036 scoped_ptr<ResourceEntry> null; | 948 scoped_ptr<ResourceEntry> null; |
| 1037 base::MessageLoop::current()->PostTask( | 949 base::MessageLoop::current()->PostTask( |
| 1038 FROM_HERE, | 950 FROM_HERE, |
| 1039 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 951 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
| 1040 return CancelCallback(); | 952 return CancelCallback(); |
| 1041 } | 953 } |
| 1042 | 954 |
| 1043 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*new_entry)); | 955 scoped_ptr<ResourceEntry> parsed_entry( |
| 956 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource)); |
| 1044 base::MessageLoop::current()->PostTask( | 957 base::MessageLoop::current()->PostTask( |
| 1045 FROM_HERE, | 958 FROM_HERE, |
| 1046 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); | 959 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); |
| 1047 return CancelCallback(); | 960 return CancelCallback(); |
| 1048 } | 961 } |
| 1049 | 962 |
| 1050 CancelCallback FakeDriveService::InitiateUploadNewFile( | 963 CancelCallback FakeDriveService::InitiateUploadNewFile( |
| 1051 const std::string& content_type, | 964 const std::string& content_type, |
| 1052 int64 content_length, | 965 int64 content_length, |
| 1053 const std::string& parent_resource_id, | 966 const std::string& parent_resource_id, |
| 1054 const std::string& title, | 967 const std::string& title, |
| 1055 const InitiateUploadCallback& callback) { | 968 const InitiateUploadCallback& callback) { |
| 1056 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 969 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1057 DCHECK(!callback.is_null()); | 970 DCHECK(!callback.is_null()); |
| 1058 | 971 |
| 1059 if (offline_) { | 972 if (offline_) { |
| 1060 base::MessageLoop::current()->PostTask( | 973 base::MessageLoop::current()->PostTask( |
| 1061 FROM_HERE, | 974 FROM_HERE, |
| 1062 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); | 975 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); |
| 1063 return CancelCallback(); | 976 return CancelCallback(); |
| 1064 } | 977 } |
| 1065 | 978 |
| 1066 if (parent_resource_id != GetRootResourceId() && | 979 if (parent_resource_id != GetRootResourceId() && |
| 1067 !FindEntryByResourceId(parent_resource_id)) { | 980 !entries_.count(parent_resource_id)) { |
| 1068 base::MessageLoop::current()->PostTask( | 981 base::MessageLoop::current()->PostTask( |
| 1069 FROM_HERE, | 982 FROM_HERE, |
| 1070 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | 983 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
| 1071 return CancelCallback(); | 984 return CancelCallback(); |
| 1072 } | 985 } |
| 1073 | 986 |
| 1074 GURL session_url = GetNewUploadSessionUrl(); | 987 GURL session_url = GetNewUploadSessionUrl(); |
| 1075 upload_sessions_[session_url] = | 988 upload_sessions_[session_url] = |
| 1076 UploadSession(content_type, content_length, | 989 UploadSession(content_type, content_length, |
| 1077 parent_resource_id, | 990 parent_resource_id, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1094 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1007 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1095 DCHECK(!callback.is_null()); | 1008 DCHECK(!callback.is_null()); |
| 1096 | 1009 |
| 1097 if (offline_) { | 1010 if (offline_) { |
| 1098 base::MessageLoop::current()->PostTask( | 1011 base::MessageLoop::current()->PostTask( |
| 1099 FROM_HERE, | 1012 FROM_HERE, |
| 1100 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); | 1013 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); |
| 1101 return CancelCallback(); | 1014 return CancelCallback(); |
| 1102 } | 1015 } |
| 1103 | 1016 |
| 1104 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 1017 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 1105 if (!entry) { | 1018 if (!entry) { |
| 1106 base::MessageLoop::current()->PostTask( | 1019 base::MessageLoop::current()->PostTask( |
| 1107 FROM_HERE, | 1020 FROM_HERE, |
| 1108 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | 1021 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
| 1109 return CancelCallback(); | 1022 return CancelCallback(); |
| 1110 } | 1023 } |
| 1111 | 1024 |
| 1112 std::string entry_etag; | 1025 const FileResource* file = entry->change_resource.file(); |
| 1113 entry->GetString("gd$etag", &entry_etag); | 1026 if (!etag.empty() && etag != file->etag()) { |
| 1114 if (!etag.empty() && etag != entry_etag) { | |
| 1115 base::MessageLoop::current()->PostTask( | 1027 base::MessageLoop::current()->PostTask( |
| 1116 FROM_HERE, | 1028 FROM_HERE, |
| 1117 base::Bind(callback, HTTP_PRECONDITION, GURL())); | 1029 base::Bind(callback, HTTP_PRECONDITION, GURL())); |
| 1118 return CancelCallback(); | 1030 return CancelCallback(); |
| 1119 } | 1031 } |
| 1120 | 1032 |
| 1121 GURL session_url = GetNewUploadSessionUrl(); | 1033 GURL session_url = GetNewUploadSessionUrl(); |
| 1122 upload_sessions_[session_url] = | 1034 upload_sessions_[session_url] = |
| 1123 UploadSession(content_type, content_length, | 1035 UploadSession(content_type, content_length, |
| 1124 "", // parent_resource_id | 1036 "", // parent_resource_id |
| 1125 resource_id, | 1037 resource_id, |
| 1126 entry_etag, | 1038 file->etag(), |
| 1127 "" /* title */); | 1039 "" /* title */); |
| 1128 | 1040 |
| 1129 base::MessageLoop::current()->PostTask( | 1041 base::MessageLoop::current()->PostTask( |
| 1130 FROM_HERE, | 1042 FROM_HERE, |
| 1131 base::Bind(callback, HTTP_SUCCESS, session_url)); | 1043 base::Bind(callback, HTTP_SUCCESS, session_url)); |
| 1132 return CancelCallback(); | 1044 return CancelCallback(); |
| 1133 } | 1045 } |
| 1134 | 1046 |
| 1135 CancelCallback FakeDriveService::GetUploadStatus( | 1047 CancelCallback FakeDriveService::GetUploadStatus( |
| 1136 const GURL& upload_url, | 1048 const GURL& upload_url, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1202 session->uploaded_size = end_position; | 1114 session->uploaded_size = end_position; |
| 1203 completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>()); | 1115 completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>()); |
| 1204 return CancelCallback(); | 1116 return CancelCallback(); |
| 1205 } | 1117 } |
| 1206 session->uploaded_size = end_position; | 1118 session->uploaded_size = end_position; |
| 1207 | 1119 |
| 1208 // |resource_id| is empty if the upload is for new file. | 1120 // |resource_id| is empty if the upload is for new file. |
| 1209 if (session->resource_id.empty()) { | 1121 if (session->resource_id.empty()) { |
| 1210 DCHECK(!session->parent_resource_id.empty()); | 1122 DCHECK(!session->parent_resource_id.empty()); |
| 1211 DCHECK(!session->title.empty()); | 1123 DCHECK(!session->title.empty()); |
| 1212 const base::DictionaryValue* new_entry = AddNewEntry( | 1124 const EntryInfo* new_entry = AddNewEntry( |
| 1213 session->content_type, | 1125 session->content_type, |
| 1214 content_data, | 1126 content_data, |
| 1215 session->parent_resource_id, | 1127 session->parent_resource_id, |
| 1216 session->title, | 1128 session->title, |
| 1217 false, // shared_with_me | 1129 false); // shared_with_me |
| 1218 "file"); | |
| 1219 if (!new_entry) { | 1130 if (!new_entry) { |
| 1220 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); | 1131 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); |
| 1221 return CancelCallback(); | 1132 return CancelCallback(); |
| 1222 } | 1133 } |
| 1223 | 1134 |
| 1224 completion_callback.Run(HTTP_CREATED, | 1135 completion_callback.Run( |
| 1225 ResourceEntry::CreateFrom(*new_entry)); | 1136 HTTP_CREATED, |
| 1137 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource)); |
| 1226 return CancelCallback(); | 1138 return CancelCallback(); |
| 1227 } | 1139 } |
| 1228 | 1140 |
| 1229 base::DictionaryValue* entry = FindEntryByResourceId(session->resource_id); | 1141 EntryInfo* entry = FindEntryByResourceId(session->resource_id); |
| 1230 if (!entry) { | 1142 if (!entry) { |
| 1231 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); | 1143 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); |
| 1232 return CancelCallback(); | 1144 return CancelCallback(); |
| 1233 } | 1145 } |
| 1234 | 1146 |
| 1235 std::string entry_etag; | 1147 ChangeResource* change = &entry->change_resource; |
| 1236 entry->GetString("gd$etag", &entry_etag); | 1148 FileResource* file = change->mutable_file(); |
| 1237 if (entry_etag.empty() || session->etag != entry_etag) { | 1149 if (file->etag().empty() || session->etag != file->etag()) { |
| 1238 completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>()); | 1150 completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>()); |
| 1239 return CancelCallback(); | 1151 return CancelCallback(); |
| 1240 } | 1152 } |
| 1241 | 1153 |
| 1242 entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data)); | 1154 file->set_md5_checksum(base::MD5String(content_data)); |
| 1243 entry->Set("test$data", | 1155 entry->content_data = content_data; |
| 1244 base::BinaryValue::CreateWithCopiedBuffer( | 1156 file->set_file_size(end_position); |
| 1245 content_data.data(), content_data.size())); | 1157 AddNewChangestamp(change); |
| 1246 entry->SetString("docs$size.$t", base::Int64ToString(end_position)); | 1158 UpdateETag(file); |
| 1247 AddNewChangestamp(entry); | |
| 1248 UpdateETag(entry); | |
| 1249 | 1159 |
| 1250 completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry)); | 1160 completion_callback.Run(HTTP_SUCCESS, |
| 1161 util::ConvertChangeResourceToResourceEntry(*change)); |
| 1251 return CancelCallback(); | 1162 return CancelCallback(); |
| 1252 } | 1163 } |
| 1253 | 1164 |
| 1254 CancelCallback FakeDriveService::AuthorizeApp( | 1165 CancelCallback FakeDriveService::AuthorizeApp( |
| 1255 const std::string& resource_id, | 1166 const std::string& resource_id, |
| 1256 const std::string& app_id, | 1167 const std::string& app_id, |
| 1257 const AuthorizeAppCallback& callback) { | 1168 const AuthorizeAppCallback& callback) { |
| 1258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1259 DCHECK(!callback.is_null()); | 1170 DCHECK(!callback.is_null()); |
| 1260 return CancelCallback(); | 1171 return CancelCallback(); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1361 if (offline_) { | 1272 if (offline_) { |
| 1362 scoped_ptr<ResourceEntry> null; | 1273 scoped_ptr<ResourceEntry> null; |
| 1363 base::MessageLoop::current()->PostTask( | 1274 base::MessageLoop::current()->PostTask( |
| 1364 FROM_HERE, | 1275 FROM_HERE, |
| 1365 base::Bind(callback, | 1276 base::Bind(callback, |
| 1366 GDATA_NO_CONNECTION, | 1277 GDATA_NO_CONNECTION, |
| 1367 base::Passed(&null))); | 1278 base::Passed(&null))); |
| 1368 return; | 1279 return; |
| 1369 } | 1280 } |
| 1370 | 1281 |
| 1371 // Prepare "kind" for hosted documents. This only supports Google Document. | 1282 const EntryInfo* new_entry = AddNewEntry(content_type, |
| 1372 std::string entry_kind; | 1283 content_data, |
| 1373 if (content_type == "application/vnd.google-apps.document") | 1284 parent_resource_id, |
| 1374 entry_kind = "document"; | 1285 title, |
| 1375 else | 1286 shared_with_me); |
| 1376 entry_kind = "file"; | |
| 1377 | |
| 1378 const base::DictionaryValue* new_entry = AddNewEntry(content_type, | |
| 1379 content_data, | |
| 1380 parent_resource_id, | |
| 1381 title, | |
| 1382 shared_with_me, | |
| 1383 entry_kind); | |
| 1384 if (!new_entry) { | 1287 if (!new_entry) { |
| 1385 scoped_ptr<ResourceEntry> null; | 1288 scoped_ptr<ResourceEntry> null; |
| 1386 base::MessageLoop::current()->PostTask( | 1289 base::MessageLoop::current()->PostTask( |
| 1387 FROM_HERE, | 1290 FROM_HERE, |
| 1388 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 1291 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
| 1389 return; | 1292 return; |
| 1390 } | 1293 } |
| 1391 | 1294 |
| 1392 scoped_ptr<ResourceEntry> parsed_entry( | 1295 scoped_ptr<ResourceEntry> parsed_entry( |
| 1393 ResourceEntry::CreateFrom(*new_entry)); | 1296 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource)); |
| 1394 base::MessageLoop::current()->PostTask( | 1297 base::MessageLoop::current()->PostTask( |
| 1395 FROM_HERE, | 1298 FROM_HERE, |
| 1396 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); | 1299 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); |
| 1397 } | 1300 } |
| 1398 | 1301 |
| 1399 void FakeDriveService::SetLastModifiedTime( | 1302 void FakeDriveService::SetLastModifiedTime( |
| 1400 const std::string& resource_id, | 1303 const std::string& resource_id, |
| 1401 const base::Time& last_modified_time, | 1304 const base::Time& last_modified_time, |
| 1402 const GetResourceEntryCallback& callback) { | 1305 const GetResourceEntryCallback& callback) { |
| 1403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1404 DCHECK(!callback.is_null()); | 1307 DCHECK(!callback.is_null()); |
| 1405 | 1308 |
| 1406 if (offline_) { | 1309 if (offline_) { |
| 1407 scoped_ptr<ResourceEntry> null; | 1310 scoped_ptr<ResourceEntry> null; |
| 1408 base::MessageLoop::current()->PostTask( | 1311 base::MessageLoop::current()->PostTask( |
| 1409 FROM_HERE, | 1312 FROM_HERE, |
| 1410 base::Bind(callback, | 1313 base::Bind(callback, |
| 1411 GDATA_NO_CONNECTION, | 1314 GDATA_NO_CONNECTION, |
| 1412 base::Passed(&null))); | 1315 base::Passed(&null))); |
| 1413 return; | 1316 return; |
| 1414 } | 1317 } |
| 1415 | 1318 |
| 1416 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 1319 EntryInfo* entry = FindEntryByResourceId(resource_id); |
| 1417 if (!entry) { | 1320 if (!entry) { |
| 1418 scoped_ptr<ResourceEntry> null; | 1321 scoped_ptr<ResourceEntry> null; |
| 1419 base::MessageLoop::current()->PostTask( | 1322 base::MessageLoop::current()->PostTask( |
| 1420 FROM_HERE, | 1323 FROM_HERE, |
| 1421 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 1324 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
| 1422 return; | 1325 return; |
| 1423 } | 1326 } |
| 1424 | 1327 |
| 1425 if (last_modified_time.is_null()) { | 1328 ChangeResource* change = &entry->change_resource; |
| 1426 entry->Remove("updated.$t", NULL); | 1329 FileResource* file = change->mutable_file(); |
| 1427 } else { | 1330 file->set_modified_date(last_modified_time); |
| 1428 entry->SetString( | |
| 1429 "updated.$t", | |
| 1430 google_apis::util::FormatTimeAsString(last_modified_time)); | |
| 1431 } | |
| 1432 | 1331 |
| 1433 scoped_ptr<ResourceEntry> parsed_entry( | 1332 scoped_ptr<ResourceEntry> parsed_entry( |
| 1434 ResourceEntry::CreateFrom(*entry)); | 1333 util::ConvertChangeResourceToResourceEntry(*change)); |
| 1435 base::MessageLoop::current()->PostTask( | 1334 base::MessageLoop::current()->PostTask( |
| 1436 FROM_HERE, | 1335 FROM_HERE, |
| 1437 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); | 1336 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); |
| 1438 } | 1337 } |
| 1439 | 1338 |
| 1440 base::DictionaryValue* FakeDriveService::FindEntryByResourceId( | 1339 FakeDriveService::EntryInfo* FakeDriveService::FindEntryByResourceId( |
| 1441 const std::string& resource_id) { | 1340 const std::string& resource_id) { |
| 1442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1443 | 1342 |
| 1444 base::ListValue* entries = NULL; | 1343 EntryInfoMap::iterator it = entries_.find(resource_id); |
| 1445 // Go through entries and return the one that matches |resource_id|. | 1344 // Deleted entries don't have FileResource. |
| 1446 if (resource_list_value_->GetList("entry", &entries)) { | 1345 return it != entries_.end() && it->second->change_resource.file() ? |
| 1447 for (size_t i = 0; i < entries->GetSize(); ++i) { | 1346 it->second : NULL; |
| 1448 base::DictionaryValue* entry = NULL; | |
| 1449 std::string current_resource_id; | |
| 1450 if (entries->GetDictionary(i, &entry) && | |
| 1451 entry->GetString("gd$resourceId.$t", ¤t_resource_id) && | |
| 1452 resource_id == current_resource_id && | |
| 1453 !entry->HasKey("docs$removed")) { | |
| 1454 return entry; | |
| 1455 } | |
| 1456 } | |
| 1457 } | |
| 1458 | |
| 1459 return NULL; | |
| 1460 } | |
| 1461 | |
| 1462 base::DictionaryValue* FakeDriveService::FindEntryByContentUrl( | |
| 1463 const GURL& content_url) { | |
| 1464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 1465 | |
| 1466 base::ListValue* entries = NULL; | |
| 1467 // Go through entries and return the one that matches |content_url|. | |
| 1468 if (resource_list_value_->GetList("entry", &entries)) { | |
| 1469 for (size_t i = 0; i < entries->GetSize(); ++i) { | |
| 1470 base::DictionaryValue* entry = NULL; | |
| 1471 std::string current_content_url; | |
| 1472 if (entries->GetDictionary(i, &entry) && | |
| 1473 entry->GetString("content.src", ¤t_content_url) && | |
| 1474 content_url == GURL(current_content_url)) { | |
| 1475 return entry; | |
| 1476 } | |
| 1477 } | |
| 1478 } | |
| 1479 | |
| 1480 return NULL; | |
| 1481 } | 1347 } |
| 1482 | 1348 |
| 1483 std::string FakeDriveService::GetNewResourceId() { | 1349 std::string FakeDriveService::GetNewResourceId() { |
| 1484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1485 | 1351 |
| 1486 ++resource_id_count_; | 1352 ++resource_id_count_; |
| 1487 return base::StringPrintf("resource_id_%d", resource_id_count_); | 1353 return base::StringPrintf("resource_id_%d", resource_id_count_); |
| 1488 } | 1354 } |
| 1489 | 1355 |
| 1490 void FakeDriveService::UpdateETag(base::DictionaryValue* entry) { | 1356 void FakeDriveService::UpdateETag(google_apis::FileResource* file) { |
| 1491 entry->SetString("gd$etag", | 1357 file->set_etag("etag_" + base::Int64ToString(largest_changestamp_)); |
| 1492 "etag_" + base::Int64ToString(largest_changestamp_)); | |
| 1493 } | 1358 } |
| 1494 | 1359 |
| 1495 void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) { | 1360 void FakeDriveService::AddNewChangestamp(google_apis::ChangeResource* change) { |
| 1496 ++largest_changestamp_; | 1361 ++largest_changestamp_; |
| 1497 entry->SetString("docs$changestamp.value", | 1362 change->set_change_id(largest_changestamp_); |
| 1498 base::Int64ToString(largest_changestamp_)); | |
| 1499 } | 1363 } |
| 1500 | 1364 |
| 1501 const base::DictionaryValue* FakeDriveService::AddNewEntry( | 1365 const FakeDriveService::EntryInfo* FakeDriveService::AddNewEntry( |
| 1502 const std::string& content_type, | 1366 const std::string& content_type, |
| 1503 const std::string& content_data, | 1367 const std::string& content_data, |
| 1504 const std::string& parent_resource_id, | 1368 const std::string& parent_resource_id, |
| 1505 const std::string& title, | 1369 const std::string& title, |
| 1506 bool shared_with_me, | 1370 bool shared_with_me) { |
| 1507 const std::string& entry_kind) { | |
| 1508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1509 | 1372 |
| 1510 if (!parent_resource_id.empty() && | 1373 if (!parent_resource_id.empty() && |
| 1511 parent_resource_id != GetRootResourceId() && | 1374 parent_resource_id != GetRootResourceId() && |
| 1512 !FindEntryByResourceId(parent_resource_id)) { | 1375 !entries_.count(parent_resource_id)) { |
| 1513 return NULL; | 1376 return NULL; |
| 1514 } | 1377 } |
| 1515 | 1378 |
| 1516 std::string resource_id = GetNewResourceId(); | 1379 std::string resource_id = GetNewResourceId(); |
| 1517 GURL upload_url = GURL("https://xxx/upload/" + resource_id); | 1380 GURL upload_url = GURL("https://xxx/upload/" + resource_id); |
| 1518 | 1381 |
| 1519 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue); | 1382 scoped_ptr<EntryInfo> new_entry(new EntryInfo); |
| 1383 ChangeResource* new_change = &new_entry->change_resource; |
| 1384 FileResource* new_file = new FileResource; |
| 1385 new_change->set_file(make_scoped_ptr(new_file)); |
| 1386 |
| 1520 // Set the resource ID and the title | 1387 // Set the resource ID and the title |
| 1521 new_entry->SetString("gd$resourceId.$t", resource_id); | 1388 new_change->set_file_id(resource_id); |
| 1522 new_entry->SetString("title.$t", title); | 1389 new_file->set_file_id(resource_id); |
| 1523 new_entry->SetString("docs$filename", title); | 1390 new_file->set_title(title); |
| 1524 // Set the contents, size and MD5 for a file. | 1391 // Set the contents, size and MD5 for a file. |
| 1525 if (entry_kind == "file") { | 1392 if (content_type != kDriveFolderMimeType) { |
| 1526 new_entry->Set("test$data", | 1393 new_entry->content_data = content_data; |
| 1527 base::BinaryValue::CreateWithCopiedBuffer( | 1394 new_file->set_file_size(content_data.size()); |
| 1528 content_data.c_str(), content_data.size())); | 1395 new_file->set_md5_checksum(base::MD5String(content_data)); |
| 1529 new_entry->SetString("docs$size.$t", | |
| 1530 base::Int64ToString(content_data.size())); | |
| 1531 new_entry->SetString("docs$md5Checksum.$t", | |
| 1532 base::MD5String(content_data)); | |
| 1533 } | 1396 } |
| 1534 | 1397 |
| 1535 // Add "category" which sets the resource type to |entry_kind|. | |
| 1536 base::ListValue* categories = new base::ListValue; | |
| 1537 base::DictionaryValue* category = new base::DictionaryValue; | |
| 1538 category->SetString("scheme", "http://schemas.google.com/g/2005#kind"); | |
| 1539 category->SetString("term", "http://schemas.google.com/docs/2007#" + | |
| 1540 entry_kind); | |
| 1541 categories->Append(category); | |
| 1542 new_entry->Set("category", categories); | |
| 1543 if (shared_with_me) { | 1398 if (shared_with_me) { |
| 1544 base::DictionaryValue* shared_with_me_label = new base::DictionaryValue; | 1399 // Set current time to mark the file as shared_with_me. |
| 1545 shared_with_me_label->SetString("label", "shared-with-me"); | 1400 new_file->set_shared_with_me_date(base::Time::Now()); |
| 1546 shared_with_me_label->SetString("scheme", | |
| 1547 "http://schemas.google.com/g/2005/labels"); | |
| 1548 shared_with_me_label->SetString( | |
| 1549 "term", "http://schemas.google.com/g/2005/labels#shared"); | |
| 1550 categories->Append(shared_with_me_label); | |
| 1551 } | 1401 } |
| 1552 | 1402 |
| 1553 std::string escaped_resource_id = net::EscapePath(resource_id); | 1403 std::string escaped_resource_id = net::EscapePath(resource_id); |
| 1554 | 1404 |
| 1555 // Add "content" which sets the content URL. | 1405 // Set download URL and mime type. |
| 1556 base::DictionaryValue* content = new base::DictionaryValue; | 1406 new_file->set_download_url( |
| 1557 content->SetString("src", "https://xxx/content/" + escaped_resource_id); | 1407 GURL("https://xxx/content/" + escaped_resource_id)); |
| 1558 content->SetString("type", content_type); | 1408 new_file->set_mime_type(content_type); |
| 1559 new_entry->Set("content", content); | |
| 1560 | 1409 |
| 1561 // Add "link" which sets the parent URL, the edit URL and the upload URL. | 1410 // Set parents. |
| 1562 base::ListValue* links = new base::ListValue; | 1411 scoped_ptr<ParentReference> parent(new ParentReference); |
| 1412 if (parent_resource_id.empty()) |
| 1413 parent->set_file_id(GetRootResourceId()); |
| 1414 else |
| 1415 parent->set_file_id(parent_resource_id); |
| 1416 parent->set_parent_link(GetFakeLinkUrl(parent->file_id())); |
| 1417 parent->set_is_root(parent->file_id() == GetRootResourceId()); |
| 1418 ScopedVector<ParentReference> parents; |
| 1419 parents.push_back(parent.release()); |
| 1420 new_file->set_parents(parents.Pass()); |
| 1563 | 1421 |
| 1564 base::DictionaryValue* parent_link = new base::DictionaryValue; | 1422 new_file->set_self_link(GURL("https://xxx/edit/" + escaped_resource_id)); |
| 1565 if (parent_resource_id.empty()) | |
| 1566 parent_link->SetString("href", GetFakeLinkUrl(GetRootResourceId()).spec()); | |
| 1567 else | |
| 1568 parent_link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); | |
| 1569 parent_link->SetString("rel", | |
| 1570 "http://schemas.google.com/docs/2007#parent"); | |
| 1571 links->Append(parent_link); | |
| 1572 | 1423 |
| 1573 base::DictionaryValue* edit_link = new base::DictionaryValue; | 1424 new_entry->share_url = net::AppendOrReplaceQueryParameter( |
| 1574 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id); | 1425 share_url_base_, "name", title); |
| 1575 edit_link->SetString("rel", "edit"); | |
| 1576 links->Append(edit_link); | |
| 1577 | 1426 |
| 1578 base::DictionaryValue* upload_link = new base::DictionaryValue; | 1427 AddNewChangestamp(new_change); |
| 1579 upload_link->SetString("href", upload_url.spec()); | 1428 UpdateETag(new_file); |
| 1580 upload_link->SetString("rel", kUploadUrlRel); | |
| 1581 links->Append(upload_link); | |
| 1582 | |
| 1583 const GURL share_url = net::AppendOrReplaceQueryParameter( | |
| 1584 share_url_base_, "name", title); | |
| 1585 base::DictionaryValue* share_link = new base::DictionaryValue; | |
| 1586 upload_link->SetString("href", share_url.spec()); | |
| 1587 upload_link->SetString("rel", kShareUrlRel); | |
| 1588 links->Append(share_link); | |
| 1589 new_entry->Set("link", links); | |
| 1590 | |
| 1591 AddNewChangestamp(new_entry.get()); | |
| 1592 UpdateETag(new_entry.get()); | |
| 1593 | 1429 |
| 1594 base::Time published_date = | 1430 base::Time published_date = |
| 1595 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); | 1431 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); |
| 1596 new_entry->SetString( | 1432 new_file->set_created_date(published_date); |
| 1597 "published.$t", | |
| 1598 google_apis::util::FormatTimeAsString(published_date)); | |
| 1599 | 1433 |
| 1600 // If there are no entries, prepare an empty entry to add. | 1434 EntryInfo* raw_new_entry = new_entry.release(); |
| 1601 if (!resource_list_value_->HasKey("entry")) | 1435 entries_[resource_id] = raw_new_entry; |
| 1602 resource_list_value_->Set("entry", new base::ListValue); | |
| 1603 | |
| 1604 base::DictionaryValue* raw_new_entry = new_entry.release(); | |
| 1605 base::ListValue* entries = NULL; | |
| 1606 if (resource_list_value_->GetList("entry", &entries)) | |
| 1607 entries->Append(raw_new_entry); | |
| 1608 | |
| 1609 return raw_new_entry; | 1436 return raw_new_entry; |
| 1610 } | 1437 } |
| 1611 | 1438 |
| 1612 void FakeDriveService::GetResourceListInternal( | 1439 void FakeDriveService::GetResourceListInternal( |
| 1613 int64 start_changestamp, | 1440 int64 start_changestamp, |
| 1614 const std::string& search_query, | 1441 const std::string& search_query, |
| 1615 const std::string& directory_resource_id, | 1442 const std::string& directory_resource_id, |
| 1616 int start_offset, | 1443 int start_offset, |
| 1617 int max_results, | 1444 int max_results, |
| 1618 int* load_counter, | 1445 int* load_counter, |
| 1619 const GetResourceListCallback& callback) { | 1446 const GetResourceListCallback& callback) { |
| 1620 if (offline_) { | 1447 if (offline_) { |
| 1621 base::MessageLoop::current()->PostTask( | 1448 base::MessageLoop::current()->PostTask( |
| 1622 FROM_HERE, | 1449 FROM_HERE, |
| 1623 base::Bind(callback, | 1450 base::Bind(callback, |
| 1624 GDATA_NO_CONNECTION, | 1451 GDATA_NO_CONNECTION, |
| 1625 base::Passed(scoped_ptr<ResourceList>()))); | 1452 base::Passed(scoped_ptr<ResourceList>()))); |
| 1626 return; | 1453 return; |
| 1627 } | 1454 } |
| 1628 | 1455 |
| 1629 scoped_ptr<ResourceList> resource_list = | |
| 1630 ResourceList::CreateFrom(*resource_list_value_); | |
| 1631 | |
| 1632 // TODO(hashimoto): Drive API always provides largest changestamp. Remove this | |
| 1633 // if-statement after API switch. | |
| 1634 if (start_changestamp > 0 && start_offset == 0) | |
| 1635 resource_list->set_largest_changestamp(largest_changestamp_); | |
| 1636 | |
| 1637 // Filter out entries per parameters like |directory_resource_id| and | 1456 // Filter out entries per parameters like |directory_resource_id| and |
| 1638 // |search_query|. | 1457 // |search_query|. |
| 1639 ScopedVector<ResourceEntry>* entries = resource_list->mutable_entries(); | 1458 ScopedVector<ResourceEntry> entries; |
| 1640 | |
| 1641 int num_entries_matched = 0; | 1459 int num_entries_matched = 0; |
| 1642 for (size_t i = 0; i < entries->size();) { | 1460 for (EntryInfoMap::iterator it = entries_.begin(); it != entries_.end(); |
| 1643 ResourceEntry* entry = (*entries)[i]; | 1461 ++it) { |
| 1462 scoped_ptr<ResourceEntry> entry = |
| 1463 util::ConvertChangeResourceToResourceEntry(it->second->change_resource); |
| 1644 bool should_exclude = false; | 1464 bool should_exclude = false; |
| 1645 | 1465 |
| 1646 // If |directory_resource_id| is set, exclude the entry if it's not in | 1466 // If |directory_resource_id| is set, exclude the entry if it's not in |
| 1647 // the target directory. | 1467 // the target directory. |
| 1648 if (!directory_resource_id.empty()) { | 1468 if (!directory_resource_id.empty()) { |
| 1649 // Get the parent resource ID of the entry. | 1469 // Get the parent resource ID of the entry. |
| 1650 std::string parent_resource_id; | 1470 std::string parent_resource_id; |
| 1651 const google_apis::Link* parent_link = | 1471 const google_apis::Link* parent_link = |
| 1652 entry->GetLinkByType(Link::LINK_PARENT); | 1472 entry->GetLinkByType(Link::LINK_PARENT); |
| 1653 if (parent_link) { | 1473 if (parent_link) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1681 // The entry matched the criteria for inclusion. | 1501 // The entry matched the criteria for inclusion. |
| 1682 if (!should_exclude) | 1502 if (!should_exclude) |
| 1683 ++num_entries_matched; | 1503 ++num_entries_matched; |
| 1684 | 1504 |
| 1685 // If |start_offset| is set, exclude the entry if the entry is before the | 1505 // If |start_offset| is set, exclude the entry if the entry is before the |
| 1686 // start index. <= instead of < as |num_entries_matched| was | 1506 // start index. <= instead of < as |num_entries_matched| was |
| 1687 // already incremented. | 1507 // already incremented. |
| 1688 if (start_offset > 0 && num_entries_matched <= start_offset) | 1508 if (start_offset > 0 && num_entries_matched <= start_offset) |
| 1689 should_exclude = true; | 1509 should_exclude = true; |
| 1690 | 1510 |
| 1691 if (should_exclude) | 1511 if (!should_exclude) |
| 1692 entries->erase(entries->begin() + i); | 1512 entries.push_back(entry.release()); |
| 1693 else | |
| 1694 ++i; | |
| 1695 } | 1513 } |
| 1696 | 1514 |
| 1515 scoped_ptr<ResourceList> resource_list(new ResourceList); |
| 1516 if (start_changestamp > 0 && start_offset == 0) |
| 1517 resource_list->set_largest_changestamp(largest_changestamp_); |
| 1518 |
| 1697 // If |max_results| is set, trim the entries if the number exceeded the max | 1519 // If |max_results| is set, trim the entries if the number exceeded the max |
| 1698 // results. | 1520 // results. |
| 1699 if (max_results > 0 && entries->size() > static_cast<size_t>(max_results)) { | 1521 if (max_results > 0 && entries.size() > static_cast<size_t>(max_results)) { |
| 1700 entries->erase(entries->begin() + max_results, entries->end()); | 1522 entries.erase(entries.begin() + max_results, entries.end()); |
| 1701 // Adds the next URL. | 1523 // Adds the next URL. |
| 1702 // Here, we embed information which is needed for continuing the | 1524 // Here, we embed information which is needed for continuing the |
| 1703 // GetResourceList request in the next invocation into url query | 1525 // GetResourceList request in the next invocation into url query |
| 1704 // parameters. | 1526 // parameters. |
| 1705 GURL next_url(base::StringPrintf( | 1527 GURL next_url(base::StringPrintf( |
| 1706 "http://localhost/?start-offset=%d&max-results=%d", | 1528 "http://localhost/?start-offset=%d&max-results=%d", |
| 1707 start_offset + max_results, | 1529 start_offset + max_results, |
| 1708 max_results)); | 1530 max_results)); |
| 1709 if (start_changestamp > 0) { | 1531 if (start_changestamp > 0) { |
| 1710 next_url = net::AppendOrReplaceQueryParameter( | 1532 next_url = net::AppendOrReplaceQueryParameter( |
| 1711 next_url, "changestamp", | 1533 next_url, "changestamp", |
| 1712 base::Int64ToString(start_changestamp).c_str()); | 1534 base::Int64ToString(start_changestamp).c_str()); |
| 1713 } | 1535 } |
| 1714 if (!search_query.empty()) { | 1536 if (!search_query.empty()) { |
| 1715 next_url = net::AppendOrReplaceQueryParameter( | 1537 next_url = net::AppendOrReplaceQueryParameter( |
| 1716 next_url, "q", search_query); | 1538 next_url, "q", search_query); |
| 1717 } | 1539 } |
| 1718 if (!directory_resource_id.empty()) { | 1540 if (!directory_resource_id.empty()) { |
| 1719 next_url = net::AppendOrReplaceQueryParameter( | 1541 next_url = net::AppendOrReplaceQueryParameter( |
| 1720 next_url, "parent", directory_resource_id); | 1542 next_url, "parent", directory_resource_id); |
| 1721 } | 1543 } |
| 1722 | 1544 |
| 1723 Link* link = new Link; | 1545 Link* link = new Link; |
| 1724 link->set_type(Link::LINK_NEXT); | 1546 link->set_type(Link::LINK_NEXT); |
| 1725 link->set_href(next_url); | 1547 link->set_href(next_url); |
| 1726 resource_list->mutable_links()->push_back(link); | 1548 resource_list->mutable_links()->push_back(link); |
| 1727 } | 1549 } |
| 1550 resource_list->set_entries(entries.Pass()); |
| 1728 | 1551 |
| 1729 if (load_counter) | 1552 if (load_counter) |
| 1730 *load_counter += 1; | 1553 *load_counter += 1; |
| 1731 base::MessageLoop::current()->PostTask( | 1554 base::MessageLoop::current()->PostTask( |
| 1732 FROM_HERE, | 1555 FROM_HERE, |
| 1733 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_list))); | 1556 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_list))); |
| 1734 } | 1557 } |
| 1735 | 1558 |
| 1736 GURL FakeDriveService::GetNewUploadSessionUrl() { | 1559 GURL FakeDriveService::GetNewUploadSessionUrl() { |
| 1737 return GURL("https://upload_session_url/" + | 1560 return GURL("https://upload_session_url/" + |
| 1738 base::Int64ToString(next_upload_sequence_number_++)); | 1561 base::Int64ToString(next_upload_sequence_number_++)); |
| 1739 } | 1562 } |
| 1740 | 1563 |
| 1741 } // namespace drive | 1564 } // namespace drive |
| OLD | NEW |