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 362 scoped_ptr<base::Value> value(ParseJsonInternal(response_writer_->data())); 363 base::DictionaryValue* dictionary = NULL; 364 base::DictionaryValue* error = NULL; 365 if (value && 366 value->GetAsDictionary(&dictionary) && 367 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) { 368 // Get error message. 369 std::string message; 370 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message); 371 DLOG(ERROR) << "code: " << error_code_ << ", message: " << message; 372 373 // Override the error code based on the reason of the first error. 374 base::ListValue* errors = NULL; 375 base::DictionaryValue* first_error = NULL; 376 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) && 377 errors->GetDictionary(0, &first_error)) { 378 std::string reason; 379 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason); 380 if (reason == kErrorReasonRateLimitExceeded || 381 reason == kErrorReasonUserRateLimitExceeded) 382 error_code_ = HTTP_SERVICE_UNAVAILABLE; 383 } 384 } 385 } 386 387 // Handle authentication failure. 388 if (error_code_ == HTTP_UNAUTHORIZED) { 389 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) { 390 // Reset re_authenticate_callback_ so Start() can be called again. 391 ReAuthenticateCallback callback = re_authenticate_callback_; 392 re_authenticate_callback_.Reset(); 393 callback.Run(this); 394 return; 395 } 396 397 OnAuthFailed(error_code_); 398 return; 399 } 400 401 // Overridden by each specialization 402 ProcessURLFetchResults(source); 403 } 404 405 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) { 406 RunCallbackOnPrematureFailure(code); 407 sender_->RequestFinished(this); 408 } 409 410 base::WeakPtr<AuthenticatedRequestInterface> 411 UrlFetchRequestBase::GetWeakPtr() { 412 return weak_ptr_factory_.GetWeakPtr(); 413 } 414 415 //============================ EntryActionRequest ============================ 416 417 EntryActionRequest::EntryActionRequest(RequestSender* sender, 418 const EntryActionCallback& callback) 419 : UrlFetchRequestBase(sender), 420 callback_(callback) { 421 DCHECK(!callback_.is_null()); 422 } 423 424 EntryActionRequest::~EntryActionRequest() {} 425 426 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) { 427 callback_.Run(GetErrorCode()); 428 OnProcessURLFetchResultsComplete(); 429 } 430 431 void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) { 432 callback_.Run(code); 433 } 434 435 //============================== GetDataRequest ============================== 436 437 GetDataRequest::GetDataRequest(RequestSender* sender, 438 const GetDataCallback& callback) 439 : UrlFetchRequestBase(sender), 440 callback_(callback), 441 weak_ptr_factory_(this) { 442 DCHECK(!callback_.is_null()); 443 } 444 445 GetDataRequest::~GetDataRequest() {} 446 447 void GetDataRequest::ParseResponse(GDataErrorCode fetch_error_code, 448 const std::string& data) { 449 DCHECK(CalledOnValidThread()); 450 451 VLOG(1) << "JSON received from " << GetURL().spec() << ": " 452 << data.size() << " bytes"; 453 ParseJson(blocking_task_runner(), 454 data, 455 base::Bind(&GetDataRequest::OnDataParsed, 456 weak_ptr_factory_.GetWeakPtr(), 457 fetch_error_code)); 458 } 459 460 void GetDataRequest::ProcessURLFetchResults(const URLFetcher* source) { 461 GDataErrorCode fetch_error_code = GetErrorCode(); 462 463 switch (fetch_error_code) { 464 case HTTP_SUCCESS: 465 case HTTP_CREATED: 466 ParseResponse(fetch_error_code, response_writer()->data()); 467 break; 468 default: 469 RunCallbackOnPrematureFailure(fetch_error_code); 470 OnProcessURLFetchResultsComplete(); 471 break; 472 } 473 } 474 475 void GetDataRequest::RunCallbackOnPrematureFailure( 476 GDataErrorCode fetch_error_code) { 477 callback_.Run(fetch_error_code, scoped_ptr<base::Value>()); 478 } 479 480 void GetDataRequest::OnDataParsed(GDataErrorCode fetch_error_code, 481 scoped_ptr<base::Value> value) { 482 DCHECK(CalledOnValidThread()); 483 484 if (!value.get()) 485 fetch_error_code = GDATA_PARSE_ERROR; 486 487 callback_.Run(fetch_error_code, value.Pass()); 488 OnProcessURLFetchResultsComplete(); 489 } 490 491 //========================= InitiateUploadRequestBase ======================== 492 493 InitiateUploadRequestBase::InitiateUploadRequestBase( 494 RequestSender* sender, 495 const InitiateUploadCallback& callback, 496 const std::string& content_type, 497 int64 content_length) 498 : UrlFetchRequestBase(sender), 499 callback_(callback), 500 content_type_(content_type), 501 content_length_(content_length) { 502 DCHECK(!callback_.is_null()); 503 DCHECK(!content_type_.empty()); 504 DCHECK_GE(content_length_, 0); 505 } 506 507 InitiateUploadRequestBase::~InitiateUploadRequestBase() {} 508 509 void InitiateUploadRequestBase::ProcessURLFetchResults( 510 const URLFetcher* source) { 511 GDataErrorCode code = GetErrorCode(); 512 513 std::string upload_location; 514 if (code == HTTP_SUCCESS) { 515 // Retrieve value of the first "Location" header. 516 source->GetResponseHeaders()->EnumerateHeader(NULL, 517 kUploadResponseLocation, 518 &upload_location); 519 } 520 521 callback_.Run(code, GURL(upload_location)); 522 OnProcessURLFetchResultsComplete(); 523 } 524 525 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure( 526 GDataErrorCode code) { 527 callback_.Run(code, GURL()); 528 } 529 530 std::vector<std::string> 531 InitiateUploadRequestBase::GetExtraRequestHeaders() const { 532 std::vector<std::string> headers; 533 headers.push_back(kUploadContentType + content_type_); 534 headers.push_back( 535 kUploadContentLength + base::Int64ToString(content_length_)); 536 return headers; 537 } 538 539 //============================ UploadRangeResponse ============================= 540 541 UploadRangeResponse::UploadRangeResponse() 542 : code(HTTP_SUCCESS), 543 start_position_received(0), 544 end_position_received(0) { 545 } 546 547 UploadRangeResponse::UploadRangeResponse(GDataErrorCode code, 548 int64 start_position_received, 549 int64 end_position_received) 550 : code(code), 551 start_position_received(start_position_received), 552 end_position_received(end_position_received) { 553 } 554 555 UploadRangeResponse::~UploadRangeResponse() { 556 } 557 558 //========================== UploadRangeRequestBase ========================== 559 560 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender, 561 const GURL& upload_url) 562 : UrlFetchRequestBase(sender), 563 upload_url_(upload_url), 564 weak_ptr_factory_(this) { 565 } 566 567 UploadRangeRequestBase::~UploadRangeRequestBase() {} 568 569 GURL UploadRangeRequestBase::GetURL() const { 570 // This is very tricky to get json from this request. To do that, &alt=json 571 // has to be appended not here but in InitiateUploadRequestBase::GetURL(). 572 return upload_url_; 573 } 574 575 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const { 576 return URLFetcher::PUT; 577 } 578 579 void UploadRangeRequestBase::ProcessURLFetchResults( 580 const URLFetcher* source) { 581 GDataErrorCode code = GetErrorCode(); 582 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders(); 583 584 if (code == HTTP_RESUME_INCOMPLETE) { 585 // Retrieve value of the first "Range" header. 586 // The Range header is appeared only if there is at least one received 587 // byte. So, initialize the positions by 0 so that the [0,0) will be 588 // returned via the |callback_| for empty data case. 589 int64 start_position_received = 0; 590 int64 end_position_received = 0; 591 std::string range_received; 592 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received); 593 if (!range_received.empty()) { // Parse the range header. 594 std::vector<net::HttpByteRange> ranges; 595 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) && 596 !ranges.empty() ) { 597 // We only care about the first start-end pair in the range. 598 // 599 // Range header represents the range inclusively, while we are treating 600 // ranges exclusively (i.e., end_position_received should be one passed 601 // the last valid index). So "+ 1" is added. 602 start_position_received = ranges[0].first_byte_position(); 603 end_position_received = ranges[0].last_byte_position() + 1; 604 } 605 } 606 // The Range header has the received data range, so the start position 607 // should be always 0. 608 DCHECK_EQ(start_position_received, 0); 609 610 OnRangeRequestComplete(UploadRangeResponse(code, 611 start_position_received, 612 end_position_received), 613 scoped_ptr<base::Value>()); 614 615 OnProcessURLFetchResultsComplete(); 616 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) { 617 // The upload is successfully done. Parse the response which should be 618 // the entry's metadata. 619 ParseJson(blocking_task_runner(), 620 response_writer()->data(), 621 base::Bind(&UploadRangeRequestBase::OnDataParsed, 622 weak_ptr_factory_.GetWeakPtr(), 623 code)); 624 } else { 625 // Failed to upload. Run callbacks to notify the error. 626 OnRangeRequestComplete( 627 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>()); 628 OnProcessURLFetchResultsComplete(); 629 } 630 } 631 632 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code, 633 scoped_ptr<base::Value> value) { 634 DCHECK(CalledOnValidThread()); 635 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS); 636 637 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass()); 638 OnProcessURLFetchResultsComplete(); 639 } 640 641 void UploadRangeRequestBase::RunCallbackOnPrematureFailure( 642 GDataErrorCode code) { 643 OnRangeRequestComplete( 644 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>()); 645 } 646 647 //========================== ResumeUploadRequestBase ========================= 648 649 ResumeUploadRequestBase::ResumeUploadRequestBase( 650 RequestSender* sender, 651 const GURL& upload_location, 652 int64 start_position, 653 int64 end_position, 654 int64 content_length, 655 const std::string& content_type, 656 const base::FilePath& local_file_path) 657 : UploadRangeRequestBase(sender, upload_location), 658 start_position_(start_position), 659 end_position_(end_position), 660 content_length_(content_length), 661 content_type_(content_type), 662 local_file_path_(local_file_path) { 663 DCHECK_LE(start_position_, end_position_); 664 } 665 666 ResumeUploadRequestBase::~ResumeUploadRequestBase() {} 667 668 std::vector<std::string> 669 ResumeUploadRequestBase::GetExtraRequestHeaders() const { 670 if (content_length_ == 0) { 671 // For uploading an empty document, just PUT an empty content. 672 DCHECK_EQ(start_position_, 0); 673 DCHECK_EQ(end_position_, 0); 674 return std::vector<std::string>(); 675 } 676 677 // The header looks like 678 // Content-Range: bytes <start_position>-<end_position>/<content_length> 679 // for example: 680 // Content-Range: bytes 7864320-8388607/13851821 681 // The header takes inclusive range, so we adjust by "end_position - 1". 682 DCHECK_GE(start_position_, 0); 683 DCHECK_GT(end_position_, 0); 684 DCHECK_GE(content_length_, 0); 685 686 std::vector<std::string> headers; 687 headers.push_back( 688 std::string(kUploadContentRange) + 689 base::Int64ToString(start_position_) + "-" + 690 base::Int64ToString(end_position_ - 1) + "/" + 691 base::Int64ToString(content_length_)); 692 return headers; 693 } 694 695 bool ResumeUploadRequestBase::GetContentFile( 696 base::FilePath* local_file_path, 697 int64* range_offset, 698 int64* range_length, 699 std::string* upload_content_type) { 700 if (start_position_ == end_position_) { 701 // No content data. 702 return false; 703 } 704 705 *local_file_path = local_file_path_; 706 *range_offset = start_position_; 707 *range_length = end_position_ - start_position_; 708 *upload_content_type = content_type_; 709 return true; 710 } 711 712 //======================== GetUploadStatusRequestBase ======================== 713 714 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender, 715 const GURL& upload_url, 716 int64 content_length) 717 : UploadRangeRequestBase(sender, upload_url), 718 content_length_(content_length) {} 719 720 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {} 721 722 std::vector<std::string> 723 GetUploadStatusRequestBase::GetExtraRequestHeaders() const { 724 // The header looks like 725 // Content-Range: bytes */<content_length> 726 // for example: 727 // Content-Range: bytes */13851821 728 DCHECK_GE(content_length_, 0); 729 730 std::vector<std::string> headers; 731 headers.push_back( 732 std::string(kUploadContentRange) + "*/" + 733 base::Int64ToString(content_length_)); 734 return headers; 735 } 736 737 //============================ DownloadFileRequestBase ========================= 738 739 DownloadFileRequestBase::DownloadFileRequestBase( 740 RequestSender* sender, 741 const DownloadActionCallback& download_action_callback, 742 const GetContentCallback& get_content_callback, 743 const ProgressCallback& progress_callback, 744 const GURL& download_url, 745 const base::FilePath& output_file_path) 746 : UrlFetchRequestBase(sender), 747 download_action_callback_(download_action_callback), 748 get_content_callback_(get_content_callback), 749 progress_callback_(progress_callback), 750 download_url_(download_url), 751 output_file_path_(output_file_path) { 752 DCHECK(!download_action_callback_.is_null()); 753 DCHECK(!output_file_path_.empty()); 754 // get_content_callback may be null. 755 } 756 757 DownloadFileRequestBase::~DownloadFileRequestBase() {} 758 759 // Overridden from UrlFetchRequestBase. 760 GURL DownloadFileRequestBase::GetURL() const { 761 return download_url_; 762 } 763 764 void DownloadFileRequestBase::GetOutputFilePath( 765 base::FilePath* local_file_path, 766 GetContentCallback* get_content_callback) { 767 // Configure so that the downloaded content is saved to |output_file_path_|. 768 *local_file_path = output_file_path_; 769 *get_content_callback = get_content_callback_; 770 } 771 772 void DownloadFileRequestBase::OnURLFetchDownloadProgress( 773 const URLFetcher* source, 774 int64 current, 775 int64 total) { 776 if (!progress_callback_.is_null()) 777 progress_callback_.Run(current, total); 778 } 779 780 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) { 781 GDataErrorCode code = GetErrorCode(); 782 783 // Take over the ownership of the the downloaded temp file. 784 base::FilePath temp_file; 785 if (code == HTTP_SUCCESS) { 786 response_writer()->DisownFile(); 787 temp_file = output_file_path_; 788 } 789 790 download_action_callback_.Run(code, temp_file); 791 OnProcessURLFetchResultsComplete(); 792 } 793 794 void DownloadFileRequestBase::RunCallbackOnPrematureFailure( 795 GDataErrorCode code) { 796 download_action_callback_.Run(code, base::FilePath()); 797 } 798 799 } // namespace google_apis 800