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