Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: chrome/browser/drive/fake_drive_service.cc

Issue 17140009: Support contents upload on FakeDriveService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: +completion callback Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/logging.h" 10 #include "base/logging.h"
11 #include "base/md5.h"
10 #include "base/message_loop.h" 12 #include "base/message_loop.h"
11 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h" 14 #include "base/strings/string_split.h"
13 #include "base/strings/string_tokenizer.h" 15 #include "base/strings/string_tokenizer.h"
14 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h" 17 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h" 18 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/google_apis/drive_api_parser.h" 19 #include "chrome/browser/google_apis/drive_api_parser.h"
18 #include "chrome/browser/google_apis/gdata_wapi_parser.h" 20 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
19 #include "chrome/browser/google_apis/test_util.h" 21 #include "chrome/browser/google_apis/test_util.h"
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 // TODO(peria): Deal with other attributes than title. 91 // TODO(peria): Deal with other attributes than title.
90 if (!key.empty() && key != "title") 92 if (!key.empty() && key != "title")
91 return false; 93 return false;
92 // Search query in the title. 94 // Search query in the title.
93 if (entry.title().find(value) == std::string::npos) 95 if (entry.title().find(value) == std::string::npos)
94 return false; 96 return false;
95 } 97 }
96 return true; 98 return true;
97 } 99 }
98 100
99 // Gets the upload URL from the given entry. Returns an empty URL if not
100 // found.
101 GURL GetUploadUrl(const base::DictionaryValue& entry) {
102 std::string upload_url;
103 const base::ListValue* links = NULL;
104 if (entry.GetList("link", &links) && links) {
105 for (size_t link_index = 0;
106 link_index < links->GetSize();
107 ++link_index) {
108 const base::DictionaryValue* link = NULL;
109 std::string rel;
110 if (links->GetDictionary(link_index, &link) &&
111 link && link->GetString("rel", &rel) &&
112 rel == kUploadUrlRel &&
113 link->GetString("href", &upload_url)) {
114 break;
115 }
116 }
117 }
118 return GURL(upload_url);
119 }
120
121 // Returns |url| without query parameter. 101 // Returns |url| without query parameter.
122 GURL RemoveQueryParameter(const GURL& url) { 102 GURL RemoveQueryParameter(const GURL& url) {
123 GURL::Replacements replacements; 103 GURL::Replacements replacements;
124 replacements.ClearQuery(); 104 replacements.ClearQuery();
125 return url.ReplaceComponents(replacements); 105 return url.ReplaceComponents(replacements);
126 } 106 }
127 107
108 void ScheduleUploadRangeCallback(const UploadRangeCallback& callback,
109 int64 start_position,
110 int64 end_position,
111 GDataErrorCode error,
112 scoped_ptr<ResourceEntry> entry) {
113 base::MessageLoop::current()->PostTask(
114 FROM_HERE,
115 base::Bind(callback,
116 UploadRangeResponse(GDATA_NO_CONNECTION,
hashimoto 2013/06/21 08:05:32 Shouldn't this be |error|?
tzik 2013/06/21 10:41:30 Done.
117 start_position,
118 end_position),
119 base::Passed(&entry)));
120 }
121
128 } // namespace 122 } // namespace
129 123
124 struct FakeDriveService::UploadSession {
125 std::string content_type;
126 int64 content_length;
127 std::string parent_resource_id;
128 std::string resource_id;
129 std::string etag;
130 std::string title;
131
132 int64 uploaded_size;
133
134 UploadSession()
135 : content_length(0),
136 uploaded_size(0) {}
137
138 UploadSession(
139 std::string content_type,
140 int64 content_length,
141 std::string parent_resource_id,
142 std::string resource_id,
143 std::string etag,
144 std::string title)
145 : content_type(content_type),
146 content_length(content_length),
147 parent_resource_id(parent_resource_id),
148 resource_id(resource_id),
149 etag(etag),
150 title(title),
151 uploaded_size(0) {
152 }
153 };
154
130 FakeDriveService::FakeDriveService() 155 FakeDriveService::FakeDriveService()
131 : largest_changestamp_(0), 156 : largest_changestamp_(0),
132 published_date_seq_(0), 157 published_date_seq_(0),
158 next_upload_sequence_number_(0),
133 default_max_results_(0), 159 default_max_results_(0),
134 resource_id_count_(0), 160 resource_id_count_(0),
135 resource_list_load_count_(0), 161 resource_list_load_count_(0),
136 change_list_load_count_(0), 162 change_list_load_count_(0),
137 directory_load_count_(0), 163 directory_load_count_(0),
138 about_resource_load_count_(0), 164 about_resource_load_count_(0),
139 offline_(false) { 165 offline_(false) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
141 } 167 }
142 168
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 if (!entry) { 567 if (!entry) {
542 base::MessageLoopProxy::current()->PostTask( 568 base::MessageLoopProxy::current()->PostTask(
543 FROM_HERE, 569 FROM_HERE,
544 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); 570 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath()));
545 return CancelCallback(); 571 return CancelCallback();
546 } 572 }
547 573
548 // Write "x"s of the file size specified in the entry. 574 // Write "x"s of the file size specified in the entry.
549 std::string file_size_string; 575 std::string file_size_string;
550 entry->GetString("docs$size.$t", &file_size_string); 576 entry->GetString("docs$size.$t", &file_size_string);
551 // TODO(satorux): To be correct, we should update docs$md5Checksum.$t here.
552 int64 file_size = 0; 577 int64 file_size = 0;
553 if (base::StringToInt64(file_size_string, &file_size)) { 578 if (base::StringToInt64(file_size_string, &file_size)) {
554 base::BinaryValue* content_binary_data; 579 base::BinaryValue* content_binary_data;
555 std::string content_data; 580 std::string content_data;
556 if (entry->GetBinary("test$data", &content_binary_data)) { 581 if (entry->GetBinary("test$data", &content_binary_data)) {
557 content_data = std::string(content_binary_data->GetBuffer(), 582 content_data = std::string(content_binary_data->GetBuffer(),
558 content_binary_data->GetSize()); 583 content_binary_data->GetSize());
559 } 584 }
560 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); 585 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
561 586
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 entry->Set("link", links); 668 entry->Set("link", links);
644 } 669 }
645 links->Clear(); 670 links->Clear();
646 671
647 base::DictionaryValue* link = new base::DictionaryValue; 672 base::DictionaryValue* link = new base::DictionaryValue;
648 link->SetString( 673 link->SetString(
649 "rel", "http://schemas.google.com/docs/2007#parent"); 674 "rel", "http://schemas.google.com/docs/2007#parent");
650 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); 675 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
651 links->Append(link); 676 links->Append(link);
652 677
653 AddNewChangestamp(copied_entry.get()); 678 AddNewChangestampAndETag(copied_entry.get());
654 679
655 // Parse the new entry. 680 // Parse the new entry.
656 scoped_ptr<ResourceEntry> resource_entry = 681 scoped_ptr<ResourceEntry> resource_entry =
657 ResourceEntry::CreateFrom(*copied_entry); 682 ResourceEntry::CreateFrom(*copied_entry);
658 // Add it to the resource list. 683 // Add it to the resource list.
659 entries->Append(copied_entry.release()); 684 entries->Append(copied_entry.release());
660 685
661 base::MessageLoop::current()->PostTask( 686 base::MessageLoop::current()->PostTask(
662 FROM_HERE, 687 FROM_HERE,
663 base::Bind(callback, 688 base::Bind(callback,
(...skipping 30 matching lines...) Expand all
694 719
695 if (offline_) { 720 if (offline_) {
696 base::MessageLoop::current()->PostTask( 721 base::MessageLoop::current()->PostTask(
697 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); 722 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
698 return CancelCallback(); 723 return CancelCallback();
699 } 724 }
700 725
701 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 726 base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
702 if (entry) { 727 if (entry) {
703 entry->SetString("title.$t", new_name); 728 entry->SetString("title.$t", new_name);
704 AddNewChangestamp(entry); 729 AddNewChangestampAndETag(entry);
705 base::MessageLoop::current()->PostTask( 730 base::MessageLoop::current()->PostTask(
706 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); 731 FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
707 return CancelCallback(); 732 return CancelCallback();
708 } 733 }
709 734
710 base::MessageLoop::current()->PostTask( 735 base::MessageLoop::current()->PostTask(
711 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 736 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
712 return CancelCallback(); 737 return CancelCallback();
713 } 738 }
714 739
(...skipping 21 matching lines...) Expand all
736 FROM_HERE, 761 FROM_HERE,
737 base::Bind(callback, HTTP_NOT_FOUND, 762 base::Bind(callback, HTTP_NOT_FOUND,
738 base::Passed(scoped_ptr<ResourceEntry>()))); 763 base::Passed(scoped_ptr<ResourceEntry>())));
739 return CancelCallback(); 764 return CancelCallback();
740 } 765 }
741 766
742 entry->SetString("updated.$t", 767 entry->SetString("updated.$t",
743 util::FormatTimeAsString(modified_date)); 768 util::FormatTimeAsString(modified_date));
744 entry->SetString("gd$lastViewed.$t", 769 entry->SetString("gd$lastViewed.$t",
745 util::FormatTimeAsString(last_viewed_by_me_date)); 770 util::FormatTimeAsString(last_viewed_by_me_date));
746 AddNewChangestamp(entry); 771 AddNewChangestampAndETag(entry);
747 772
748 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry)); 773 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry));
749 base::MessageLoop::current()->PostTask( 774 base::MessageLoop::current()->PostTask(
750 FROM_HERE, 775 FROM_HERE,
751 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); 776 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
752 return CancelCallback(); 777 return CancelCallback();
753 } 778 }
754 779
755 CancelCallback FakeDriveService::AddResourceToDirectory( 780 CancelCallback FakeDriveService::AddResourceToDirectory(
756 const std::string& parent_resource_id, 781 const std::string& parent_resource_id,
(...skipping 19 matching lines...) Expand all
776 // On the real Drive server, resources do not necessary shape a tree 801 // On the real Drive server, resources do not necessary shape a tree
777 // structure. That is, each resource can have multiple parent. 802 // structure. That is, each resource can have multiple parent.
778 // We mimic the behavior here; AddResourceToDirectoy just adds 803 // We mimic the behavior here; AddResourceToDirectoy just adds
779 // one more parent link, not overwriting old links. 804 // one more parent link, not overwriting old links.
780 base::DictionaryValue* link = new base::DictionaryValue; 805 base::DictionaryValue* link = new base::DictionaryValue;
781 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); 806 link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
782 link->SetString( 807 link->SetString(
783 "href", GetFakeLinkUrl(parent_resource_id).spec()); 808 "href", GetFakeLinkUrl(parent_resource_id).spec());
784 links->Append(link); 809 links->Append(link);
785 810
786 AddNewChangestamp(entry); 811 AddNewChangestampAndETag(entry);
787 base::MessageLoop::current()->PostTask( 812 base::MessageLoop::current()->PostTask(
788 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); 813 FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
789 return CancelCallback(); 814 return CancelCallback();
790 } 815 }
791 816
792 base::MessageLoop::current()->PostTask( 817 base::MessageLoop::current()->PostTask(
793 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 818 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
794 return CancelCallback(); 819 return CancelCallback();
795 } 820 }
796 821
(...skipping 18 matching lines...) Expand all
815 for (size_t i = 0; i < links->GetSize(); ++i) { 840 for (size_t i = 0; i < links->GetSize(); ++i) {
816 base::DictionaryValue* link = NULL; 841 base::DictionaryValue* link = NULL;
817 std::string rel; 842 std::string rel;
818 std::string href; 843 std::string href;
819 if (links->GetDictionary(i, &link) && 844 if (links->GetDictionary(i, &link) &&
820 link->GetString("rel", &rel) && 845 link->GetString("rel", &rel) &&
821 link->GetString("href", &href) && 846 link->GetString("href", &href) &&
822 rel == "http://schemas.google.com/docs/2007#parent" && 847 rel == "http://schemas.google.com/docs/2007#parent" &&
823 GURL(href) == parent_content_url) { 848 GURL(href) == parent_content_url) {
824 links->Remove(i, NULL); 849 links->Remove(i, NULL);
825 AddNewChangestamp(entry); 850 AddNewChangestampAndETag(entry);
826 base::MessageLoop::current()->PostTask( 851 base::MessageLoop::current()->PostTask(
827 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); 852 FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
828 return CancelCallback(); 853 return CancelCallback();
829 } 854 }
830 } 855 }
831 } 856 }
832 } 857 }
833 858
834 base::MessageLoop::current()->PostTask( 859 base::MessageLoop::current()->PostTask(
835 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 860 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
885 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 910 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
886 DCHECK(!callback.is_null()); 911 DCHECK(!callback.is_null());
887 912
888 if (offline_) { 913 if (offline_) {
889 base::MessageLoop::current()->PostTask( 914 base::MessageLoop::current()->PostTask(
890 FROM_HERE, 915 FROM_HERE,
891 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); 916 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
892 return CancelCallback(); 917 return CancelCallback();
893 } 918 }
894 919
895 // Content length should be zero, as we'll create an empty file first. The 920 if (parent_resource_id != GetRootResourceId() &&
896 // content will be added in ResumeUpload(). 921 !FindEntryByResourceId(parent_resource_id)) {
897 const base::DictionaryValue* new_entry = AddNewEntry(content_type,
898 "", // content_data
899 parent_resource_id,
900 title,
901 false, // shared_with_me
902 "file");
903 if (!new_entry) {
904 base::MessageLoop::current()->PostTask( 922 base::MessageLoop::current()->PostTask(
905 FROM_HERE, 923 FROM_HERE,
906 base::Bind(callback, HTTP_NOT_FOUND, GURL())); 924 base::Bind(callback, HTTP_NOT_FOUND, GURL()));
907 return CancelCallback(); 925 return CancelCallback();
908 } 926 }
909 const GURL upload_url = GetUploadUrl(*new_entry); 927
910 DCHECK(upload_url.is_valid()); 928 GURL session_url = GetNewUploadSessionUrl();
929 upload_sessions_[session_url] =
930 UploadSession(content_type, content_length,
931 parent_resource_id,
932 "", // resource_id
933 "", // etag
934 title);
911 935
912 base::MessageLoop::current()->PostTask( 936 base::MessageLoop::current()->PostTask(
913 FROM_HERE, 937 FROM_HERE,
914 base::Bind(callback, HTTP_SUCCESS, 938 base::Bind(callback, HTTP_SUCCESS, session_url));
915 net::AppendQueryParameter(upload_url, "mode", "newfile")));
916 return CancelCallback(); 939 return CancelCallback();
917 } 940 }
918 941
919 CancelCallback FakeDriveService::InitiateUploadExistingFile( 942 CancelCallback FakeDriveService::InitiateUploadExistingFile(
920 const base::FilePath& drive_file_path, 943 const base::FilePath& drive_file_path,
921 const std::string& content_type, 944 const std::string& content_type,
922 int64 content_length, 945 int64 content_length,
923 const std::string& resource_id, 946 const std::string& resource_id,
924 const std::string& etag, 947 const std::string& etag,
925 const InitiateUploadCallback& callback) { 948 const InitiateUploadCallback& callback) {
(...skipping 16 matching lines...) Expand all
942 } 965 }
943 966
944 std::string entry_etag; 967 std::string entry_etag;
945 entry->GetString("gd$etag", &entry_etag); 968 entry->GetString("gd$etag", &entry_etag);
946 if (!etag.empty() && etag != entry_etag) { 969 if (!etag.empty() && etag != entry_etag) {
947 base::MessageLoop::current()->PostTask( 970 base::MessageLoop::current()->PostTask(
948 FROM_HERE, 971 FROM_HERE,
949 base::Bind(callback, HTTP_PRECONDITION, GURL())); 972 base::Bind(callback, HTTP_PRECONDITION, GURL()));
950 return CancelCallback(); 973 return CancelCallback();
951 } 974 }
952 entry->SetString("docs$size.$t", "0");
953 975
954 const GURL upload_url = GetUploadUrl(*entry); 976 GURL session_url = GetNewUploadSessionUrl();
955 DCHECK(upload_url.is_valid()); 977 upload_sessions_[session_url] =
978 UploadSession(content_type, content_length,
979 "", // parent_resource_id
980 resource_id,
981 entry_etag,
982 "" /* title */);
956 983
957 base::MessageLoop::current()->PostTask( 984 base::MessageLoop::current()->PostTask(
958 FROM_HERE, 985 FROM_HERE,
959 base::Bind(callback, HTTP_SUCCESS, 986 base::Bind(callback, HTTP_SUCCESS, session_url));
960 net::AppendQueryParameter(upload_url, "mode", "existing")));
961 return CancelCallback(); 987 return CancelCallback();
962 } 988 }
963 989
964 CancelCallback FakeDriveService::GetUploadStatus( 990 CancelCallback FakeDriveService::GetUploadStatus(
965 const base::FilePath& drive_file_path, 991 const base::FilePath& drive_file_path,
966 const GURL& upload_url, 992 const GURL& upload_url,
967 int64 content_length, 993 int64 content_length,
968 const UploadRangeCallback& callback) { 994 const UploadRangeCallback& callback) {
969 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 995 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
970 DCHECK(!callback.is_null()); 996 DCHECK(!callback.is_null());
971 return CancelCallback(); 997 return CancelCallback();
972 } 998 }
973 999
974 CancelCallback FakeDriveService::ResumeUpload( 1000 CancelCallback FakeDriveService::ResumeUpload(
975 const base::FilePath& drive_file_path, 1001 const base::FilePath& drive_file_path,
976 const GURL& upload_url, 1002 const GURL& upload_url,
977 int64 start_position, 1003 int64 start_position,
978 int64 end_position, 1004 int64 end_position,
979 int64 content_length, 1005 int64 content_length,
980 const std::string& content_type, 1006 const std::string& content_type,
981 const base::FilePath& local_file_path, 1007 const base::FilePath& local_file_path,
982 const UploadRangeCallback& callback, 1008 const UploadRangeCallback& callback,
983 const ProgressCallback& progress_callback) { 1009 const ProgressCallback& progress_callback) {
984 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1010 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
985 DCHECK(!callback.is_null()); 1011 DCHECK(!callback.is_null());
986 1012
987 scoped_ptr<ResourceEntry> result_entry; 1013 GetResourceEntryCallback completion_callback
1014 = base::Bind(&ScheduleUploadRangeCallback,
1015 callback, start_position, end_position);
988 1016
1017 scoped_ptr<ResourceEntry> uploaded_entry;
hashimoto 2013/06/21 08:05:32 nit: It seems there is no need to have this variab
tzik 2013/06/21 10:41:30 Done.
989 if (offline_) { 1018 if (offline_) {
990 base::MessageLoop::current()->PostTask( 1019 completion_callback.Run(GDATA_NO_CONNECTION,
991 FROM_HERE, 1020 uploaded_entry.Pass());
992 base::Bind(callback,
993 UploadRangeResponse(GDATA_NO_CONNECTION,
994 start_position,
995 end_position),
996 base::Passed(&result_entry)));
997 return CancelCallback(); 1021 return CancelCallback();
998 } 1022 }
999 1023
1000 DictionaryValue* entry = NULL; 1024 if (!upload_sessions_.count(upload_url)) {
1001 entry = FindEntryByUploadUrl(RemoveQueryParameter(upload_url)); 1025 completion_callback.Run(HTTP_NOT_FOUND,
hashimoto 2013/06/21 08:05:32 nit: The next line can be merged into this line wi
tzik 2013/06/21 10:41:30 Done.
1002 if (!entry) { 1026 uploaded_entry.Pass());
1003 base::MessageLoop::current()->PostTask(
1004 FROM_HERE,
1005 base::Bind(callback,
1006 UploadRangeResponse(HTTP_NOT_FOUND,
1007 start_position,
1008 end_position),
1009 base::Passed(&result_entry)));
1010 return CancelCallback(); 1027 return CancelCallback();
1011 } 1028 }
1012 1029
1030 UploadSession* session = &upload_sessions_[upload_url];
1031
1013 // Chunks are required to be sent in such a ways that they fill from the start 1032 // Chunks are required to be sent in such a ways that they fill from the start
1014 // of the not-yet-uploaded part with no gaps nor overlaps. 1033 // of the not-yet-uploaded part with no gaps nor overlaps.
1015 std::string current_size_string; 1034 if (session->uploaded_size != start_position) {
1016 int64 current_size; 1035 completion_callback.Run(HTTP_BAD_REQUEST,
1017 if (!entry->GetString("docs$size.$t", &current_size_string) || 1036 uploaded_entry.Pass());
1018 !base::StringToInt64(current_size_string, &current_size) ||
1019 current_size != start_position) {
1020 base::MessageLoop::current()->PostTask(
1021 FROM_HERE,
1022 base::Bind(callback,
1023 UploadRangeResponse(HTTP_BAD_REQUEST,
1024 start_position,
1025 end_position),
1026 base::Passed(&result_entry)));
1027 return CancelCallback(); 1037 return CancelCallback();
1028 } 1038 }
1029 1039
1030 entry->SetString("docs$size.$t", base::Int64ToString(end_position));
1031
1032 if (!progress_callback.is_null()) { 1040 if (!progress_callback.is_null()) {
1033 // In the real GDataWapi/Drive DriveService, progress is reported in 1041 // In the real GDataWapi/Drive DriveService, progress is reported in
1034 // nondeterministic timing. In this fake implementation, we choose to call 1042 // nondeterministic timing. In this fake implementation, we choose to call
1035 // it twice per one ResumeUpload. This is for making sure that client code 1043 // it twice per one ResumeUpload. This is for making sure that client code
1036 // works fine even if the callback is invoked more than once; it is the 1044 // works fine even if the callback is invoked more than once; it is the
1037 // crucial difference of the progress callback from others. 1045 // crucial difference of the progress callback from others.
1038 // Note that progress is notified in the relative offset in each chunk. 1046 // Note that progress is notified in the relative offset in each chunk.
1039 const int64 chunk_size = end_position - start_position; 1047 const int64 chunk_size = end_position - start_position;
1040 base::MessageLoop::current()->PostTask( 1048 base::MessageLoop::current()->PostTask(
1041 FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size)); 1049 FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size));
1042 base::MessageLoop::current()->PostTask( 1050 base::MessageLoop::current()->PostTask(
1043 FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size)); 1051 FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size));
1044 } 1052 }
1045 1053
1046 if (content_length != end_position) { 1054 if (content_length != end_position) {
1047 base::MessageLoop::current()->PostTask( 1055 session->uploaded_size = end_position;
1048 FROM_HERE, 1056 completion_callback.Run(HTTP_RESUME_INCOMPLETE,
1049 base::Bind(callback, 1057 uploaded_entry.Pass());
1050 UploadRangeResponse(HTTP_RESUME_INCOMPLETE,
1051 start_position,
1052 end_position),
1053 base::Passed(&result_entry)));
1054 return CancelCallback(); 1058 return CancelCallback();
1055 } 1059 }
1056 1060
1057 AddNewChangestamp(entry); 1061 std::string content_data;
1058 result_entry = ResourceEntry::CreateFrom(*entry).Pass(); 1062 if (!file_util::ReadFileToString(local_file_path, &content_data)) {
1063 session->uploaded_size = end_position;
1064 completion_callback.Run(GDATA_FILE_ERROR,
1065 uploaded_entry.Pass());
1066 return CancelCallback();
1067 }
1068 session->uploaded_size = end_position;
1059 1069
1060 std::string upload_mode; 1070 // |resource_id| is empty if the upload is for new file.
1061 bool upload_mode_found = 1071 if (session->resource_id.empty()) {
1062 net::GetValueForKeyInQuery(upload_url, "mode", &upload_mode); 1072 DCHECK(!session->parent_resource_id.empty());
1063 DCHECK(upload_mode_found && 1073 DCHECK(!session->title.empty());
1064 (upload_mode == "newfile" || upload_mode == "existing")); 1074 const DictionaryValue* new_entry = AddNewEntry(
1075 session->content_type,
1076 content_data,
1077 session->parent_resource_id,
1078 session->title,
1079 false, // shared_with_me
1080 "file");
1081 if (!new_entry) {
1082 completion_callback.Run(HTTP_NOT_FOUND,
1083 uploaded_entry.Pass());
1084 return CancelCallback();
1085 }
1065 1086
1066 GDataErrorCode return_code = 1087 uploaded_entry = ResourceEntry::CreateFrom(*new_entry);
1067 upload_mode == "newfile" ? HTTP_CREATED : HTTP_SUCCESS; 1088 completion_callback.Run(HTTP_CREATED,
1089 uploaded_entry.Pass());
1090 return CancelCallback();
1091 }
1068 1092
1069 base::MessageLoop::current()->PostTask( 1093 DictionaryValue* entry = FindEntryByResourceId(session->resource_id);
1070 FROM_HERE, 1094 if (!entry) {
1071 base::Bind(callback, 1095 completion_callback.Run(HTTP_NOT_FOUND,
1072 UploadRangeResponse(return_code, 1096 uploaded_entry.Pass());
1073 start_position, 1097 return CancelCallback();
1074 end_position), 1098 }
1075 base::Passed(&result_entry))); 1099
1100 std::string entry_etag;
1101 entry->GetString("gd$etag", &entry_etag);
1102 if (entry_etag.empty() || session->etag != entry_etag) {
1103 completion_callback.Run(HTTP_PRECONDITION,
1104 uploaded_entry.Pass());
1105 return CancelCallback();
1106 }
1107
1108 entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data));
1109 entry->Set("test$data",
1110 base::BinaryValue::CreateWithCopiedBuffer(
1111 content_data.data(), content_data.size()));
1112 entry->SetString("docs$size.$t", base::Int64ToString(end_position));
1113 AddNewChangestampAndETag(entry);
1114
1115 uploaded_entry = ResourceEntry::CreateFrom(*entry);
1116 completion_callback.Run(HTTP_SUCCESS,
1117 uploaded_entry.Pass());
1076 return CancelCallback(); 1118 return CancelCallback();
1077 } 1119 }
1078 1120
1079 CancelCallback FakeDriveService::AuthorizeApp( 1121 CancelCallback FakeDriveService::AuthorizeApp(
1080 const std::string& resource_id, 1122 const std::string& resource_id,
1081 const std::string& app_id, 1123 const std::string& app_id,
1082 const AuthorizeAppCallback& callback) { 1124 const AuthorizeAppCallback& callback) {
1083 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1084 DCHECK(!callback.is_null()); 1126 DCHECK(!callback.is_null());
1085 return CancelCallback(); 1127 return CancelCallback();
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
1207 entry->GetString("content.src", &current_content_url) && 1249 entry->GetString("content.src", &current_content_url) &&
1208 content_url == GURL(current_content_url)) { 1250 content_url == GURL(current_content_url)) {
1209 return entry; 1251 return entry;
1210 } 1252 }
1211 } 1253 }
1212 } 1254 }
1213 1255
1214 return NULL; 1256 return NULL;
1215 } 1257 }
1216 1258
1217 base::DictionaryValue* FakeDriveService::FindEntryByUploadUrl(
1218 const GURL& upload_url) {
1219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1220
1221 base::ListValue* entries = NULL;
1222 // Go through entries and return the one that matches |upload_url|.
1223 if (resource_list_value_->GetList("entry", &entries)) {
1224 for (size_t i = 0; i < entries->GetSize(); ++i) {
1225 base::DictionaryValue* entry = NULL;
1226 base::ListValue* links = NULL;
1227 if (entries->GetDictionary(i, &entry) &&
1228 entry->GetList("link", &links) &&
1229 links) {
1230 for (size_t link_index = 0;
1231 link_index < links->GetSize();
1232 ++link_index) {
1233 base::DictionaryValue* link = NULL;
1234 std::string rel;
1235 std::string found_upload_url;
1236 if (links->GetDictionary(link_index, &link) &&
1237 link && link->GetString("rel", &rel) &&
1238 rel == kUploadUrlRel &&
1239 link->GetString("href", &found_upload_url) &&
1240 GURL(found_upload_url) == upload_url) {
1241 return entry;
1242 }
1243 }
1244 }
1245 }
1246 }
1247
1248 return NULL;
1249 }
1250
1251 std::string FakeDriveService::GetNewResourceId() { 1259 std::string FakeDriveService::GetNewResourceId() {
1252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1253 1261
1254 ++resource_id_count_; 1262 ++resource_id_count_;
1255 return base::StringPrintf("resource_id_%d", resource_id_count_); 1263 return base::StringPrintf("resource_id_%d", resource_id_count_);
1256 } 1264 }
1257 1265
1258 void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) { 1266 void FakeDriveService::AddNewChangestampAndETag(base::DictionaryValue* entry) {
1259 ++largest_changestamp_; 1267 ++largest_changestamp_;
1260 entry->SetString("docs$changestamp.value", 1268 entry->SetString("docs$changestamp.value",
1261 base::Int64ToString(largest_changestamp_)); 1269 base::Int64ToString(largest_changestamp_));
1270 entry->SetString("gd$etag",
1271 "etag_" + base::Int64ToString(largest_changestamp_));
1262 } 1272 }
1263 1273
1264 const base::DictionaryValue* FakeDriveService::AddNewEntry( 1274 const base::DictionaryValue* FakeDriveService::AddNewEntry(
1265 const std::string& content_type, 1275 const std::string& content_type,
1266 const std::string& content_data, 1276 const std::string& content_data,
1267 const std::string& parent_resource_id, 1277 const std::string& parent_resource_id,
1268 const std::string& title, 1278 const std::string& title,
1269 bool shared_with_me, 1279 bool shared_with_me,
1270 const std::string& entry_kind) { 1280 const std::string& entry_kind) {
1271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
(...skipping 11 matching lines...) Expand all
1283 new_entry->SetString("gd$resourceId.$t", resource_id); 1293 new_entry->SetString("gd$resourceId.$t", resource_id);
1284 new_entry->SetString("title.$t", title); 1294 new_entry->SetString("title.$t", title);
1285 new_entry->SetString("docs$filename", title); 1295 new_entry->SetString("docs$filename", title);
1286 // Set the contents, size and MD5 for a file. 1296 // Set the contents, size and MD5 for a file.
1287 if (entry_kind == "file") { 1297 if (entry_kind == "file") {
1288 new_entry->Set("test$data", 1298 new_entry->Set("test$data",
1289 base::BinaryValue::CreateWithCopiedBuffer( 1299 base::BinaryValue::CreateWithCopiedBuffer(
1290 content_data.c_str(), content_data.size())); 1300 content_data.c_str(), content_data.size()));
1291 new_entry->SetString("docs$size.$t", 1301 new_entry->SetString("docs$size.$t",
1292 base::Int64ToString(content_data.size())); 1302 base::Int64ToString(content_data.size()));
1293 // TODO(satorux): Set the correct MD5 here.
1294 new_entry->SetString("docs$md5Checksum.$t", 1303 new_entry->SetString("docs$md5Checksum.$t",
1295 "3b4385ebefec6e743574c76bbd0575de"); 1304 base::MD5String(content_data));
1296 } 1305 }
1297 1306
1298 // Add "category" which sets the resource type to |entry_kind|. 1307 // Add "category" which sets the resource type to |entry_kind|.
1299 base::ListValue* categories = new base::ListValue; 1308 base::ListValue* categories = new base::ListValue;
1300 base::DictionaryValue* category = new base::DictionaryValue; 1309 base::DictionaryValue* category = new base::DictionaryValue;
1301 category->SetString("scheme", "http://schemas.google.com/g/2005#kind"); 1310 category->SetString("scheme", "http://schemas.google.com/g/2005#kind");
1302 category->SetString("term", "http://schemas.google.com/docs/2007#" + 1311 category->SetString("term", "http://schemas.google.com/docs/2007#" +
1303 entry_kind); 1312 entry_kind);
1304 categories->Append(category); 1313 categories->Append(category);
1305 new_entry->Set("category", categories); 1314 new_entry->Set("category", categories);
(...skipping 28 matching lines...) Expand all
1334 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id); 1343 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id);
1335 edit_link->SetString("rel", "edit"); 1344 edit_link->SetString("rel", "edit");
1336 links->Append(edit_link); 1345 links->Append(edit_link);
1337 1346
1338 base::DictionaryValue* upload_link = new base::DictionaryValue; 1347 base::DictionaryValue* upload_link = new base::DictionaryValue;
1339 upload_link->SetString("href", upload_url.spec()); 1348 upload_link->SetString("href", upload_url.spec());
1340 upload_link->SetString("rel", kUploadUrlRel); 1349 upload_link->SetString("rel", kUploadUrlRel);
1341 links->Append(upload_link); 1350 links->Append(upload_link);
1342 new_entry->Set("link", links); 1351 new_entry->Set("link", links);
1343 1352
1344 AddNewChangestamp(new_entry.get()); 1353 AddNewChangestampAndETag(new_entry.get());
1345 1354
1346 base::Time published_date = 1355 base::Time published_date =
1347 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); 1356 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
1348 new_entry->SetString("published.$t", 1357 new_entry->SetString("published.$t",
1349 util::FormatTimeAsString(published_date)); 1358 util::FormatTimeAsString(published_date));
1350 1359
1351 // If there are no entries, prepare an empty entry to add. 1360 // If there are no entries, prepare an empty entry to add.
1352 if (!resource_list_value_->HasKey("entry")) 1361 if (!resource_list_value_->HasKey("entry"))
1353 resource_list_value_->Set("entry", new ListValue); 1362 resource_list_value_->Set("entry", new ListValue);
1354 1363
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1470 1479
1471 if (load_counter) 1480 if (load_counter)
1472 *load_counter += 1; 1481 *load_counter += 1;
1473 base::MessageLoop::current()->PostTask( 1482 base::MessageLoop::current()->PostTask(
1474 FROM_HERE, 1483 FROM_HERE,
1475 base::Bind(callback, 1484 base::Bind(callback,
1476 HTTP_SUCCESS, 1485 HTTP_SUCCESS,
1477 base::Passed(&resource_list))); 1486 base::Passed(&resource_list)));
1478 } 1487 }
1479 1488
1489 GURL FakeDriveService::GetNewUploadSessionUrl() {
1490 return GURL("https://upload_session_url/" +
1491 base::Int64ToString(next_upload_sequence_number_++));
1492 }
1493
1480 } // namespace drive 1494 } // namespace drive
OLDNEW
« no previous file with comments | « chrome/browser/drive/fake_drive_service.h ('k') | chrome/browser/drive/fake_drive_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698