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