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/google_apis/fake_drive_service.h" | 5 #include "chrome/browser/google_apis/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" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
13 #include "base/string_split.h" | 13 #include "base/string_split.h" |
14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
15 #include "base/stringprintf.h" | 15 #include "base/stringprintf.h" |
16 #include "base/strings/string_tokenizer.h" | 16 #include "base/strings/string_tokenizer.h" |
17 #include "base/utf_string_conversions.h" | 17 #include "base/utf_string_conversions.h" |
18 #include "chrome/browser/google_apis/drive_api_parser.h" | 18 #include "chrome/browser/google_apis/drive_api_parser.h" |
19 #include "chrome/browser/google_apis/gdata_wapi_parser.h" | 19 #include "chrome/browser/google_apis/gdata_wapi_parser.h" |
20 #include "chrome/browser/google_apis/test_util.h" | 20 #include "chrome/browser/google_apis/test_util.h" |
21 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
22 #include "net/base/escape.h" | 22 #include "net/base/escape.h" |
23 | 23 |
24 using content::BrowserThread; | 24 using content::BrowserThread; |
25 | 25 |
26 namespace google_apis { | 26 namespace google_apis { |
27 namespace { | 27 namespace { |
| 28 |
| 29 // Rel property of upload link in the entries dictionary value. |
| 30 const char kUploadUrlRel[] = |
| 31 "http://schemas.google.com/g/2005#resumable-create-media"; |
| 32 |
28 // Returns true if a resource entry matches with the search query. | 33 // Returns true if a resource entry matches with the search query. |
29 // Supports queries consist of following format. | 34 // Supports queries consist of following format. |
30 // - Phrases quoted by double/single quotes | 35 // - Phrases quoted by double/single quotes |
31 // - AND search for multiple words/phrases segmented by space | 36 // - AND search for multiple words/phrases segmented by space |
32 // - Limited attribute search. Only "title:" is supported. | 37 // - Limited attribute search. Only "title:" is supported. |
33 bool EntryMatchWithQuery(const ResourceEntry& entry, | 38 bool EntryMatchWithQuery(const ResourceEntry& entry, |
34 const std::string& query) { | 39 const std::string& query) { |
35 base::StringTokenizer tokenizer(query, " "); | 40 base::StringTokenizer tokenizer(query, " "); |
36 tokenizer.set_quote_chars("\"'"); | 41 tokenizer.set_quote_chars("\"'"); |
37 while (tokenizer.GetNext()) { | 42 while (tokenizer.GetNext()) { |
(...skipping 732 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 MessageLoop::current()->PostTask( | 775 MessageLoop::current()->PostTask( |
771 FROM_HERE, | 776 FROM_HERE, |
772 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 777 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
773 } | 778 } |
774 | 779 |
775 void FakeDriveService::InitiateUpload( | 780 void FakeDriveService::InitiateUpload( |
776 const InitiateUploadParams& params, | 781 const InitiateUploadParams& params, |
777 const InitiateUploadCallback& callback) { | 782 const InitiateUploadCallback& callback) { |
778 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 783 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
779 DCHECK(!callback.is_null()); | 784 DCHECK(!callback.is_null()); |
780 } | |
781 | 785 |
782 void FakeDriveService::ResumeUpload(const ResumeUploadParams& params, | 786 if (offline_) { |
783 const UploadRangeCallback& callback) { | 787 MessageLoop::current()->PostTask( |
784 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 788 FROM_HERE, |
785 DCHECK(!callback.is_null()); | 789 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); |
| 790 return; |
| 791 } |
| 792 |
| 793 DictionaryValue* entry = FindEntryByUploadUrl(params.upload_location); |
| 794 if (!entry) { |
| 795 MessageLoop::current()->PostTask( |
| 796 FROM_HERE, |
| 797 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
| 798 return; |
| 799 } |
| 800 |
| 801 if (params.upload_mode == UPLOAD_EXISTING_FILE) { |
| 802 std::string etag; |
| 803 entry->GetString("gd$etag", &etag); |
| 804 if (params.etag != etag) { |
| 805 MessageLoop::current()->PostTask( |
| 806 FROM_HERE, |
| 807 base::Bind(callback, HTTP_PRECONDITION, GURL())); |
| 808 return; |
| 809 } |
| 810 MessageLoop::current()->PostTask( |
| 811 FROM_HERE, |
| 812 base::Bind(callback, HTTP_SUCCESS, params.upload_location)); |
| 813 return; |
| 814 } |
| 815 |
| 816 // If the title was set, the upload_location is the location of the parent |
| 817 // directory of the file that will be uploaded. The file does not yet exist |
| 818 // and it must be created. Its title will be the passed title param. |
| 819 std::string parent_resource_id; |
| 820 entry->GetString("gd$resourceId.$t", &parent_resource_id); |
| 821 |
| 822 std::string resource_id = GetNewResourceId(); |
| 823 GURL upload_url = GURL("https://xxx/upload/" + resource_id); |
| 824 |
| 825 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue); |
| 826 // Set the resource ID and the title |
| 827 new_entry->SetString("gd$resourceId.$t", resource_id); |
| 828 new_entry->SetString("title.$t", params.title); |
| 829 new_entry->SetString("docs$filename", params.title); |
| 830 new_entry->SetString("docs$size", "0"); |
| 831 new_entry->SetString("docs$md5Checksum.$t", |
| 832 "3b4385ebefec6e743574c76bbd0575de"); |
| 833 |
| 834 // Add "category" which sets the resource type to file. |
| 835 base::ListValue* categories = new base::ListValue; |
| 836 base::DictionaryValue* category = new base::DictionaryValue; |
| 837 category->SetString("label", "test/foo"); |
| 838 category->SetString("scheme", "http://schemas.google.com/g/2005#kind"); |
| 839 category->SetString("term", "http://schemas.google.com/docs/2007#file"); |
| 840 categories->Append(category); |
| 841 new_entry->Set("category", categories); |
| 842 |
| 843 // Add "content" which sets the content URL. |
| 844 base::DictionaryValue* content = new base::DictionaryValue; |
| 845 content->SetString("src", "https://xxx/content/" + resource_id); |
| 846 content->SetString("type", params.content_type); |
| 847 new_entry->Set("content", content); |
| 848 |
| 849 // Add "link" which sets the parent URL, the edit URL and the upload URL. |
| 850 base::ListValue* links = new base::ListValue; |
| 851 if (parent_resource_id != GetRootResourceId()) { |
| 852 base::DictionaryValue* parent_link = new base::DictionaryValue; |
| 853 parent_link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); |
| 854 parent_link->SetString("rel", |
| 855 "http://schemas.google.com/docs/2007#parent"); |
| 856 links->Append(parent_link); |
| 857 } |
| 858 |
| 859 base::DictionaryValue* edit_link = new base::DictionaryValue; |
| 860 edit_link->SetString("href", "https://xxx/edit/" + resource_id); |
| 861 edit_link->SetString("rel", "edit"); |
| 862 links->Append(edit_link); |
| 863 |
| 864 base::DictionaryValue* upload_link = new base::DictionaryValue; |
| 865 upload_link->SetString("href", upload_url.spec()); |
| 866 upload_link->SetString("rel", kUploadUrlRel); |
| 867 links->Append(upload_link); |
| 868 new_entry->Set("link", links); |
| 869 |
| 870 AddNewChangestamp(new_entry.get()); |
| 871 |
| 872 base::DictionaryValue* resource_list_dict = NULL; |
| 873 base::ListValue* entries = NULL; |
| 874 if (!resource_list_value_->GetAsDictionary(&resource_list_dict)) { |
| 875 MessageLoop::current()->PostTask( |
| 876 FROM_HERE, |
| 877 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
| 878 return; |
| 879 } |
| 880 |
| 881 // If there are no entries, prepare an empty entry to add. |
| 882 if (!resource_list_dict->HasKey("entry")) |
| 883 resource_list_dict->Set("entry", new ListValue); |
| 884 |
| 885 if (resource_list_dict->GetList("entry", &entries)) |
| 886 entries->Append(new_entry.release()); |
| 887 |
| 888 MessageLoop::current()->PostTask( |
| 889 FROM_HERE, |
| 890 base::Bind(callback, HTTP_SUCCESS, upload_url)); |
786 } | 891 } |
787 | 892 |
788 void FakeDriveService::GetUploadStatus( | 893 void FakeDriveService::GetUploadStatus( |
789 UploadMode upload_mode, | 894 UploadMode upload_mode, |
790 const FilePath& drive_file_path, | 895 const FilePath& drive_file_path, |
791 const GURL& upload_url, | 896 const GURL& upload_url, |
792 int64 content_length, | 897 int64 content_length, |
793 const UploadRangeCallback& callback) { | 898 const UploadRangeCallback& callback) { |
794 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
795 DCHECK(!callback.is_null()); | 900 DCHECK(!callback.is_null()); |
796 } | 901 } |
797 | 902 |
| 903 void FakeDriveService::ResumeUpload(const ResumeUploadParams& params, |
| 904 const UploadRangeCallback& callback) { |
| 905 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 906 DCHECK(!callback.is_null()); |
| 907 |
| 908 scoped_ptr<ResourceEntry> result_entry; |
| 909 |
| 910 if (offline_) { |
| 911 MessageLoop::current()->PostTask( |
| 912 FROM_HERE, |
| 913 base::Bind(callback, |
| 914 UploadRangeResponse(GDATA_NO_CONNECTION, |
| 915 params.start_position, |
| 916 params.end_position), |
| 917 base::Passed(&result_entry))); |
| 918 return; |
| 919 } |
| 920 |
| 921 DictionaryValue* entry = NULL; |
| 922 entry = FindEntryByUploadUrl(params.upload_location); |
| 923 if (!entry) { |
| 924 MessageLoop::current()->PostTask( |
| 925 FROM_HERE, |
| 926 base::Bind(callback, |
| 927 UploadRangeResponse(HTTP_NOT_FOUND, |
| 928 params.start_position, |
| 929 params.end_position), |
| 930 base::Passed(&result_entry))); |
| 931 return; |
| 932 } |
| 933 |
| 934 entry->SetString("docs$size.$t", base::Int64ToString(params.end_position)); |
| 935 |
| 936 if (params.content_length != params.end_position) { |
| 937 MessageLoop::current()->PostTask( |
| 938 FROM_HERE, |
| 939 base::Bind(callback, |
| 940 UploadRangeResponse(HTTP_RESUME_INCOMPLETE, |
| 941 params.start_position, |
| 942 params.end_position), |
| 943 base::Passed(&result_entry))); |
| 944 return; |
| 945 } |
| 946 |
| 947 result_entry = ResourceEntry::CreateFrom(*entry).Pass(); |
| 948 |
| 949 GDataErrorCode return_code = HTTP_SUCCESS; |
| 950 if (params.upload_mode == UPLOAD_NEW_FILE) |
| 951 return_code = HTTP_CREATED; |
| 952 |
| 953 MessageLoop::current()->PostTask( |
| 954 FROM_HERE, |
| 955 base::Bind(callback, |
| 956 UploadRangeResponse(return_code, |
| 957 params.start_position, |
| 958 params.end_position), |
| 959 base::Passed(&result_entry))); |
| 960 } |
| 961 |
798 void FakeDriveService::AuthorizeApp(const GURL& edit_url, | 962 void FakeDriveService::AuthorizeApp(const GURL& edit_url, |
799 const std::string& app_id, | 963 const std::string& app_id, |
800 const AuthorizeAppCallback& callback) { | 964 const AuthorizeAppCallback& callback) { |
801 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 965 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
802 DCHECK(!callback.is_null()); | 966 DCHECK(!callback.is_null()); |
803 } | 967 } |
804 | 968 |
805 base::DictionaryValue* FakeDriveService::FindEntryByResourceId( | 969 base::DictionaryValue* FakeDriveService::FindEntryByResourceId( |
806 const std::string& resource_id) { | 970 const std::string& resource_id) { |
807 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 971 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 entry->GetString("content.src", ¤t_content_url) && | 1005 entry->GetString("content.src", ¤t_content_url) && |
842 content_url == GURL(current_content_url)) { | 1006 content_url == GURL(current_content_url)) { |
843 return entry; | 1007 return entry; |
844 } | 1008 } |
845 } | 1009 } |
846 } | 1010 } |
847 | 1011 |
848 return NULL; | 1012 return NULL; |
849 } | 1013 } |
850 | 1014 |
| 1015 base::DictionaryValue* FakeDriveService::FindEntryByUploadUrl( |
| 1016 const GURL& upload_url) { |
| 1017 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1018 |
| 1019 base::DictionaryValue* resource_list_dict = NULL; |
| 1020 base::ListValue* entries = NULL; |
| 1021 // Go through entries and return the one that matches |upload_url|. |
| 1022 if (resource_list_value_->GetAsDictionary(&resource_list_dict) && |
| 1023 resource_list_dict->GetList("entry", &entries)) { |
| 1024 for (size_t i = 0; i < entries->GetSize(); ++i) { |
| 1025 base::DictionaryValue* entry = NULL; |
| 1026 base::ListValue* links = NULL; |
| 1027 if (entries->GetDictionary(i, &entry) && |
| 1028 entry->GetList("link", &links) && |
| 1029 links) { |
| 1030 for (size_t link_index = 0; |
| 1031 link_index < links->GetSize(); |
| 1032 ++link_index) { |
| 1033 base::DictionaryValue* link = NULL; |
| 1034 std::string rel; |
| 1035 std::string found_upload_url; |
| 1036 if (links->GetDictionary(link_index, &link) && |
| 1037 link && link->GetString("rel", &rel) && |
| 1038 rel == kUploadUrlRel && |
| 1039 link->GetString("href", &found_upload_url) && |
| 1040 GURL(found_upload_url) == upload_url) { |
| 1041 return entry; |
| 1042 } |
| 1043 } |
| 1044 } |
| 1045 } |
| 1046 } |
| 1047 |
| 1048 return NULL; |
| 1049 } |
| 1050 |
851 std::string FakeDriveService::GetNewResourceId() { | 1051 std::string FakeDriveService::GetNewResourceId() { |
852 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1052 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
853 | 1053 |
854 ++resource_id_count_; | 1054 ++resource_id_count_; |
855 return base::StringPrintf("resource_id_%d", resource_id_count_); | 1055 return base::StringPrintf("resource_id_%d", resource_id_count_); |
856 } | 1056 } |
857 | 1057 |
858 void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) { | 1058 void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) { |
859 ++largest_changestamp_; | 1059 ++largest_changestamp_; |
860 entry->SetString("docs$changestamp.value", | 1060 entry->SetString("docs$changestamp.value", |
861 base::Int64ToString(largest_changestamp_)); | 1061 base::Int64ToString(largest_changestamp_)); |
862 } | 1062 } |
863 | 1063 |
864 } // namespace google_apis | 1064 } // namespace google_apis |
OLD | NEW |