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 "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/file_path.h" | 6 #include "base/file_path.h" |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
9 #include "base/message_loop_proxy.h" | 9 #include "base/message_loop_proxy.h" |
10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
11 #include "base/string_split.h" | |
11 #include "base/stringprintf.h" | 12 #include "base/stringprintf.h" |
12 #include "chrome/browser/google_apis/gdata_wapi_operations.h" | 13 #include "chrome/browser/google_apis/gdata_wapi_operations.h" |
13 #include "chrome/browser/google_apis/gdata_wapi_parser.h" | 14 #include "chrome/browser/google_apis/gdata_wapi_parser.h" |
14 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h" | 15 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h" |
15 #include "chrome/browser/google_apis/operation_registry.h" | 16 #include "chrome/browser/google_apis/operation_registry.h" |
16 #include "chrome/browser/google_apis/test_server/http_server.h" | 17 #include "chrome/browser/google_apis/test_server/http_server.h" |
17 #include "chrome/browser/google_apis/test_util.h" | 18 #include "chrome/browser/google_apis/test_util.h" |
18 #include "chrome/browser/profiles/profile.h" | 19 #include "chrome/browser/profiles/profile.h" |
19 #include "chrome/test/base/testing_browser_process.h" | 20 #include "chrome/test/base/testing_browser_process.h" |
20 #include "chrome/test/base/testing_profile.h" | 21 #include "chrome/test/base/testing_profile.h" |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
124 bool RemovePrefix(const std::string& input, | 125 bool RemovePrefix(const std::string& input, |
125 const std::string& prefix, | 126 const std::string& prefix, |
126 std::string* output) { | 127 std::string* output) { |
127 if (!StartsWithASCII(input, prefix, true /* case sensitive */)) | 128 if (!StartsWithASCII(input, prefix, true /* case sensitive */)) |
128 return false; | 129 return false; |
129 | 130 |
130 *output = input.substr(prefix.size()); | 131 *output = input.substr(prefix.size()); |
131 return true; | 132 return true; |
132 } | 133 } |
133 | 134 |
135 // Parses a value of Content-Range header, which looks like | |
136 // "bytes <start_position>-<end_position>/<length>". | |
137 // Returns true on success. | |
138 bool ParseContentRangeHeader(const std::string& value, | |
139 int64* start_position, | |
140 int64* end_position, | |
141 int64* length) { | |
142 DCHECK(start_position); | |
143 DCHECK(end_position); | |
144 DCHECK(length); | |
145 | |
146 std::string remaining; | |
147 if (!RemovePrefix(value, "bytes ", &remaining)) | |
148 return false; | |
149 | |
150 std::vector<std::string> parts; | |
151 base::SplitString(remaining, '/', &parts); | |
152 if (parts.size() != 2U) | |
153 return false; | |
154 | |
155 const std::string range = parts[0]; | |
156 if (!base::StringToInt64(parts[1], length)) | |
157 return false; | |
158 | |
159 parts.clear(); | |
160 base::SplitString(range, '-', &parts); | |
161 if (parts.size() != 2U) | |
162 return false; | |
163 | |
164 return (base::StringToInt64(parts[0], start_position) && | |
165 base::StringToInt64(parts[1], end_position)); | |
166 } | |
167 | |
134 // This class sets a request context getter for testing in | 168 // This class sets a request context getter for testing in |
135 // |testing_browser_process| and then clears the state when an instance of it | 169 // |testing_browser_process| and then clears the state when an instance of it |
136 // goes out of scope. | 170 // goes out of scope. |
137 class ScopedRequestContextGetterForTesting { | 171 class ScopedRequestContextGetterForTesting { |
138 public: | 172 public: |
139 ScopedRequestContextGetterForTesting( | 173 ScopedRequestContextGetterForTesting( |
140 TestingBrowserProcess* testing_browser_process) | 174 TestingBrowserProcess* testing_browser_process) |
141 : testing_browser_process_(testing_browser_process) { | 175 : testing_browser_process_(testing_browser_process) { |
142 context_getter_ = new net::TestURLRequestContextGetter( | 176 context_getter_ = new net::TestURLRequestContextGetter( |
143 content::BrowserThread::GetMessageLoopProxyForThread( | 177 content::BrowserThread::GetMessageLoopProxyForThread( |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
322 scoped_ptr<test_server::HttpResponse> HandleUploadRequest( | 356 scoped_ptr<test_server::HttpResponse> HandleUploadRequest( |
323 const test_server::HttpRequest& request) { | 357 const test_server::HttpRequest& request) { |
324 http_request_ = request; | 358 http_request_ = request; |
325 | 359 |
326 const GURL absolute_url = test_server_.GetURL(request.relative_url); | 360 const GURL absolute_url = test_server_.GetURL(request.relative_url); |
327 if (absolute_url.path() != "/upload_url") | 361 if (absolute_url.path() != "/upload_url") |
328 return scoped_ptr<test_server::HttpResponse>(); | 362 return scoped_ptr<test_server::HttpResponse>(); |
329 | 363 |
330 // TODO(satorux): We should create a correct entry for the uploaded file, | 364 // TODO(satorux): We should create a correct entry for the uploaded file, |
331 // but for now, just return entry.xml. | 365 // but for now, just return entry.xml. |
332 return CreateHttpResponseFromFile( | 366 scoped_ptr<test_server::HttpResponse> response = |
333 test_util::GetTestFilePath("gdata/entry.xml")); | 367 CreateHttpResponseFromFile( |
368 test_util::GetTestFilePath("gdata/entry.xml")); | |
369 | |
370 // Check if the Content-Range header is present. This must be present if | |
371 // the request body is not empty. | |
372 if (!request.content.empty()) { | |
373 std::map<std::string, std::string>::const_iterator iter = | |
374 request.headers.find("Content-Range"); | |
375 if (iter == request.headers.end()) | |
376 return scoped_ptr<test_server::HttpResponse>(); | |
377 int64 start_position = 0; | |
378 int64 end_position = 0; | |
379 int64 length = 0; | |
380 if (!ParseContentRangeHeader(iter->second, | |
381 &start_position, | |
382 &end_position, | |
383 &length)) { | |
384 return scoped_ptr<test_server::HttpResponse>(); | |
385 } | |
386 | |
387 // Add Range header to the response, based on the values of | |
388 // Content-Range header in the request. | |
389 response->AddCustomHeader( | |
390 "Range", | |
391 "bytes=" + | |
392 base::Int64ToString(start_position) + "-" + | |
393 base::Int64ToString(end_position)); | |
394 | |
395 // Change the response code if this is not the end of an upload. | |
396 if (end_position + 1 < length) | |
397 response->set_code(test_server::RESUME_INCOMPLETE); | |
398 } | |
399 | |
400 return response.Pass(); | |
334 } | 401 } |
335 | 402 |
336 MessageLoopForUI message_loop_; | 403 MessageLoopForUI message_loop_; |
337 content::TestBrowserThread ui_thread_; | 404 content::TestBrowserThread ui_thread_; |
338 content::TestBrowserThread file_thread_; | 405 content::TestBrowserThread file_thread_; |
339 content::TestBrowserThread io_thread_; | 406 content::TestBrowserThread io_thread_; |
340 test_server::HttpServer test_server_; | 407 test_server::HttpServer test_server_; |
341 scoped_ptr<TestingProfile> profile_; | 408 scoped_ptr<TestingProfile> profile_; |
342 OperationRegistry operation_registry_; | 409 OperationRegistry operation_registry_; |
343 scoped_ptr<GDataWapiUrlGenerator> url_generator_; | 410 scoped_ptr<GDataWapiUrlGenerator> url_generator_; |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
855 new ResumeUploadOperation( | 922 new ResumeUploadOperation( |
856 &operation_registry_, | 923 &operation_registry_, |
857 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, | 924 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, |
858 &response, | 925 &response, |
859 &new_entry), | 926 &new_entry), |
860 resume_params); | 927 resume_params); |
861 | 928 |
862 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); | 929 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); |
863 MessageLoop::current()->Run(); | 930 MessageLoop::current()->Run(); |
864 | 931 |
865 EXPECT_EQ(HTTP_SUCCESS, result_code); | |
866 // METHOD_PUT should be used to upload data. | 932 // METHOD_PUT should be used to upload data. |
867 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); | 933 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); |
868 // Request should go to the upload URL. | 934 // Request should go to the upload URL. |
869 EXPECT_EQ(upload_url.path(), http_request_.relative_url); | 935 EXPECT_EQ(upload_url.path(), http_request_.relative_url); |
870 // Content-Range header should be added. | 936 // Content-Range header should be added. |
871 EXPECT_EQ("bytes 0-" + | 937 EXPECT_EQ("bytes 0-" + |
872 base::Int64ToString(kUploadContent.size() -1) + "/" + | 938 base::Int64ToString(kUploadContent.size() -1) + "/" + |
873 base::Int64ToString(kUploadContent.size()), | 939 base::Int64ToString(kUploadContent.size()), |
874 http_request_.headers["Content-Range"]); | 940 http_request_.headers["Content-Range"]); |
875 // The upload content should be set in the HTTP request. | 941 // The upload content should be set in the HTTP request. |
876 EXPECT_TRUE(http_request_.has_content); | 942 EXPECT_TRUE(http_request_.has_content); |
877 EXPECT_EQ(kUploadContent, http_request_.content); | 943 EXPECT_EQ(kUploadContent, http_request_.content); |
944 | |
945 // Check the response. | |
946 EXPECT_EQ(HTTP_SUCCESS, response.code); | |
947 // The start and end positions should be set to -1, if an upload is complete. | |
948 EXPECT_EQ(-1, response.start_range_received); | |
949 EXPECT_EQ(-1, response.end_range_received); | |
878 } | 950 } |
879 | 951 |
880 // This test exercises InitiateUploadOperation and ResumeUploadOperation for | 952 // This test exercises InitiateUploadOperation and ResumeUploadOperation for |
953 // a scenario of uploading a new *large* file, which requires mutiple requests | |
954 // of ResumeUploadOperation. | |
955 TEST_F(GDataWapiOperationsTest, UploadNewLargeFile) { | |
956 const size_t kMaxNumBytes = 10; | |
957 // This is big enough to cause multiple requests of ResumeUploadOperation | |
958 // as we are gonig to send at most kMaxNumBytes at a time. | |
959 const std::string kUploadContent(kMaxNumBytes + 1, 'a'); | |
960 GDataErrorCode result_code = GDATA_OTHER_ERROR; | |
961 GURL upload_url; | |
962 | |
963 // 1) Get the upload URL for uploading a new file. | |
964 InitiateUploadParams initiate_params( | |
965 UPLOAD_NEW_FILE, | |
966 "New file", | |
967 "text/plain", | |
968 kUploadContent.size(), | |
969 test_server_.GetURL("/feeds/upload/create-session/default/private/full"), | |
970 FilePath::FromUTF8Unsafe("drive/newfile.txt")); | |
971 | |
972 InitiateUploadOperation* initiate_operation = | |
973 new InitiateUploadOperation( | |
974 &operation_registry_, | |
975 base::Bind(&CopyResultFromInitiateUploadCallbackAndQuit, | |
976 &result_code, | |
977 &upload_url), | |
978 initiate_params); | |
979 | |
980 initiate_operation->Start(kTestGDataAuthToken, kTestUserAgent); | |
981 MessageLoop::current()->Run(); | |
982 | |
983 EXPECT_EQ(HTTP_SUCCESS, result_code); | |
984 EXPECT_EQ(test_server_.GetURL("/upload_url"), upload_url); | |
985 EXPECT_EQ(test_server::METHOD_POST, http_request_.method); | |
986 // convert=false should be passed as files should be uploaded as-is. | |
987 EXPECT_EQ("/feeds/upload/create-session/default/private/full?convert=false", | |
988 http_request_.relative_url); | |
989 EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]); | |
990 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]); | |
991 EXPECT_EQ(base::Int64ToString(kUploadContent.size()), | |
992 http_request_.headers["X-Upload-Content-Length"]); | |
993 | |
994 EXPECT_TRUE(http_request_.has_content); | |
995 EXPECT_EQ("<?xml version=\"1.0\"?>\n" | |
996 "<entry xmlns=\"http://www.w3.org/2005/Atom\" " | |
997 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n" | |
998 " <title>New file</title>\n" | |
999 "</entry>\n", | |
1000 http_request_.content); | |
1001 | |
1002 // 2) Upload the content to the upload URL with multiple requests. | |
1003 size_t num_bytes_consumed = 0; | |
1004 for (size_t start_position = 0; start_position < kUploadContent.size(); | |
1005 start_position += kMaxNumBytes) { | |
1006 SCOPED_TRACE(testing::Message("start_position: ") << start_position); | |
1007 | |
1008 // The payload is at most kMaxNumBytes. | |
1009 const size_t remaining_size = kUploadContent.size() - start_position; | |
1010 const std::string payload = kUploadContent.substr( | |
1011 start_position, std::min(kMaxNumBytes, remaining_size)); | |
1012 num_bytes_consumed += payload.size(); | |
1013 // The end position is inclusive, hence -1. | |
1014 const size_t end_position = start_position + payload.size() - 1; | |
1015 | |
1016 scoped_refptr<net::IOBuffer> buffer = new net::StringIOBuffer(payload); | |
1017 ResumeUploadParams resume_params( | |
1018 UPLOAD_NEW_FILE, | |
1019 start_position, // start_range | |
1020 end_position, // end_range | |
1021 kUploadContent.size(), // content_length, | |
1022 "text/plain", // content_type | |
1023 buffer, | |
1024 upload_url, | |
1025 FilePath::FromUTF8Unsafe("drive/newfile.txt")); | |
1026 | |
1027 ResumeUploadResponse response; | |
1028 scoped_ptr<DocumentEntry> new_entry; | |
1029 | |
1030 ResumeUploadOperation* resume_operation = | |
1031 new ResumeUploadOperation( | |
1032 &operation_registry_, | |
1033 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, | |
1034 &response, | |
1035 &new_entry), | |
1036 resume_params); | |
1037 | |
1038 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); | |
1039 MessageLoop::current()->Run(); | |
1040 | |
1041 // METHOD_PUT should be used to upload data. | |
1042 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); | |
1043 // Request should go to the upload URL. | |
1044 EXPECT_EQ(upload_url.path(), http_request_.relative_url); | |
1045 // Content-Range header should be added. | |
1046 EXPECT_EQ("bytes " + | |
1047 base::Int64ToString(start_position) + "-" + | |
1048 base::Int64ToString(end_position) + "/" + | |
1049 base::Int64ToString(kUploadContent.size()), | |
1050 http_request_.headers["Content-Range"]); | |
1051 // The upload content should be set in the HTTP request. | |
1052 EXPECT_TRUE(http_request_.has_content); | |
1053 EXPECT_EQ(payload, http_request_.content); | |
1054 | |
1055 // Check the response. | |
1056 if (payload.size() == remaining_size) { | |
1057 EXPECT_EQ(HTTP_SUCCESS, response.code); | |
kinaba
2012/12/03 04:37:57
The expected response code for UPLOAD_NEW_FILE mod
satorux1
2012/12/03 05:02:22
Good catch! Fixed!
| |
1058 // The start and end positions should be set to -1, if an upload is | |
1059 // complete. | |
1060 EXPECT_EQ(-1, response.start_range_received); | |
1061 EXPECT_EQ(-1, response.end_range_received); | |
1062 } else { | |
1063 EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code); | |
1064 EXPECT_EQ(static_cast<int64>(start_position), | |
1065 response.start_range_received); | |
1066 EXPECT_EQ(static_cast<int64>(end_position), | |
1067 response.end_range_received); | |
1068 } | |
1069 } | |
1070 | |
1071 EXPECT_EQ(kUploadContent.size(), num_bytes_consumed); | |
1072 } | |
1073 | |
1074 // This test exercises InitiateUploadOperation and ResumeUploadOperation for | |
881 // a scenario of uploading a new *empty* file. | 1075 // a scenario of uploading a new *empty* file. |
882 // | 1076 // |
883 // The test is almost identical to UploadNewFile. The only difference is the | 1077 // The test is almost identical to UploadNewFile. The only difference is the |
884 // expectation for the Content-Range header. | 1078 // expectation for the Content-Range header. |
885 TEST_F(GDataWapiOperationsTest, UploadNewEmptyFile) { | 1079 TEST_F(GDataWapiOperationsTest, UploadNewEmptyFile) { |
886 const std::string kUploadContent = ""; | 1080 const std::string kUploadContent = ""; |
887 GDataErrorCode result_code = GDATA_OTHER_ERROR; | 1081 GDataErrorCode result_code = GDATA_OTHER_ERROR; |
888 GURL upload_url; | 1082 GURL upload_url; |
889 | 1083 |
890 // 1) Get the upload URL for uploading a new file. | 1084 // 1) Get the upload URL for uploading a new file. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
945 new ResumeUploadOperation( | 1139 new ResumeUploadOperation( |
946 &operation_registry_, | 1140 &operation_registry_, |
947 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, | 1141 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, |
948 &response, | 1142 &response, |
949 &new_entry), | 1143 &new_entry), |
950 resume_params); | 1144 resume_params); |
951 | 1145 |
952 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); | 1146 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); |
953 MessageLoop::current()->Run(); | 1147 MessageLoop::current()->Run(); |
954 | 1148 |
955 EXPECT_EQ(HTTP_SUCCESS, result_code); | |
956 // METHOD_PUT should be used to upload data. | 1149 // METHOD_PUT should be used to upload data. |
957 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); | 1150 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); |
958 // Request should go to the upload URL. | 1151 // Request should go to the upload URL. |
959 EXPECT_EQ(upload_url.path(), http_request_.relative_url); | 1152 EXPECT_EQ(upload_url.path(), http_request_.relative_url); |
960 // Content-Range header should not exit if the content is empty. | 1153 // Content-Range header should not exit if the content is empty. |
961 // We should not generate the header with an invalid value "bytes 0--1/0". | 1154 // We should not generate the header with an invalid value "bytes 0--1/0". |
962 EXPECT_EQ(0U, http_request_.headers.count("Content-Range")); | 1155 EXPECT_EQ(0U, http_request_.headers.count("Content-Range")); |
963 // The upload content should be set in the HTTP request. | 1156 // The upload content should be set in the HTTP request. |
964 EXPECT_TRUE(http_request_.has_content); | 1157 EXPECT_TRUE(http_request_.has_content); |
965 EXPECT_EQ(kUploadContent, http_request_.content); | 1158 EXPECT_EQ(kUploadContent, http_request_.content); |
1159 | |
1160 // Check the response. | |
1161 EXPECT_EQ(HTTP_SUCCESS, response.code); | |
1162 // The start and end positions should be set to -1, if an upload is complete. | |
1163 EXPECT_EQ(-1, response.start_range_received); | |
1164 EXPECT_EQ(-1, response.end_range_received); | |
966 } | 1165 } |
967 | 1166 |
968 // This test exercises InitiateUploadOperation and ResumeUploadOperation for | 1167 // This test exercises InitiateUploadOperation and ResumeUploadOperation for |
969 // a scenario of updating an existing file. | 1168 // a scenario of updating an existing file. |
970 TEST_F(GDataWapiOperationsTest, UploadExistingFile) { | 1169 TEST_F(GDataWapiOperationsTest, UploadExistingFile) { |
971 const std::string kUploadContent = "hello"; | 1170 const std::string kUploadContent = "hello"; |
972 GDataErrorCode result_code = GDATA_OTHER_ERROR; | 1171 GDataErrorCode result_code = GDATA_OTHER_ERROR; |
973 GURL upload_url; | 1172 GURL upload_url; |
974 | 1173 |
975 // 1) Get the upload URL for uploading an existing file. | 1174 // 1) Get the upload URL for uploading an existing file. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1031 new ResumeUploadOperation( | 1230 new ResumeUploadOperation( |
1032 &operation_registry_, | 1231 &operation_registry_, |
1033 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, | 1232 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, |
1034 &response, | 1233 &response, |
1035 &new_entry), | 1234 &new_entry), |
1036 resume_params); | 1235 resume_params); |
1037 | 1236 |
1038 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); | 1237 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); |
1039 MessageLoop::current()->Run(); | 1238 MessageLoop::current()->Run(); |
1040 | 1239 |
1041 EXPECT_EQ(HTTP_SUCCESS, result_code); | |
1042 // METHOD_PUT should be used to upload data. | 1240 // METHOD_PUT should be used to upload data. |
1043 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); | 1241 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); |
1044 // Request should go to the upload URL. | 1242 // Request should go to the upload URL. |
1045 EXPECT_EQ(upload_url.path(), http_request_.relative_url); | 1243 EXPECT_EQ(upload_url.path(), http_request_.relative_url); |
1046 // Content-Range header should be added. | 1244 // Content-Range header should be added. |
1047 EXPECT_EQ("bytes 0-" + | 1245 EXPECT_EQ("bytes 0-" + |
1048 base::Int64ToString(kUploadContent.size() -1) + "/" + | 1246 base::Int64ToString(kUploadContent.size() -1) + "/" + |
1049 base::Int64ToString(kUploadContent.size()), | 1247 base::Int64ToString(kUploadContent.size()), |
1050 http_request_.headers["Content-Range"]); | 1248 http_request_.headers["Content-Range"]); |
1051 // The upload content should be set in the HTTP request. | 1249 // The upload content should be set in the HTTP request. |
1052 EXPECT_TRUE(http_request_.has_content); | 1250 EXPECT_TRUE(http_request_.has_content); |
1053 EXPECT_EQ(kUploadContent, http_request_.content); | 1251 EXPECT_EQ(kUploadContent, http_request_.content); |
1252 | |
1253 // Check the response. | |
1254 EXPECT_EQ(HTTP_SUCCESS, response.code); | |
1255 // The start and end positions should be set to -1, if an upload is complete. | |
1256 EXPECT_EQ(-1, response.start_range_received); | |
1257 EXPECT_EQ(-1, response.end_range_received); | |
1054 } | 1258 } |
1055 | 1259 |
1056 } // namespace google_apis | 1260 } // namespace google_apis |
OLD | NEW |