OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/google_apis/base_requests.h" | |
6 | |
7 #include "base/json/json_reader.h" | |
8 #include "base/location.h" | |
9 #include "base/sequenced_task_runner.h" | |
10 #include "base/strings/string_number_conversions.h" | |
11 #include "base/strings/stringprintf.h" | |
12 #include "base/task_runner_util.h" | |
13 #include "base/values.h" | |
14 #include "chrome/browser/google_apis/request_sender.h" | |
15 #include "chrome/browser/google_apis/task_util.h" | |
16 #include "net/base/io_buffer.h" | |
17 #include "net/base/load_flags.h" | |
18 #include "net/base/net_errors.h" | |
19 #include "net/http/http_byte_range.h" | |
20 #include "net/http/http_response_headers.h" | |
21 #include "net/http/http_util.h" | |
22 #include "net/url_request/url_fetcher.h" | |
23 #include "net/url_request/url_request_status.h" | |
24 | |
25 using net::URLFetcher; | |
26 | |
27 namespace { | |
28 | |
29 // Template for optional OAuth2 authorization HTTP header. | |
30 const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; | |
31 // Template for GData API version HTTP header. | |
32 const char kGDataVersionHeader[] = "GData-Version: 3.0"; | |
33 | |
34 // Maximum number of attempts for re-authentication per request. | |
35 const int kMaxReAuthenticateAttemptsPerRequest = 1; | |
36 | |
37 // Template for initiate upload of both GData WAPI and Drive API v2. | |
38 const char kUploadContentType[] = "X-Upload-Content-Type: "; | |
39 const char kUploadContentLength[] = "X-Upload-Content-Length: "; | |
40 const char kUploadResponseLocation[] = "location"; | |
41 | |
42 // Template for upload data range of both GData WAPI and Drive API v2. | |
43 const char kUploadContentRange[] = "Content-Range: bytes "; | |
44 const char kUploadResponseRange[] = "range"; | |
45 | |
46 // Parse JSON string to base::Value object. | |
47 scoped_ptr<base::Value> ParseJsonInternal(const std::string& json) { | |
48 int error_code = -1; | |
49 std::string error_message; | |
50 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( | |
51 json, base::JSON_PARSE_RFC, &error_code, &error_message)); | |
52 | |
53 if (!value.get()) { | |
54 std::string trimmed_json; | |
55 if (json.size() < 80) { | |
56 trimmed_json = json; | |
57 } else { | |
58 // Take the first 50 and the last 10 bytes. | |
59 trimmed_json = base::StringPrintf( | |
60 "%s [%s bytes] %s", | |
61 json.substr(0, 50).c_str(), | |
62 base::Uint64ToString(json.size() - 60).c_str(), | |
63 json.substr(json.size() - 10).c_str()); | |
64 } | |
65 LOG(WARNING) << "Error while parsing entry response: " << error_message | |
66 << ", code: " << error_code << ", json:\n" << trimmed_json; | |
67 } | |
68 return value.Pass(); | |
69 } | |
70 | |
71 // Returns response headers as a string. Returns a warning message if | |
72 // |url_fetcher| does not contain a valid response. Used only for debugging. | |
73 std::string GetResponseHeadersAsString( | |
74 const URLFetcher* url_fetcher) { | |
75 // net::HttpResponseHeaders::raw_headers(), as the name implies, stores | |
76 // all headers in their raw format, i.e each header is null-terminated. | |
77 // So logging raw_headers() only shows the first header, which is probably | |
78 // the status line. GetNormalizedHeaders, on the other hand, will show all | |
79 // the headers, one per line, which is probably what we want. | |
80 std::string headers; | |
81 // Check that response code indicates response headers are valid (i.e. not | |
82 // malformed) before we retrieve the headers. | |
83 if (url_fetcher->GetResponseCode() == URLFetcher::RESPONSE_CODE_INVALID) { | |
84 headers.assign("Response headers are malformed!!"); | |
85 } else { | |
86 url_fetcher->GetResponseHeaders()->GetNormalizedHeaders(&headers); | |
87 } | |
88 return headers; | |
89 } | |
90 | |
91 bool IsSuccessfulResponseCode(int response_code) { | |
92 return 200 <= response_code && response_code <= 299; | |
93 } | |
94 | |
95 } // namespace | |
96 | |
97 namespace google_apis { | |
98 | |
99 void ParseJson(base::TaskRunner* blocking_task_runner, | |
100 const std::string& json, | |
101 const ParseJsonCallback& callback) { | |
102 base::PostTaskAndReplyWithResult( | |
103 blocking_task_runner, | |
104 FROM_HERE, | |
105 base::Bind(&ParseJsonInternal, json), | |
106 callback); | |
107 } | |
108 | |
109 //=========================== ResponseWriter ================================== | |
110 ResponseWriter::ResponseWriter(net::URLFetcher* url_fetcher, | |
111 base::SequencedTaskRunner* file_task_runner, | |
112 const base::FilePath& file_path, | |
113 const GetContentCallback& get_content_callback) | |
114 : url_fetcher_(url_fetcher), | |
115 get_content_callback_(get_content_callback) { | |
116 if (!file_path.empty()) { | |
117 file_writer_.reset( | |
118 new net::URLFetcherFileWriter(file_task_runner, file_path)); | |
119 } | |
120 } | |
121 | |
122 ResponseWriter::~ResponseWriter() { | |
123 } | |
124 | |
125 void ResponseWriter::DisownFile() { | |
126 DCHECK(file_writer_); | |
127 file_writer_->DisownFile(); | |
128 } | |
129 | |
130 int ResponseWriter::Initialize(const net::CompletionCallback& callback) { | |
131 if (file_writer_) | |
132 return file_writer_->Initialize(callback); | |
133 | |
134 data_.clear(); | |
135 return net::OK; | |
136 } | |
137 | |
138 int ResponseWriter::Write(net::IOBuffer* buffer, | |
139 int num_bytes, | |
140 const net::CompletionCallback& callback) { | |
141 // |get_content_callback_| and |file_writer_| are used only when the response | |
142 // code is successful one. | |
143 if (IsSuccessfulResponseCode(url_fetcher_->GetResponseCode())) { | |
144 if (!get_content_callback_.is_null()) { | |
145 get_content_callback_.Run( | |
146 HTTP_SUCCESS, | |
147 make_scoped_ptr(new std::string(buffer->data(), num_bytes))); | |
148 } | |
149 | |
150 if (file_writer_) | |
151 return file_writer_->Write(buffer, num_bytes, callback); | |
152 } | |
153 | |
154 data_.append(buffer->data(), num_bytes); | |
155 return num_bytes; | |
156 } | |
157 | |
158 int ResponseWriter::Finish(const net::CompletionCallback& callback) { | |
159 if (file_writer_) | |
160 return file_writer_->Finish(callback); | |
161 | |
162 return net::OK; | |
163 } | |
164 | |
165 //============================ UrlFetchRequestBase =========================== | |
166 | |
167 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender) | |
168 : re_authenticate_count_(0), | |
169 sender_(sender), | |
170 error_code_(GDATA_OTHER_ERROR), | |
171 weak_ptr_factory_(this) { | |
172 } | |
173 | |
174 UrlFetchRequestBase::~UrlFetchRequestBase() {} | |
175 | |
176 void UrlFetchRequestBase::Start(const std::string& access_token, | |
177 const std::string& custom_user_agent, | |
178 const ReAuthenticateCallback& callback) { | |
179 DCHECK(CalledOnValidThread()); | |
180 DCHECK(!access_token.empty()); | |
181 DCHECK(!callback.is_null()); | |
182 DCHECK(re_authenticate_callback_.is_null()); | |
183 | |
184 re_authenticate_callback_ = callback; | |
185 | |
186 GURL url = GetURL(); | |
187 if (url.is_empty()) { | |
188 // Error is found on generating the url. Send the error message to the | |
189 // callback, and then return immediately without trying to connect | |
190 // to the server. | |
191 RunCallbackOnPrematureFailure(GDATA_OTHER_ERROR); | |
192 return; | |
193 } | |
194 DVLOG(1) << "URL: " << url.spec(); | |
195 | |
196 URLFetcher::RequestType request_type = GetRequestType(); | |
197 url_fetcher_.reset( | |
198 URLFetcher::Create(url, request_type, this)); | |
199 url_fetcher_->SetRequestContext(sender_->url_request_context_getter()); | |
200 // Always set flags to neither send nor save cookies. | |
201 url_fetcher_->SetLoadFlags( | |
202 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES | | |
203 net::LOAD_DISABLE_CACHE); | |
204 | |
205 base::FilePath output_file_path; | |
206 GetContentCallback get_content_callback; | |
207 GetOutputFilePath(&output_file_path, &get_content_callback); | |
208 if (!get_content_callback.is_null()) | |
209 get_content_callback = CreateRelayCallback(get_content_callback); | |
210 response_writer_ = new ResponseWriter(url_fetcher_.get(), | |
211 blocking_task_runner(), | |
212 output_file_path, | |
213 get_content_callback); | |
214 url_fetcher_->SaveResponseWithWriter( | |
215 scoped_ptr<net::URLFetcherResponseWriter>(response_writer_)); | |
216 | |
217 // Add request headers. | |
218 // Note that SetExtraRequestHeaders clears the current headers and sets it | |
219 // to the passed-in headers, so calling it for each header will result in | |
220 // only the last header being set in request headers. | |
221 if (!custom_user_agent.empty()) | |
222 url_fetcher_->AddExtraRequestHeader("User-Agent: " + custom_user_agent); | |
223 url_fetcher_->AddExtraRequestHeader(kGDataVersionHeader); | |
224 url_fetcher_->AddExtraRequestHeader( | |
225 base::StringPrintf(kAuthorizationHeaderFormat, access_token.data())); | |
226 std::vector<std::string> headers = GetExtraRequestHeaders(); | |
227 for (size_t i = 0; i < headers.size(); ++i) { | |
228 url_fetcher_->AddExtraRequestHeader(headers[i]); | |
229 DVLOG(1) << "Extra header: " << headers[i]; | |
230 } | |
231 | |
232 // Set upload data if available. | |
233 std::string upload_content_type; | |
234 std::string upload_content; | |
235 if (GetContentData(&upload_content_type, &upload_content)) { | |
236 url_fetcher_->SetUploadData(upload_content_type, upload_content); | |
237 } else { | |
238 base::FilePath local_file_path; | |
239 int64 range_offset = 0; | |
240 int64 range_length = 0; | |
241 if (GetContentFile(&local_file_path, &range_offset, &range_length, | |
242 &upload_content_type)) { | |
243 url_fetcher_->SetUploadFilePath( | |
244 upload_content_type, | |
245 local_file_path, | |
246 range_offset, | |
247 range_length, | |
248 blocking_task_runner()); | |
249 } else { | |
250 // Even if there is no content data, UrlFetcher requires to set empty | |
251 // upload data string for POST, PUT and PATCH methods, explicitly. | |
252 // It is because that most requests of those methods have non-empty | |
253 // body, and UrlFetcher checks whether it is actually not forgotten. | |
254 if (request_type == URLFetcher::POST || | |
255 request_type == URLFetcher::PUT || | |
256 request_type == URLFetcher::PATCH) { | |
257 // Set empty upload content-type and upload content, so that | |
258 // the request will have no "Content-type: " header and no content. | |
259 url_fetcher_->SetUploadData(std::string(), std::string()); | |
260 } | |
261 } | |
262 } | |
263 | |
264 url_fetcher_->Start(); | |
265 } | |
266 | |
267 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const { | |
268 return URLFetcher::GET; | |
269 } | |
270 | |
271 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const { | |
272 return std::vector<std::string>(); | |
273 } | |
274 | |
275 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type, | |
276 std::string* upload_content) { | |
277 return false; | |
278 } | |
279 | |
280 bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path, | |
281 int64* range_offset, | |
282 int64* range_length, | |
283 std::string* upload_content_type) { | |
284 return false; | |
285 } | |
286 | |
287 void UrlFetchRequestBase::GetOutputFilePath( | |
288 base::FilePath* local_file_path, | |
289 GetContentCallback* get_content_callback) { | |
290 } | |
291 | |
292 void UrlFetchRequestBase::Cancel() { | |
293 response_writer_ = NULL; | |
294 url_fetcher_.reset(NULL); | |
295 RunCallbackOnPrematureFailure(GDATA_CANCELLED); | |
296 sender_->RequestFinished(this); | |
297 } | |
298 | |
299 GDataErrorCode UrlFetchRequestBase::GetErrorCode() { | |
300 return error_code_; | |
301 } | |
302 | |
303 bool UrlFetchRequestBase::CalledOnValidThread() { | |
304 return thread_checker_.CalledOnValidThread(); | |
305 } | |
306 | |
307 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const { | |
308 return sender_->blocking_task_runner(); | |
309 } | |
310 | |
311 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() { | |
312 sender_->RequestFinished(this); | |
313 } | |
314 | |
315 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) { | |
316 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source); | |
317 | |
318 // Determine error code. | |
319 error_code_ = static_cast<GDataErrorCode>(source->GetResponseCode()); | |
320 if (!source->GetStatus().is_success()) { | |
321 switch (source->GetStatus().error()) { | |
322 case net::ERR_NETWORK_CHANGED: | |
323 error_code_ = GDATA_NO_CONNECTION; | |
324 break; | |
325 default: | |
326 error_code_ = GDATA_OTHER_ERROR; | |
327 } | |
328 } | |
329 | |
330 // The server may return detailed error status in JSON. | |
331 // See https://developers.google.com/drive/handle-errors | |
332 if (!IsSuccessfulResponseCode(error_code_)) { | |
333 DVLOG(1) << response_writer_->data(); | |
334 | |
335 const char kErrorKey[] = "error"; | |
336 const char kErrorErrorsKey[] = "errors"; | |
337 const char kErrorReasonKey[] = "reason"; | |
338 const char kErrorMessageKey[] = "message"; | |
339 const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded"; | |
340 const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded"; | |
341 | |
342 scoped_ptr<base::Value> value(ParseJsonInternal(response_writer_->data())); | |
343 base::DictionaryValue* dictionary = NULL; | |
344 base::DictionaryValue* error = NULL; | |
345 if (value && | |
346 value->GetAsDictionary(&dictionary) && | |
347 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) { | |
348 // Get error message. | |
349 std::string message; | |
350 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message); | |
351 DLOG(ERROR) << "code: " << error_code_ << ", message: " << message; | |
352 | |
353 // Override the error code based on the reason of the first error. | |
354 base::ListValue* errors = NULL; | |
355 base::DictionaryValue* first_error = NULL; | |
356 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) && | |
357 errors->GetDictionary(0, &first_error)) { | |
358 std::string reason; | |
359 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason); | |
360 if (reason == kErrorReasonRateLimitExceeded || | |
361 reason == kErrorReasonUserRateLimitExceeded) | |
362 error_code_ = HTTP_SERVICE_UNAVAILABLE; | |
363 } | |
364 } | |
365 } | |
366 | |
367 // Handle authentication failure. | |
368 if (error_code_ == HTTP_UNAUTHORIZED) { | |
369 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) { | |
370 // Reset re_authenticate_callback_ so Start() can be called again. | |
371 ReAuthenticateCallback callback = re_authenticate_callback_; | |
372 re_authenticate_callback_.Reset(); | |
373 callback.Run(this); | |
374 return; | |
375 } | |
376 | |
377 OnAuthFailed(error_code_); | |
378 return; | |
379 } | |
380 | |
381 // Overridden by each specialization | |
382 ProcessURLFetchResults(source); | |
383 } | |
384 | |
385 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) { | |
386 RunCallbackOnPrematureFailure(code); | |
387 sender_->RequestFinished(this); | |
388 } | |
389 | |
390 base::WeakPtr<AuthenticatedRequestInterface> | |
391 UrlFetchRequestBase::GetWeakPtr() { | |
392 return weak_ptr_factory_.GetWeakPtr(); | |
393 } | |
394 | |
395 //============================ EntryActionRequest ============================ | |
396 | |
397 EntryActionRequest::EntryActionRequest(RequestSender* sender, | |
398 const EntryActionCallback& callback) | |
399 : UrlFetchRequestBase(sender), | |
400 callback_(callback) { | |
401 DCHECK(!callback_.is_null()); | |
402 } | |
403 | |
404 EntryActionRequest::~EntryActionRequest() {} | |
405 | |
406 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) { | |
407 callback_.Run(GetErrorCode()); | |
408 OnProcessURLFetchResultsComplete(); | |
409 } | |
410 | |
411 void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) { | |
412 callback_.Run(code); | |
413 } | |
414 | |
415 //============================== GetDataRequest ============================== | |
416 | |
417 GetDataRequest::GetDataRequest(RequestSender* sender, | |
418 const GetDataCallback& callback) | |
419 : UrlFetchRequestBase(sender), | |
420 callback_(callback), | |
421 weak_ptr_factory_(this) { | |
422 DCHECK(!callback_.is_null()); | |
423 } | |
424 | |
425 GetDataRequest::~GetDataRequest() {} | |
426 | |
427 void GetDataRequest::ParseResponse(GDataErrorCode fetch_error_code, | |
428 const std::string& data) { | |
429 DCHECK(CalledOnValidThread()); | |
430 | |
431 VLOG(1) << "JSON received from " << GetURL().spec() << ": " | |
432 << data.size() << " bytes"; | |
433 ParseJson(blocking_task_runner(), | |
434 data, | |
435 base::Bind(&GetDataRequest::OnDataParsed, | |
436 weak_ptr_factory_.GetWeakPtr(), | |
437 fetch_error_code)); | |
438 } | |
439 | |
440 void GetDataRequest::ProcessURLFetchResults(const URLFetcher* source) { | |
441 GDataErrorCode fetch_error_code = GetErrorCode(); | |
442 | |
443 switch (fetch_error_code) { | |
444 case HTTP_SUCCESS: | |
445 case HTTP_CREATED: | |
446 ParseResponse(fetch_error_code, response_writer()->data()); | |
447 break; | |
448 default: | |
449 RunCallbackOnPrematureFailure(fetch_error_code); | |
450 OnProcessURLFetchResultsComplete(); | |
451 break; | |
452 } | |
453 } | |
454 | |
455 void GetDataRequest::RunCallbackOnPrematureFailure( | |
456 GDataErrorCode fetch_error_code) { | |
457 callback_.Run(fetch_error_code, scoped_ptr<base::Value>()); | |
458 } | |
459 | |
460 void GetDataRequest::OnDataParsed(GDataErrorCode fetch_error_code, | |
461 scoped_ptr<base::Value> value) { | |
462 DCHECK(CalledOnValidThread()); | |
463 | |
464 if (!value.get()) | |
465 fetch_error_code = GDATA_PARSE_ERROR; | |
466 | |
467 callback_.Run(fetch_error_code, value.Pass()); | |
468 OnProcessURLFetchResultsComplete(); | |
469 } | |
470 | |
471 //========================= InitiateUploadRequestBase ======================== | |
472 | |
473 InitiateUploadRequestBase::InitiateUploadRequestBase( | |
474 RequestSender* sender, | |
475 const InitiateUploadCallback& callback, | |
476 const std::string& content_type, | |
477 int64 content_length) | |
478 : UrlFetchRequestBase(sender), | |
479 callback_(callback), | |
480 content_type_(content_type), | |
481 content_length_(content_length) { | |
482 DCHECK(!callback_.is_null()); | |
483 DCHECK(!content_type_.empty()); | |
484 DCHECK_GE(content_length_, 0); | |
485 } | |
486 | |
487 InitiateUploadRequestBase::~InitiateUploadRequestBase() {} | |
488 | |
489 void InitiateUploadRequestBase::ProcessURLFetchResults( | |
490 const URLFetcher* source) { | |
491 GDataErrorCode code = GetErrorCode(); | |
492 | |
493 std::string upload_location; | |
494 if (code == HTTP_SUCCESS) { | |
495 // Retrieve value of the first "Location" header. | |
496 source->GetResponseHeaders()->EnumerateHeader(NULL, | |
497 kUploadResponseLocation, | |
498 &upload_location); | |
499 } | |
500 | |
501 callback_.Run(code, GURL(upload_location)); | |
502 OnProcessURLFetchResultsComplete(); | |
503 } | |
504 | |
505 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure( | |
506 GDataErrorCode code) { | |
507 callback_.Run(code, GURL()); | |
508 } | |
509 | |
510 std::vector<std::string> | |
511 InitiateUploadRequestBase::GetExtraRequestHeaders() const { | |
512 std::vector<std::string> headers; | |
513 headers.push_back(kUploadContentType + content_type_); | |
514 headers.push_back( | |
515 kUploadContentLength + base::Int64ToString(content_length_)); | |
516 return headers; | |
517 } | |
518 | |
519 //============================ UploadRangeResponse ============================= | |
520 | |
521 UploadRangeResponse::UploadRangeResponse() | |
522 : code(HTTP_SUCCESS), | |
523 start_position_received(0), | |
524 end_position_received(0) { | |
525 } | |
526 | |
527 UploadRangeResponse::UploadRangeResponse(GDataErrorCode code, | |
528 int64 start_position_received, | |
529 int64 end_position_received) | |
530 : code(code), | |
531 start_position_received(start_position_received), | |
532 end_position_received(end_position_received) { | |
533 } | |
534 | |
535 UploadRangeResponse::~UploadRangeResponse() { | |
536 } | |
537 | |
538 //========================== UploadRangeRequestBase ========================== | |
539 | |
540 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender, | |
541 const GURL& upload_url) | |
542 : UrlFetchRequestBase(sender), | |
543 upload_url_(upload_url), | |
544 weak_ptr_factory_(this) { | |
545 } | |
546 | |
547 UploadRangeRequestBase::~UploadRangeRequestBase() {} | |
548 | |
549 GURL UploadRangeRequestBase::GetURL() const { | |
550 // This is very tricky to get json from this request. To do that, &alt=json | |
551 // has to be appended not here but in InitiateUploadRequestBase::GetURL(). | |
552 return upload_url_; | |
553 } | |
554 | |
555 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const { | |
556 return URLFetcher::PUT; | |
557 } | |
558 | |
559 void UploadRangeRequestBase::ProcessURLFetchResults( | |
560 const URLFetcher* source) { | |
561 GDataErrorCode code = GetErrorCode(); | |
562 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders(); | |
563 | |
564 if (code == HTTP_RESUME_INCOMPLETE) { | |
565 // Retrieve value of the first "Range" header. | |
566 // The Range header is appeared only if there is at least one received | |
567 // byte. So, initialize the positions by 0 so that the [0,0) will be | |
568 // returned via the |callback_| for empty data case. | |
569 int64 start_position_received = 0; | |
570 int64 end_position_received = 0; | |
571 std::string range_received; | |
572 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received); | |
573 if (!range_received.empty()) { // Parse the range header. | |
574 std::vector<net::HttpByteRange> ranges; | |
575 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) && | |
576 !ranges.empty() ) { | |
577 // We only care about the first start-end pair in the range. | |
578 // | |
579 // Range header represents the range inclusively, while we are treating | |
580 // ranges exclusively (i.e., end_position_received should be one passed | |
581 // the last valid index). So "+ 1" is added. | |
582 start_position_received = ranges[0].first_byte_position(); | |
583 end_position_received = ranges[0].last_byte_position() + 1; | |
584 } | |
585 } | |
586 // The Range header has the received data range, so the start position | |
587 // should be always 0. | |
588 DCHECK_EQ(start_position_received, 0); | |
589 | |
590 OnRangeRequestComplete(UploadRangeResponse(code, | |
591 start_position_received, | |
592 end_position_received), | |
593 scoped_ptr<base::Value>()); | |
594 | |
595 OnProcessURLFetchResultsComplete(); | |
596 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) { | |
597 // The upload is successfully done. Parse the response which should be | |
598 // the entry's metadata. | |
599 ParseJson(blocking_task_runner(), | |
600 response_writer()->data(), | |
601 base::Bind(&UploadRangeRequestBase::OnDataParsed, | |
602 weak_ptr_factory_.GetWeakPtr(), | |
603 code)); | |
604 } else { | |
605 // Failed to upload. Run callbacks to notify the error. | |
606 OnRangeRequestComplete( | |
607 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>()); | |
608 OnProcessURLFetchResultsComplete(); | |
609 } | |
610 } | |
611 | |
612 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code, | |
613 scoped_ptr<base::Value> value) { | |
614 DCHECK(CalledOnValidThread()); | |
615 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS); | |
616 | |
617 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass()); | |
618 OnProcessURLFetchResultsComplete(); | |
619 } | |
620 | |
621 void UploadRangeRequestBase::RunCallbackOnPrematureFailure( | |
622 GDataErrorCode code) { | |
623 OnRangeRequestComplete( | |
624 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>()); | |
625 } | |
626 | |
627 //========================== ResumeUploadRequestBase ========================= | |
628 | |
629 ResumeUploadRequestBase::ResumeUploadRequestBase( | |
630 RequestSender* sender, | |
631 const GURL& upload_location, | |
632 int64 start_position, | |
633 int64 end_position, | |
634 int64 content_length, | |
635 const std::string& content_type, | |
636 const base::FilePath& local_file_path) | |
637 : UploadRangeRequestBase(sender, upload_location), | |
638 start_position_(start_position), | |
639 end_position_(end_position), | |
640 content_length_(content_length), | |
641 content_type_(content_type), | |
642 local_file_path_(local_file_path) { | |
643 DCHECK_LE(start_position_, end_position_); | |
644 } | |
645 | |
646 ResumeUploadRequestBase::~ResumeUploadRequestBase() {} | |
647 | |
648 std::vector<std::string> | |
649 ResumeUploadRequestBase::GetExtraRequestHeaders() const { | |
650 if (content_length_ == 0) { | |
651 // For uploading an empty document, just PUT an empty content. | |
652 DCHECK_EQ(start_position_, 0); | |
653 DCHECK_EQ(end_position_, 0); | |
654 return std::vector<std::string>(); | |
655 } | |
656 | |
657 // The header looks like | |
658 // Content-Range: bytes <start_position>-<end_position>/<content_length> | |
659 // for example: | |
660 // Content-Range: bytes 7864320-8388607/13851821 | |
661 // The header takes inclusive range, so we adjust by "end_position - 1". | |
662 DCHECK_GE(start_position_, 0); | |
663 DCHECK_GT(end_position_, 0); | |
664 DCHECK_GE(content_length_, 0); | |
665 | |
666 std::vector<std::string> headers; | |
667 headers.push_back( | |
668 std::string(kUploadContentRange) + | |
669 base::Int64ToString(start_position_) + "-" + | |
670 base::Int64ToString(end_position_ - 1) + "/" + | |
671 base::Int64ToString(content_length_)); | |
672 return headers; | |
673 } | |
674 | |
675 bool ResumeUploadRequestBase::GetContentFile( | |
676 base::FilePath* local_file_path, | |
677 int64* range_offset, | |
678 int64* range_length, | |
679 std::string* upload_content_type) { | |
680 if (start_position_ == end_position_) { | |
681 // No content data. | |
682 return false; | |
683 } | |
684 | |
685 *local_file_path = local_file_path_; | |
686 *range_offset = start_position_; | |
687 *range_length = end_position_ - start_position_; | |
688 *upload_content_type = content_type_; | |
689 return true; | |
690 } | |
691 | |
692 //======================== GetUploadStatusRequestBase ======================== | |
693 | |
694 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender, | |
695 const GURL& upload_url, | |
696 int64 content_length) | |
697 : UploadRangeRequestBase(sender, upload_url), | |
698 content_length_(content_length) {} | |
699 | |
700 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {} | |
701 | |
702 std::vector<std::string> | |
703 GetUploadStatusRequestBase::GetExtraRequestHeaders() const { | |
704 // The header looks like | |
705 // Content-Range: bytes */<content_length> | |
706 // for example: | |
707 // Content-Range: bytes */13851821 | |
708 DCHECK_GE(content_length_, 0); | |
709 | |
710 std::vector<std::string> headers; | |
711 headers.push_back( | |
712 std::string(kUploadContentRange) + "*/" + | |
713 base::Int64ToString(content_length_)); | |
714 return headers; | |
715 } | |
716 | |
717 //============================ DownloadFileRequestBase ========================= | |
718 | |
719 DownloadFileRequestBase::DownloadFileRequestBase( | |
720 RequestSender* sender, | |
721 const DownloadActionCallback& download_action_callback, | |
722 const GetContentCallback& get_content_callback, | |
723 const ProgressCallback& progress_callback, | |
724 const GURL& download_url, | |
725 const base::FilePath& output_file_path) | |
726 : UrlFetchRequestBase(sender), | |
727 download_action_callback_(download_action_callback), | |
728 get_content_callback_(get_content_callback), | |
729 progress_callback_(progress_callback), | |
730 download_url_(download_url), | |
731 output_file_path_(output_file_path) { | |
732 DCHECK(!download_action_callback_.is_null()); | |
733 DCHECK(!output_file_path_.empty()); | |
734 // get_content_callback may be null. | |
735 } | |
736 | |
737 DownloadFileRequestBase::~DownloadFileRequestBase() {} | |
738 | |
739 // Overridden from UrlFetchRequestBase. | |
740 GURL DownloadFileRequestBase::GetURL() const { | |
741 return download_url_; | |
742 } | |
743 | |
744 void DownloadFileRequestBase::GetOutputFilePath( | |
745 base::FilePath* local_file_path, | |
746 GetContentCallback* get_content_callback) { | |
747 // Configure so that the downloaded content is saved to |output_file_path_|. | |
748 *local_file_path = output_file_path_; | |
749 *get_content_callback = get_content_callback_; | |
750 } | |
751 | |
752 void DownloadFileRequestBase::OnURLFetchDownloadProgress( | |
753 const URLFetcher* source, | |
754 int64 current, | |
755 int64 total) { | |
756 if (!progress_callback_.is_null()) | |
757 progress_callback_.Run(current, total); | |
758 } | |
759 | |
760 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) { | |
761 GDataErrorCode code = GetErrorCode(); | |
762 | |
763 // Take over the ownership of the the downloaded temp file. | |
764 base::FilePath temp_file; | |
765 if (code == HTTP_SUCCESS) { | |
766 response_writer()->DisownFile(); | |
767 temp_file = output_file_path_; | |
768 } | |
769 | |
770 download_action_callback_.Run(code, temp_file); | |
771 OnProcessURLFetchResultsComplete(); | |
772 } | |
773 | |
774 void DownloadFileRequestBase::RunCallbackOnPrematureFailure( | |
775 GDataErrorCode code) { | |
776 download_action_callback_.Run(code, base::FilePath()); | |
777 } | |
778 | |
779 } // namespace google_apis | |
OLD | NEW |