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

Side by Side Diff: google_apis/drive/drive_api_requests.cc

Issue 1081313002: Drive: Add response handling to BatchUploadRequst class. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 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
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 "google_apis/drive/drive_api_requests.h" 5 #include "google_apis/drive/drive_api_requests.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 18 matching lines...) Expand all
29 "Content-Type: %s\n" 29 "Content-Type: %s\n"
30 "\n" 30 "\n"
31 "%s"; 31 "%s";
32 32
33 // Request header for specifying batch upload. 33 // Request header for specifying batch upload.
34 const char kBatchUploadHeader[] = "X-Goog-Upload-Protocol: batch"; 34 const char kBatchUploadHeader[] = "X-Goog-Upload-Protocol: batch";
35 35
36 // Content type of HTTP request. 36 // Content type of HTTP request.
37 const char kHttpContentType[] = "application/http"; 37 const char kHttpContentType[] = "application/http";
38 38
39 // Break line in HTTP message.
40 const std::string kHttpBr = "\r\n";
41
39 // Parses the JSON value to FileResource instance and runs |callback| on the 42 // Parses the JSON value to FileResource instance and runs |callback| on the
40 // UI thread once parsing is done. 43 // UI thread once parsing is done.
41 // This is customized version of ParseJsonAndRun defined above to adapt the 44 // This is customized version of ParseJsonAndRun defined above to adapt the
42 // remaining response type. 45 // remaining response type.
43 void ParseFileResourceWithUploadRangeAndRun(const UploadRangeCallback& callback, 46 void ParseFileResourceWithUploadRangeAndRun(const UploadRangeCallback& callback,
44 const UploadRangeResponse& response, 47 const UploadRangeResponse& response,
45 scoped_ptr<base::Value> value) { 48 scoped_ptr<base::Value> value) {
46 DCHECK(!callback.is_null()); 49 DCHECK(!callback.is_null());
47 50
48 scoped_ptr<FileResource> file_resource; 51 scoped_ptr<FileResource> file_resource;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 root.SetString("lastViewedByMeDate", google_apis::util::FormatTimeAsString( 122 root.SetString("lastViewedByMeDate", google_apis::util::FormatTimeAsString(
120 last_viewed_by_me_date)); 123 last_viewed_by_me_date));
121 } 124 }
122 125
123 AttachProperties(properties, &root); 126 AttachProperties(properties, &root);
124 std::string json_string; 127 std::string json_string;
125 base::JSONWriter::Write(&root, &json_string); 128 base::JSONWriter::Write(&root, &json_string);
126 return json_string; 129 return json_string;
127 } 130 }
128 131
132 // Checks if |str| at |pos| starts with |prefix|.
133 bool StartWith(const std::string& str, size_t pos, const std::string& prefix) {
134 if (pos + prefix.size() > str.size())
135 return false;
136 return std::equal(prefix.begin(), prefix.end(), str.begin() + pos);
137 }
138
139 // Splits multipart |response| into |parts|. Returns true on succcess.
kinaba 2015/04/14 06:25:26 Link to the spec (and preferably a short summary o
kinaba 2015/04/14 06:25:26 I think these util functions are complex enough fo
hirono 2015/04/27 06:25:07 Done.
140 bool SplitMultipartResponse(const std::string& response,
141 std::vector<std::string>* parts) {
142 const std::string kMultipartTerminator = "--";
143 std::string boundary;
144 {
145 const size_t pos = response.find(kHttpBr, 0);
146 if (pos == std::string::npos)
147 return false;
148 boundary = response.substr(0, pos);
kinaba 2015/04/14 06:25:25 Can't you get the boundary from HTTP response head
hirono 2015/04/27 06:25:07 Done.
149 }
150 size_t pos = 0;
151 parts->clear();
152 while (true) {
153 pos += boundary.size();
154 if (StartWith(response, pos, kMultipartTerminator))
155 return true;
156 else if (StartWith(response, pos, kHttpBr))
157 pos += kHttpBr.size();
158 else
159 return false;
160
161 const size_t next_pos = response.find(boundary, pos);
kinaba 2015/04/14 06:25:26 IIUC boundary may still appear in content body (wh
hirono 2015/04/27 06:25:07 Done.
162 if (next_pos == std::string::npos)
163 return false;
164 parts->push_back(response.substr(pos, next_pos - pos));
165 pos = next_pos;
166 }
167 return true;
168 }
169
170 // Parses HTTP response in multipart entry and obtain |code| and |body|.
171 // Returns true on succcess.
172 bool ParseMultipartEntry(const std::string& entry,
173 DriveApiErrorCode* code,
174 std::string* body) {
175 const std::string kHttpStatusPrefix = "HTTP/1.1 ";
176
177 // Skip content type line of multipart.
178 size_t pos = entry.find(kHttpBr + kHttpBr, 0);
179 if (pos == std::string::npos)
180 return false;
181 pos += kHttpBr.size() * 2;
kinaba 2015/04/14 06:25:26 Btw, I guess it is in general easy to split all th
hirono 2015/04/27 06:25:07 Done.
182
183 // Read status line of HTTP.
184 if (!StartWith(entry, pos, kHttpStatusPrefix))
185 return false;
186 pos += kHttpStatusPrefix.size();
187
188 *code = static_cast<DriveApiErrorCode>(atoi(entry.c_str() + pos));
189 if (*code == 0)
190 return false;
191
192 // Skip headers of HTTP.
193 pos = entry.find(kHttpBr + kHttpBr, pos);
194 if (pos == std::string::npos)
195 return false;
196 pos += kHttpBr.size() * 2;
197
198 // Read body.
199 *body = entry.substr(pos);
200
201 return true;
202 }
203
129 } // namespace 204 } // namespace
130 205
131 Property::Property() : visibility_(VISIBILITY_PRIVATE) { 206 Property::Property() : visibility_(VISIBILITY_PRIVATE) {
132 } 207 }
133 208
134 Property::~Property() { 209 Property::~Property() {
135 } 210 }
136 211
137 //============================ DriveApiPartialFieldRequest ==================== 212 //============================ DriveApiPartialFieldRequest ====================
138 213
(...skipping 868 matching lines...) Expand 10 before | Expand all | Expand 10 after
1007 void BatchUploadRequest::SetBoundaryForTesting(const std::string& boundary) { 1082 void BatchUploadRequest::SetBoundaryForTesting(const std::string& boundary) {
1008 boundary_ = boundary; 1083 boundary_ = boundary;
1009 } 1084 }
1010 1085
1011 void BatchUploadRequest::AddRequest(BatchableRequestBase* request) { 1086 void BatchUploadRequest::AddRequest(BatchableRequestBase* request) {
1012 DCHECK(CalledOnValidThread()); 1087 DCHECK(CalledOnValidThread());
1013 DCHECK(request); 1088 DCHECK(request);
1014 DCHECK(GetChildEntry(request) == child_requests_.end()); 1089 DCHECK(GetChildEntry(request) == child_requests_.end());
1015 DCHECK(!committed_); 1090 DCHECK(!committed_);
1016 child_requests_.push_back(BatchUploadChildEntry(request)); 1091 child_requests_.push_back(BatchUploadChildEntry(request));
1017 request->Prepare( 1092 request->Prepare(base::Bind(&BatchUploadRequest::OnChildRequestPrepared,
1018 base::Bind(&BatchUploadRequest::OnChildRequestPrepared, 1093 weak_ptr_factory_.GetWeakPtr(), request));
1019 weak_ptr_factory_.GetWeakPtr(),
1020 request));
1021 } 1094 }
1022 1095
1023 void BatchUploadRequest::OnChildRequestPrepared( 1096 void BatchUploadRequest::OnChildRequestPrepared(RequestID request_id,
1024 RequestID request_id, DriveApiErrorCode result) { 1097 DriveApiErrorCode result) {
1025 DCHECK(CalledOnValidThread()); 1098 DCHECK(CalledOnValidThread());
1026 auto const child = GetChildEntry(request_id); 1099 auto const child = GetChildEntry(request_id);
1027 DCHECK(child != child_requests_.end()); 1100 DCHECK(child != child_requests_.end());
1028 if (IsSuccessfulDriveApiErrorCode(result)) { 1101 if (IsSuccessfulDriveApiErrorCode(result)) {
1029 child->prepared = true; 1102 child->prepared = true;
1030 } else { 1103 } else {
1031 child->request->RunCallbackOnPrematureFailure(result); 1104 child->request->RunCallbackOnPrematureFailure(result);
1032 sender_->RequestFinished(child->request); 1105 sender_->RequestFinished(child->request);
1033 child_requests_.erase(child); 1106 child_requests_.erase(child);
1034 } 1107 }
(...skipping 19 matching lines...) Expand all
1054 for (auto& child : child_requests_) { 1127 for (auto& child : child_requests_) {
1055 // Request cancel should delete the request instance. 1128 // Request cancel should delete the request instance.
1056 child.request->Cancel(); 1129 child.request->Cancel();
1057 } 1130 }
1058 child_requests_.clear(); 1131 child_requests_.clear();
1059 UrlFetchRequestBase::Cancel(); 1132 UrlFetchRequestBase::Cancel();
1060 } 1133 }
1061 1134
1062 // Obtains corresponding child entry of |request_id|. Returns NULL if the 1135 // Obtains corresponding child entry of |request_id|. Returns NULL if the
1063 // entry is not found. 1136 // entry is not found.
1064 std::vector<BatchUploadChildEntry>::iterator 1137 std::vector<BatchUploadChildEntry>::iterator BatchUploadRequest::GetChildEntry(
1065 BatchUploadRequest::GetChildEntry(RequestID request_id) { 1138 RequestID request_id) {
1066 for (auto it = child_requests_.begin(); it != child_requests_.end(); ++it) { 1139 for (auto it = child_requests_.begin(); it != child_requests_.end(); ++it) {
1067 if (it->request == request_id) 1140 if (it->request == request_id)
1068 return it; 1141 return it;
1069 } 1142 }
1070 return child_requests_.end(); 1143 return child_requests_.end();
1071 } 1144 }
1072 1145
1073 void BatchUploadRequest::MayCompletePrepare() { 1146 void BatchUploadRequest::MayCompletePrepare() {
1074 if (!committed_ || prepare_callback_.is_null()) 1147 if (!committed_ || prepare_callback_.is_null())
1075 return; 1148 return;
(...skipping 21 matching lines...) Expand all
1097 method = "PUT"; 1170 method = "PUT";
1098 break; 1171 break;
1099 default: 1172 default:
1100 NOTREACHED(); 1173 NOTREACHED();
1101 break; 1174 break;
1102 } 1175 }
1103 1176
1104 parts.push_back(ContentTypeAndData()); 1177 parts.push_back(ContentTypeAndData());
1105 parts.back().type = kHttpContentType; 1178 parts.back().type = kHttpContentType;
1106 parts.back().data = base::StringPrintf( 1179 parts.back().data = base::StringPrintf(
1107 kBatchUploadRequestFormat, 1180 kBatchUploadRequestFormat, method.c_str(), url.path().c_str(),
1108 method.c_str(), 1181 url_generator_.GetBatchUploadUrl().host().c_str(), type.c_str(),
1109 url.path().c_str(),
1110 url_generator_.GetBatchUploadUrl().host().c_str(),
1111 type.c_str(),
1112 data.c_str()); 1182 data.c_str());
1113 } 1183 }
1114 1184
1115 GenerateMultipartBody(MULTIPART_MIXED, boundary_, parts, &upload_content_); 1185 GenerateMultipartBody(MULTIPART_MIXED, boundary_, parts, &upload_content_);
1116 prepare_callback_.Run(HTTP_SUCCESS); 1186 prepare_callback_.Run(HTTP_SUCCESS);
1117 } 1187 }
1118 1188
1119 bool BatchUploadRequest::GetContentData(std::string* upload_content_type, 1189 bool BatchUploadRequest::GetContentData(std::string* upload_content_type,
1120 std::string* upload_content_data) { 1190 std::string* upload_content_data) {
1121 upload_content_type->assign(upload_content_.type); 1191 upload_content_type->assign(upload_content_.type);
(...skipping 20 matching lines...) Expand all
1142 return headers; 1212 return headers;
1143 } 1213 }
1144 1214
1145 void BatchUploadRequest::ProcessURLFetchResults(const net::URLFetcher* source) { 1215 void BatchUploadRequest::ProcessURLFetchResults(const net::URLFetcher* source) {
1146 if (!IsSuccessfulDriveApiErrorCode(GetErrorCode())) { 1216 if (!IsSuccessfulDriveApiErrorCode(GetErrorCode())) {
1147 RunCallbackOnPrematureFailure(GetErrorCode()); 1217 RunCallbackOnPrematureFailure(GetErrorCode());
1148 sender_->RequestFinished(this); 1218 sender_->RequestFinished(this);
1149 return; 1219 return;
1150 } 1220 }
1151 1221
1152 for (auto& child : child_requests_) { 1222 std::vector<std::string> parts;
1153 // TODO(hirono): Split the mutlipart result and return the correct code and 1223 if (!SplitMultipartResponse(response_writer()->data(), &parts) ||
1154 // body. 1224 child_requests_.size() != parts.size()) {
1155 child.request->ProcessURLFetchResults(HTTP_SERVICE_UNAVAILABLE, ""); 1225 RunCallbackOnPrematureFailure(DRIVE_PARSE_ERROR);
1156 // Request deletes itself after processing. 1226 sender_->RequestFinished(this);
1227 return;
1228 }
1229
1230 for (size_t i = 0; i < parts.size(); ++i) {
1231 DriveApiErrorCode code;
1232 std::string body;
1233 if (ParseMultipartEntry(parts[i], &code, &body)) {
1234 child_requests_[i].request->ProcessURLFetchResults(code, body);
1235 // Request deletes itself after processing.
1236 } else {
1237 child_requests_[i].request->RunCallbackOnPrematureFailure(
1238 DRIVE_PARSE_ERROR);
1239 sender_->RequestFinished(child_requests_[i].request);
1240 }
1157 } 1241 }
1158 1242
1159 child_requests_.clear(); 1243 child_requests_.clear();
1160 } 1244 }
kinaba 2015/04/14 06:25:25 Maybe I should have asked this in the previous CL?
hirono 2015/04/27 06:25:07 Done.
1161 1245
1162 void BatchUploadRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) { 1246 void BatchUploadRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) {
1163 for (auto child : child_requests_) { 1247 for (auto child : child_requests_) {
1164 child.request->RunCallbackOnPrematureFailure(code); 1248 child.request->RunCallbackOnPrematureFailure(code);
1165 sender_->RequestFinished(child.request); 1249 sender_->RequestFinished(child.request);
1166 } 1250 }
1167 child_requests_.clear(); 1251 child_requests_.clear();
1168 } 1252 }
1169 1253
1170 } // namespace drive 1254 } // namespace drive
1171 } // namespace google_apis 1255 } // namespace google_apis
OLDNEW
« no previous file with comments | « google_apis/drive/drive_api_requests.h ('k') | google_apis/drive/drive_api_requests_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698