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/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 Loading... | |
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 |
128 } // namespace | 108 } // namespace |
129 | 109 |
110 struct FakeDriveService::UploadSession { | |
111 std::string content_type; | |
112 int64 content_length; | |
113 std::string parent_resource_id; | |
114 std::string resource_id; | |
115 std::string etag; | |
116 std::string title; | |
117 | |
118 int64 uploaded_size; | |
119 | |
120 UploadSession() | |
121 : content_length(0), | |
122 uploaded_size(0) {} | |
123 | |
124 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 : content_type(content_type), | |
132 content_length(content_length), | |
133 parent_resource_id(parent_resource_id), | |
134 resource_id(resource_id), | |
135 etag(etag), | |
136 title(title), | |
137 uploaded_size(0) { | |
138 } | |
139 }; | |
140 | |
130 FakeDriveService::FakeDriveService() | 141 FakeDriveService::FakeDriveService() |
131 : largest_changestamp_(0), | 142 : largest_changestamp_(0), |
132 published_date_seq_(0), | 143 published_date_seq_(0), |
144 next_upload_sequence_number_(0), | |
133 default_max_results_(0), | 145 default_max_results_(0), |
134 resource_id_count_(0), | 146 resource_id_count_(0), |
135 resource_list_load_count_(0), | 147 resource_list_load_count_(0), |
136 change_list_load_count_(0), | 148 change_list_load_count_(0), |
137 directory_load_count_(0), | 149 directory_load_count_(0), |
138 about_resource_load_count_(0), | 150 about_resource_load_count_(0), |
139 offline_(false) { | 151 offline_(false) { |
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
141 } | 153 } |
142 | 154 |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
541 if (!entry) { | 553 if (!entry) { |
542 base::MessageLoopProxy::current()->PostTask( | 554 base::MessageLoopProxy::current()->PostTask( |
543 FROM_HERE, | 555 FROM_HERE, |
544 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); | 556 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); |
545 return CancelCallback(); | 557 return CancelCallback(); |
546 } | 558 } |
547 | 559 |
548 // Write "x"s of the file size specified in the entry. | 560 // Write "x"s of the file size specified in the entry. |
549 std::string file_size_string; | 561 std::string file_size_string; |
550 entry->GetString("docs$size.$t", &file_size_string); | 562 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; | 563 int64 file_size = 0; |
553 if (base::StringToInt64(file_size_string, &file_size)) { | 564 if (base::StringToInt64(file_size_string, &file_size)) { |
554 base::BinaryValue* content_binary_data; | 565 base::BinaryValue* content_binary_data; |
555 std::string content_data; | 566 std::string content_data; |
556 if (entry->GetBinary("test$data", &content_binary_data)) { | 567 if (entry->GetBinary("test$data", &content_binary_data)) { |
557 content_data = std::string(content_binary_data->GetBuffer(), | 568 content_data = std::string(content_binary_data->GetBuffer(), |
558 content_binary_data->GetSize()); | 569 content_binary_data->GetSize()); |
559 } | 570 } |
560 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); | 571 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); |
561 | 572 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
643 entry->Set("link", links); | 654 entry->Set("link", links); |
644 } | 655 } |
645 links->Clear(); | 656 links->Clear(); |
646 | 657 |
647 base::DictionaryValue* link = new base::DictionaryValue; | 658 base::DictionaryValue* link = new base::DictionaryValue; |
648 link->SetString( | 659 link->SetString( |
649 "rel", "http://schemas.google.com/docs/2007#parent"); | 660 "rel", "http://schemas.google.com/docs/2007#parent"); |
650 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); | 661 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); |
651 links->Append(link); | 662 links->Append(link); |
652 | 663 |
653 AddNewChangestamp(copied_entry.get()); | 664 AddNewChangestampAndETag(copied_entry.get()); |
654 | 665 |
655 // Parse the new entry. | 666 // Parse the new entry. |
656 scoped_ptr<ResourceEntry> resource_entry = | 667 scoped_ptr<ResourceEntry> resource_entry = |
657 ResourceEntry::CreateFrom(*copied_entry); | 668 ResourceEntry::CreateFrom(*copied_entry); |
658 // Add it to the resource list. | 669 // Add it to the resource list. |
659 entries->Append(copied_entry.release()); | 670 entries->Append(copied_entry.release()); |
660 | 671 |
661 base::MessageLoop::current()->PostTask( | 672 base::MessageLoop::current()->PostTask( |
662 FROM_HERE, | 673 FROM_HERE, |
663 base::Bind(callback, | 674 base::Bind(callback, |
(...skipping 30 matching lines...) Expand all Loading... | |
694 | 705 |
695 if (offline_) { | 706 if (offline_) { |
696 base::MessageLoop::current()->PostTask( | 707 base::MessageLoop::current()->PostTask( |
697 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 708 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
698 return CancelCallback(); | 709 return CancelCallback(); |
699 } | 710 } |
700 | 711 |
701 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 712 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); |
702 if (entry) { | 713 if (entry) { |
703 entry->SetString("title.$t", new_name); | 714 entry->SetString("title.$t", new_name); |
704 AddNewChangestamp(entry); | 715 AddNewChangestampAndETag(entry); |
705 base::MessageLoop::current()->PostTask( | 716 base::MessageLoop::current()->PostTask( |
706 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); | 717 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); |
707 return CancelCallback(); | 718 return CancelCallback(); |
708 } | 719 } |
709 | 720 |
710 base::MessageLoop::current()->PostTask( | 721 base::MessageLoop::current()->PostTask( |
711 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 722 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
712 return CancelCallback(); | 723 return CancelCallback(); |
713 } | 724 } |
714 | 725 |
(...skipping 21 matching lines...) Expand all Loading... | |
736 FROM_HERE, | 747 FROM_HERE, |
737 base::Bind(callback, HTTP_NOT_FOUND, | 748 base::Bind(callback, HTTP_NOT_FOUND, |
738 base::Passed(scoped_ptr<ResourceEntry>()))); | 749 base::Passed(scoped_ptr<ResourceEntry>()))); |
739 return CancelCallback(); | 750 return CancelCallback(); |
740 } | 751 } |
741 | 752 |
742 entry->SetString("updated.$t", | 753 entry->SetString("updated.$t", |
743 util::FormatTimeAsString(modified_date)); | 754 util::FormatTimeAsString(modified_date)); |
744 entry->SetString("gd$lastViewed.$t", | 755 entry->SetString("gd$lastViewed.$t", |
745 util::FormatTimeAsString(last_viewed_by_me_date)); | 756 util::FormatTimeAsString(last_viewed_by_me_date)); |
746 AddNewChangestamp(entry); | 757 AddNewChangestampAndETag(entry); |
747 | 758 |
748 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry)); | 759 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry)); |
749 base::MessageLoop::current()->PostTask( | 760 base::MessageLoop::current()->PostTask( |
750 FROM_HERE, | 761 FROM_HERE, |
751 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); | 762 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); |
752 return CancelCallback(); | 763 return CancelCallback(); |
753 } | 764 } |
754 | 765 |
755 CancelCallback FakeDriveService::AddResourceToDirectory( | 766 CancelCallback FakeDriveService::AddResourceToDirectory( |
756 const std::string& parent_resource_id, | 767 const std::string& parent_resource_id, |
(...skipping 19 matching lines...) Expand all Loading... | |
776 // On the real Drive server, resources do not necessary shape a tree | 787 // On the real Drive server, resources do not necessary shape a tree |
777 // structure. That is, each resource can have multiple parent. | 788 // structure. That is, each resource can have multiple parent. |
778 // We mimic the behavior here; AddResourceToDirectoy just adds | 789 // We mimic the behavior here; AddResourceToDirectoy just adds |
779 // one more parent link, not overwriting old links. | 790 // one more parent link, not overwriting old links. |
780 base::DictionaryValue* link = new base::DictionaryValue; | 791 base::DictionaryValue* link = new base::DictionaryValue; |
781 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); | 792 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); |
782 link->SetString( | 793 link->SetString( |
783 "href", GetFakeLinkUrl(parent_resource_id).spec()); | 794 "href", GetFakeLinkUrl(parent_resource_id).spec()); |
784 links->Append(link); | 795 links->Append(link); |
785 | 796 |
786 AddNewChangestamp(entry); | 797 AddNewChangestampAndETag(entry); |
787 base::MessageLoop::current()->PostTask( | 798 base::MessageLoop::current()->PostTask( |
788 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); | 799 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); |
789 return CancelCallback(); | 800 return CancelCallback(); |
790 } | 801 } |
791 | 802 |
792 base::MessageLoop::current()->PostTask( | 803 base::MessageLoop::current()->PostTask( |
793 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 804 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
794 return CancelCallback(); | 805 return CancelCallback(); |
795 } | 806 } |
796 | 807 |
(...skipping 18 matching lines...) Expand all Loading... | |
815 for (size_t i = 0; i < links->GetSize(); ++i) { | 826 for (size_t i = 0; i < links->GetSize(); ++i) { |
816 base::DictionaryValue* link = NULL; | 827 base::DictionaryValue* link = NULL; |
817 std::string rel; | 828 std::string rel; |
818 std::string href; | 829 std::string href; |
819 if (links->GetDictionary(i, &link) && | 830 if (links->GetDictionary(i, &link) && |
820 link->GetString("rel", &rel) && | 831 link->GetString("rel", &rel) && |
821 link->GetString("href", &href) && | 832 link->GetString("href", &href) && |
822 rel == "http://schemas.google.com/docs/2007#parent" && | 833 rel == "http://schemas.google.com/docs/2007#parent" && |
823 GURL(href) == parent_content_url) { | 834 GURL(href) == parent_content_url) { |
824 links->Remove(i, NULL); | 835 links->Remove(i, NULL); |
825 AddNewChangestamp(entry); | 836 AddNewChangestampAndETag(entry); |
826 base::MessageLoop::current()->PostTask( | 837 base::MessageLoop::current()->PostTask( |
827 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); | 838 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); |
828 return CancelCallback(); | 839 return CancelCallback(); |
829 } | 840 } |
830 } | 841 } |
831 } | 842 } |
832 } | 843 } |
833 | 844 |
834 base::MessageLoop::current()->PostTask( | 845 base::MessageLoop::current()->PostTask( |
835 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 846 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
885 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 896 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
886 DCHECK(!callback.is_null()); | 897 DCHECK(!callback.is_null()); |
887 | 898 |
888 if (offline_) { | 899 if (offline_) { |
889 base::MessageLoop::current()->PostTask( | 900 base::MessageLoop::current()->PostTask( |
890 FROM_HERE, | 901 FROM_HERE, |
891 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); | 902 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); |
892 return CancelCallback(); | 903 return CancelCallback(); |
893 } | 904 } |
894 | 905 |
895 // Content length should be zero, as we'll create an empty file first. The | 906 if (parent_resource_id != GetRootResourceId() && |
896 // content will be added in ResumeUpload(). | 907 !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( | 908 base::MessageLoop::current()->PostTask( |
905 FROM_HERE, | 909 FROM_HERE, |
906 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | 910 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
907 return CancelCallback(); | 911 return CancelCallback(); |
908 } | 912 } |
909 const GURL upload_url = GetUploadUrl(*new_entry); | 913 |
910 DCHECK(upload_url.is_valid()); | 914 GURL session_url = GetNewUploadSessionUrl(); |
915 upload_sessions_[session_url] = | |
916 UploadSession(content_type, content_length, | |
917 parent_resource_id, | |
918 "", // resource_id | |
919 "", // etag | |
920 title); | |
911 | 921 |
912 base::MessageLoop::current()->PostTask( | 922 base::MessageLoop::current()->PostTask( |
913 FROM_HERE, | 923 FROM_HERE, |
914 base::Bind(callback, HTTP_SUCCESS, | 924 base::Bind(callback, HTTP_SUCCESS, session_url)); |
915 net::AppendQueryParameter(upload_url, "mode", "newfile"))); | |
916 return CancelCallback(); | 925 return CancelCallback(); |
917 } | 926 } |
918 | 927 |
919 CancelCallback FakeDriveService::InitiateUploadExistingFile( | 928 CancelCallback FakeDriveService::InitiateUploadExistingFile( |
920 const base::FilePath& drive_file_path, | 929 const base::FilePath& drive_file_path, |
921 const std::string& content_type, | 930 const std::string& content_type, |
922 int64 content_length, | 931 int64 content_length, |
923 const std::string& resource_id, | 932 const std::string& resource_id, |
924 const std::string& etag, | 933 const std::string& etag, |
925 const InitiateUploadCallback& callback) { | 934 const InitiateUploadCallback& callback) { |
(...skipping 16 matching lines...) Expand all Loading... | |
942 } | 951 } |
943 | 952 |
944 std::string entry_etag; | 953 std::string entry_etag; |
945 entry->GetString("gd$etag", &entry_etag); | 954 entry->GetString("gd$etag", &entry_etag); |
946 if (!etag.empty() && etag != entry_etag) { | 955 if (!etag.empty() && etag != entry_etag) { |
947 base::MessageLoop::current()->PostTask( | 956 base::MessageLoop::current()->PostTask( |
948 FROM_HERE, | 957 FROM_HERE, |
949 base::Bind(callback, HTTP_PRECONDITION, GURL())); | 958 base::Bind(callback, HTTP_PRECONDITION, GURL())); |
950 return CancelCallback(); | 959 return CancelCallback(); |
951 } | 960 } |
952 entry->SetString("docs$size.$t", "0"); | |
953 | 961 |
954 const GURL upload_url = GetUploadUrl(*entry); | 962 GURL session_url = GetNewUploadSessionUrl(); |
955 DCHECK(upload_url.is_valid()); | 963 upload_sessions_[session_url] = |
964 UploadSession(content_type, content_length, | |
965 "", // parent_resource_id | |
966 resource_id, | |
967 entry_etag, | |
968 "" /* title */); | |
956 | 969 |
957 base::MessageLoop::current()->PostTask( | 970 base::MessageLoop::current()->PostTask( |
958 FROM_HERE, | 971 FROM_HERE, |
959 base::Bind(callback, HTTP_SUCCESS, | 972 base::Bind(callback, HTTP_SUCCESS, session_url)); |
960 net::AppendQueryParameter(upload_url, "mode", "existing"))); | |
961 return CancelCallback(); | 973 return CancelCallback(); |
962 } | 974 } |
963 | 975 |
964 CancelCallback FakeDriveService::GetUploadStatus( | 976 CancelCallback FakeDriveService::GetUploadStatus( |
965 const base::FilePath& drive_file_path, | 977 const base::FilePath& drive_file_path, |
966 const GURL& upload_url, | 978 const GURL& upload_url, |
967 int64 content_length, | 979 int64 content_length, |
968 const UploadRangeCallback& callback) { | 980 const UploadRangeCallback& callback) { |
969 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 981 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
970 DCHECK(!callback.is_null()); | 982 DCHECK(!callback.is_null()); |
971 return CancelCallback(); | 983 return CancelCallback(); |
972 } | 984 } |
973 | 985 |
974 CancelCallback FakeDriveService::ResumeUpload( | 986 CancelCallback FakeDriveService::ResumeUpload( |
975 const base::FilePath& drive_file_path, | 987 const base::FilePath& drive_file_path, |
976 const GURL& upload_url, | 988 const GURL& upload_url, |
977 int64 start_position, | 989 int64 start_position, |
978 int64 end_position, | 990 int64 end_position, |
979 int64 content_length, | 991 int64 content_length, |
980 const std::string& content_type, | 992 const std::string& content_type, |
981 const base::FilePath& local_file_path, | 993 const base::FilePath& local_file_path, |
982 const UploadRangeCallback& callback, | 994 const UploadRangeCallback& callback, |
983 const ProgressCallback& progress_callback) { | 995 const ProgressCallback& progress_callback) { |
984 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 996 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
985 DCHECK(!callback.is_null()); | 997 DCHECK(!callback.is_null()); |
986 | 998 |
987 scoped_ptr<ResourceEntry> result_entry; | |
988 | |
989 if (offline_) { | 999 if (offline_) { |
990 base::MessageLoop::current()->PostTask( | 1000 base::MessageLoop::current()->PostTask( |
991 FROM_HERE, | 1001 FROM_HERE, |
992 base::Bind(callback, | 1002 base::Bind(callback, |
993 UploadRangeResponse(GDATA_NO_CONNECTION, | 1003 UploadRangeResponse(GDATA_NO_CONNECTION, |
994 start_position, | 1004 start_position, |
995 end_position), | 1005 end_position), |
996 base::Passed(&result_entry))); | 1006 base::Passed(scoped_ptr<ResourceEntry>()))); |
997 return CancelCallback(); | 1007 return CancelCallback(); |
998 } | 1008 } |
999 | 1009 |
1000 DictionaryValue* entry = NULL; | 1010 if (!upload_sessions_.count(upload_url)) { |
1001 entry = FindEntryByUploadUrl(RemoveQueryParameter(upload_url)); | |
1002 if (!entry) { | |
1003 base::MessageLoop::current()->PostTask( | 1011 base::MessageLoop::current()->PostTask( |
1004 FROM_HERE, | 1012 FROM_HERE, |
1005 base::Bind(callback, | 1013 base::Bind(callback, |
1006 UploadRangeResponse(HTTP_NOT_FOUND, | 1014 UploadRangeResponse(HTTP_NOT_FOUND, |
1007 start_position, | 1015 start_position, |
1008 end_position), | 1016 end_position), |
1009 base::Passed(&result_entry))); | 1017 base::Passed(scoped_ptr<ResourceEntry>()))); |
1010 return CancelCallback(); | 1018 return CancelCallback(); |
1011 } | 1019 } |
1012 | 1020 |
1021 UploadSession* session = &upload_sessions_[upload_url]; | |
1022 | |
1013 // Chunks are required to be sent in such a ways that they fill from the start | 1023 // 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. | 1024 // of the not-yet-uploaded part with no gaps nor overlaps. |
1015 std::string current_size_string; | 1025 if (session->uploaded_size != start_position) { |
1016 int64 current_size; | |
1017 if (!entry->GetString("docs$size.$t", ¤t_size_string) || | |
1018 !base::StringToInt64(current_size_string, ¤t_size) || | |
1019 current_size != start_position) { | |
1020 base::MessageLoop::current()->PostTask( | 1026 base::MessageLoop::current()->PostTask( |
1021 FROM_HERE, | 1027 FROM_HERE, |
1022 base::Bind(callback, | 1028 base::Bind(callback, |
1023 UploadRangeResponse(HTTP_BAD_REQUEST, | 1029 UploadRangeResponse(HTTP_BAD_REQUEST, |
1024 start_position, | 1030 start_position, |
1025 end_position), | 1031 end_position), |
1026 base::Passed(&result_entry))); | 1032 base::Passed(scoped_ptr<ResourceEntry>()))); |
1027 return CancelCallback(); | 1033 return CancelCallback(); |
1028 } | 1034 } |
1029 | 1035 |
1030 entry->SetString("docs$size.$t", base::Int64ToString(end_position)); | |
1031 | |
1032 if (!progress_callback.is_null()) { | 1036 if (!progress_callback.is_null()) { |
1033 // In the real GDataWapi/Drive DriveService, progress is reported in | 1037 // In the real GDataWapi/Drive DriveService, progress is reported in |
1034 // nondeterministic timing. In this fake implementation, we choose to call | 1038 // nondeterministic timing. In this fake implementation, we choose to call |
1035 // it twice per one ResumeUpload. This is for making sure that client code | 1039 // 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 | 1040 // works fine even if the callback is invoked more than once; it is the |
1037 // crucial difference of the progress callback from others. | 1041 // crucial difference of the progress callback from others. |
1038 // Note that progress is notified in the relative offset in each chunk. | 1042 // Note that progress is notified in the relative offset in each chunk. |
1039 const int64 chunk_size = end_position - start_position; | 1043 const int64 chunk_size = end_position - start_position; |
1040 base::MessageLoop::current()->PostTask( | 1044 base::MessageLoop::current()->PostTask( |
1041 FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size)); | 1045 FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size)); |
1042 base::MessageLoop::current()->PostTask( | 1046 base::MessageLoop::current()->PostTask( |
1043 FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size)); | 1047 FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size)); |
1044 } | 1048 } |
1045 | 1049 |
1046 if (content_length != end_position) { | 1050 if (content_length != end_position) { |
1051 session->uploaded_size = end_position; | |
1047 base::MessageLoop::current()->PostTask( | 1052 base::MessageLoop::current()->PostTask( |
1048 FROM_HERE, | 1053 FROM_HERE, |
1049 base::Bind(callback, | 1054 base::Bind(callback, |
1050 UploadRangeResponse(HTTP_RESUME_INCOMPLETE, | 1055 UploadRangeResponse(HTTP_RESUME_INCOMPLETE, |
1051 start_position, | 1056 start_position, |
1052 end_position), | 1057 end_position), |
1053 base::Passed(&result_entry))); | 1058 base::Passed(scoped_ptr<ResourceEntry>()))); |
1054 return CancelCallback(); | 1059 return CancelCallback(); |
1055 } | 1060 } |
1056 | 1061 |
1057 AddNewChangestamp(entry); | 1062 std::string content_data; |
1058 result_entry = ResourceEntry::CreateFrom(*entry).Pass(); | 1063 if (!file_util::ReadFileToString(local_file_path, &content_data)) { |
1064 base::MessageLoop::current()->PostTask( | |
1065 FROM_HERE, | |
1066 base::Bind(callback, | |
1067 UploadRangeResponse(GDATA_FILE_ERROR, | |
1068 start_position, | |
1069 end_position), | |
1070 base::Passed(scoped_ptr<ResourceEntry>()))); | |
1071 return CancelCallback(); | |
1072 } | |
1073 session->uploaded_size = end_position; | |
1059 | 1074 |
1060 std::string upload_mode; | 1075 // |resource_id| is empty if the upload is for new file. |
1061 bool upload_mode_found = | 1076 if (session->resource_id.empty()) { |
1062 net::GetValueForKeyInQuery(upload_url, "mode", &upload_mode); | 1077 DCHECK(!session->parent_resource_id.empty()); |
1063 DCHECK(upload_mode_found && | 1078 DCHECK(!session->title.empty()); |
1064 (upload_mode == "newfile" || upload_mode == "existing")); | 1079 const DictionaryValue* new_entry = AddNewEntry( |
1080 session->content_type, | |
1081 content_data, | |
1082 session->parent_resource_id, | |
1083 session->title, | |
1084 false, // shared_with_me | |
1085 "file"); | |
1086 if (!new_entry) { | |
1087 base::MessageLoop::current()->PostTask( | |
hashimoto
2013/06/21 05:41:24
nit: The only difference between PostTask here and
tzik
2013/06/21 07:54:02
Did you mean a reduction like this?
https://codere
hashimoto
2013/06/21 08:05:32
Wow, I was only expecting the calls for HTTP_NOT_F
| |
1088 FROM_HERE, | |
1089 base::Bind(callback, | |
1090 UploadRangeResponse(HTTP_NOT_FOUND, | |
1091 start_position, | |
1092 end_position), | |
1093 base::Passed(scoped_ptr<ResourceEntry>()))); | |
1094 return CancelCallback(); | |
1095 } | |
1065 | 1096 |
1066 GDataErrorCode return_code = | 1097 base::MessageLoop::current()->PostTask( |
1067 upload_mode == "newfile" ? HTTP_CREATED : HTTP_SUCCESS; | 1098 FROM_HERE, |
1099 base::Bind(callback, | |
1100 UploadRangeResponse(HTTP_CREATED, | |
1101 start_position, | |
1102 end_position), | |
1103 base::Passed(ResourceEntry::CreateFrom(*new_entry)))); | |
1104 return CancelCallback(); | |
1105 } | |
1106 | |
1107 DictionaryValue* entry = FindEntryByResourceId(session->resource_id); | |
1108 if (!entry) { | |
1109 base::MessageLoop::current()->PostTask( | |
1110 FROM_HERE, | |
1111 base::Bind(callback, | |
1112 UploadRangeResponse(HTTP_NOT_FOUND, | |
1113 start_position, | |
1114 end_position), | |
1115 base::Passed(scoped_ptr<ResourceEntry>()))); | |
1116 return CancelCallback(); | |
1117 } | |
1118 | |
1119 std::string entry_etag; | |
1120 entry->GetString("gd$etag", &entry_etag); | |
1121 if (entry_etag.empty() || session->etag != entry_etag) { | |
1122 base::MessageLoop::current()->PostTask( | |
1123 FROM_HERE, | |
1124 base::Bind(callback, | |
1125 UploadRangeResponse(HTTP_PRECONDITION, | |
1126 start_position, | |
1127 end_position), | |
1128 base::Passed(scoped_ptr<ResourceEntry>()))); | |
1129 return CancelCallback(); | |
1130 } | |
1131 | |
1132 entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data)); | |
1133 entry->Set("test$data", | |
1134 base::BinaryValue::CreateWithCopiedBuffer( | |
1135 content_data.data(), content_data.size())); | |
1136 entry->SetString("docs$size.$t", base::Int64ToString(end_position)); | |
1137 AddNewChangestampAndETag(entry); | |
1068 | 1138 |
1069 base::MessageLoop::current()->PostTask( | 1139 base::MessageLoop::current()->PostTask( |
1070 FROM_HERE, | 1140 FROM_HERE, |
1071 base::Bind(callback, | 1141 base::Bind(callback, |
1072 UploadRangeResponse(return_code, | 1142 UploadRangeResponse(HTTP_SUCCESS, |
1073 start_position, | 1143 start_position, |
1074 end_position), | 1144 end_position), |
1075 base::Passed(&result_entry))); | 1145 base::Passed(ResourceEntry::CreateFrom(*entry)))); |
1076 return CancelCallback(); | 1146 return CancelCallback(); |
1077 } | 1147 } |
1078 | 1148 |
1079 CancelCallback FakeDriveService::AuthorizeApp( | 1149 CancelCallback FakeDriveService::AuthorizeApp( |
1080 const std::string& resource_id, | 1150 const std::string& resource_id, |
1081 const std::string& app_id, | 1151 const std::string& app_id, |
1082 const AuthorizeAppCallback& callback) { | 1152 const AuthorizeAppCallback& callback) { |
1083 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1084 DCHECK(!callback.is_null()); | 1154 DCHECK(!callback.is_null()); |
1085 return CancelCallback(); | 1155 return CancelCallback(); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1207 entry->GetString("content.src", ¤t_content_url) && | 1277 entry->GetString("content.src", ¤t_content_url) && |
1208 content_url == GURL(current_content_url)) { | 1278 content_url == GURL(current_content_url)) { |
1209 return entry; | 1279 return entry; |
1210 } | 1280 } |
1211 } | 1281 } |
1212 } | 1282 } |
1213 | 1283 |
1214 return NULL; | 1284 return NULL; |
1215 } | 1285 } |
1216 | 1286 |
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() { | 1287 std::string FakeDriveService::GetNewResourceId() { |
1252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1253 | 1289 |
1254 ++resource_id_count_; | 1290 ++resource_id_count_; |
1255 return base::StringPrintf("resource_id_%d", resource_id_count_); | 1291 return base::StringPrintf("resource_id_%d", resource_id_count_); |
1256 } | 1292 } |
1257 | 1293 |
1258 void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) { | 1294 void FakeDriveService::AddNewChangestampAndETag(base::DictionaryValue* entry) { |
1259 ++largest_changestamp_; | 1295 ++largest_changestamp_; |
1260 entry->SetString("docs$changestamp.value", | 1296 entry->SetString("docs$changestamp.value", |
1261 base::Int64ToString(largest_changestamp_)); | 1297 base::Int64ToString(largest_changestamp_)); |
1298 entry->SetString("gd$etag", | |
1299 "etag_" + base::Int64ToString(largest_changestamp_)); | |
1262 } | 1300 } |
1263 | 1301 |
1264 const base::DictionaryValue* FakeDriveService::AddNewEntry( | 1302 const base::DictionaryValue* FakeDriveService::AddNewEntry( |
1265 const std::string& content_type, | 1303 const std::string& content_type, |
1266 const std::string& content_data, | 1304 const std::string& content_data, |
1267 const std::string& parent_resource_id, | 1305 const std::string& parent_resource_id, |
1268 const std::string& title, | 1306 const std::string& title, |
1269 bool shared_with_me, | 1307 bool shared_with_me, |
1270 const std::string& entry_kind) { | 1308 const std::string& entry_kind) { |
1271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 11 matching lines...) Expand all Loading... | |
1283 new_entry->SetString("gd$resourceId.$t", resource_id); | 1321 new_entry->SetString("gd$resourceId.$t", resource_id); |
1284 new_entry->SetString("title.$t", title); | 1322 new_entry->SetString("title.$t", title); |
1285 new_entry->SetString("docs$filename", title); | 1323 new_entry->SetString("docs$filename", title); |
1286 // Set the contents, size and MD5 for a file. | 1324 // Set the contents, size and MD5 for a file. |
1287 if (entry_kind == "file") { | 1325 if (entry_kind == "file") { |
1288 new_entry->Set("test$data", | 1326 new_entry->Set("test$data", |
1289 base::BinaryValue::CreateWithCopiedBuffer( | 1327 base::BinaryValue::CreateWithCopiedBuffer( |
1290 content_data.c_str(), content_data.size())); | 1328 content_data.c_str(), content_data.size())); |
1291 new_entry->SetString("docs$size.$t", | 1329 new_entry->SetString("docs$size.$t", |
1292 base::Int64ToString(content_data.size())); | 1330 base::Int64ToString(content_data.size())); |
1293 // TODO(satorux): Set the correct MD5 here. | |
1294 new_entry->SetString("docs$md5Checksum.$t", | 1331 new_entry->SetString("docs$md5Checksum.$t", |
1295 "3b4385ebefec6e743574c76bbd0575de"); | 1332 base::MD5String(content_data)); |
1296 } | 1333 } |
1297 | 1334 |
1298 // Add "category" which sets the resource type to |entry_kind|. | 1335 // Add "category" which sets the resource type to |entry_kind|. |
1299 base::ListValue* categories = new base::ListValue; | 1336 base::ListValue* categories = new base::ListValue; |
1300 base::DictionaryValue* category = new base::DictionaryValue; | 1337 base::DictionaryValue* category = new base::DictionaryValue; |
1301 category->SetString("scheme", "http://schemas.google.com/g/2005#kind"); | 1338 category->SetString("scheme", "http://schemas.google.com/g/2005#kind"); |
1302 category->SetString("term", "http://schemas.google.com/docs/2007#" + | 1339 category->SetString("term", "http://schemas.google.com/docs/2007#" + |
1303 entry_kind); | 1340 entry_kind); |
1304 categories->Append(category); | 1341 categories->Append(category); |
1305 new_entry->Set("category", categories); | 1342 new_entry->Set("category", categories); |
(...skipping 28 matching lines...) Expand all Loading... | |
1334 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id); | 1371 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id); |
1335 edit_link->SetString("rel", "edit"); | 1372 edit_link->SetString("rel", "edit"); |
1336 links->Append(edit_link); | 1373 links->Append(edit_link); |
1337 | 1374 |
1338 base::DictionaryValue* upload_link = new base::DictionaryValue; | 1375 base::DictionaryValue* upload_link = new base::DictionaryValue; |
1339 upload_link->SetString("href", upload_url.spec()); | 1376 upload_link->SetString("href", upload_url.spec()); |
1340 upload_link->SetString("rel", kUploadUrlRel); | 1377 upload_link->SetString("rel", kUploadUrlRel); |
1341 links->Append(upload_link); | 1378 links->Append(upload_link); |
1342 new_entry->Set("link", links); | 1379 new_entry->Set("link", links); |
1343 | 1380 |
1344 AddNewChangestamp(new_entry.get()); | 1381 AddNewChangestampAndETag(new_entry.get()); |
1345 | 1382 |
1346 base::Time published_date = | 1383 base::Time published_date = |
1347 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); | 1384 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); |
1348 new_entry->SetString("published.$t", | 1385 new_entry->SetString("published.$t", |
1349 util::FormatTimeAsString(published_date)); | 1386 util::FormatTimeAsString(published_date)); |
1350 | 1387 |
1351 // If there are no entries, prepare an empty entry to add. | 1388 // If there are no entries, prepare an empty entry to add. |
1352 if (!resource_list_value_->HasKey("entry")) | 1389 if (!resource_list_value_->HasKey("entry")) |
1353 resource_list_value_->Set("entry", new ListValue); | 1390 resource_list_value_->Set("entry", new ListValue); |
1354 | 1391 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1470 | 1507 |
1471 if (load_counter) | 1508 if (load_counter) |
1472 *load_counter += 1; | 1509 *load_counter += 1; |
1473 base::MessageLoop::current()->PostTask( | 1510 base::MessageLoop::current()->PostTask( |
1474 FROM_HERE, | 1511 FROM_HERE, |
1475 base::Bind(callback, | 1512 base::Bind(callback, |
1476 HTTP_SUCCESS, | 1513 HTTP_SUCCESS, |
1477 base::Passed(&resource_list))); | 1514 base::Passed(&resource_list))); |
1478 } | 1515 } |
1479 | 1516 |
1517 GURL FakeDriveService::GetNewUploadSessionUrl() { | |
1518 return GURL("https://upload_session_url/" + | |
1519 base::Int64ToString(next_upload_sequence_number_++)); | |
1520 } | |
1521 | |
1480 } // namespace drive | 1522 } // namespace drive |
OLD | NEW |