diff options
Diffstat (limited to 'chrome/browser/safe_browsing/two_phase_uploader.cc')
-rw-r--r-- | chrome/browser/safe_browsing/two_phase_uploader.cc | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/chrome/browser/safe_browsing/two_phase_uploader.cc b/chrome/browser/safe_browsing/two_phase_uploader.cc new file mode 100644 index 0000000..9b6165e --- /dev/null +++ b/chrome/browser/safe_browsing/two_phase_uploader.cc @@ -0,0 +1,146 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/safe_browsing/two_phase_uploader.h" + +#include "base/bind.h" +#include "base/task_runner.h" +#include "net/base/net_errors.h" +#include "net/http/http_response_headers.h" +#include "net/url_request/url_fetcher.h" +#include "net/url_request/url_request_status.h" + +namespace { + +// Header sent on initial request to start the two phase upload process. +const char* kStartHeader = "x-goog-resumable: start"; + +// Header returned on initial response with URL to use for the second phase. +const char* kLocationHeader = "Location"; + +const char* kUploadContentType = "application/octet-stream"; + +} // namespace + +TwoPhaseUploader::TwoPhaseUploader( + net::URLRequestContextGetter* url_request_context_getter, + base::TaskRunner* file_task_runner, + const GURL& base_url, + const std::string& metadata, + const base::FilePath& file_path, + const ProgressCallback& progress_callback, + const FinishCallback& finish_callback) + : state_(STATE_NONE), + url_request_context_getter_(url_request_context_getter), + file_task_runner_(file_task_runner), + base_url_(base_url), + metadata_(metadata), + file_path_(file_path), + progress_callback_(progress_callback), + finish_callback_(finish_callback) { +} + +TwoPhaseUploader::~TwoPhaseUploader() { + DCHECK(CalledOnValidThread()); +} + +void TwoPhaseUploader::Start() { + DCHECK(CalledOnValidThread()); + DCHECK_EQ(STATE_NONE, state_); + + UploadMetadata(); +} + +void TwoPhaseUploader::OnURLFetchComplete(const net::URLFetcher* source) { + DCHECK(CalledOnValidThread()); + net::URLRequestStatus status = source->GetStatus(); + int response_code = source->GetResponseCode(); + + DVLOG(1) << __FUNCTION__ << " " << source->GetURL().spec() + << " " << status.status() << " " << response_code; + + if (!status.is_success()) { + LOG(ERROR) << "URLFetcher failed, status=" << status.status() + << " err=" << status.error(); + Finish(status.error(), response_code, ""); + return; + } + + std::string response; + source->GetResponseAsString(&response); + + switch (state_) { + case UPLOAD_METADATA: + { + if (response_code != 201) { + LOG(ERROR) << "Invalid response to initial request: " + << response_code; + Finish(net::OK, response_code, response); + return; + } + std::string location; + if (!source->GetResponseHeaders()->EnumerateHeader( + NULL, kLocationHeader, &location)) { + LOG(ERROR) << "no location header"; + Finish(net::OK, response_code, ""); + return; + } + DVLOG(1) << "upload location: " << location; + upload_url_ = GURL(location); + UploadFile(); + break; + } + case UPLOAD_FILE: + if (response_code != 200) { + LOG(ERROR) << "Invalid response to upload request: " + << response_code; + } else { + state_ = STATE_SUCCESS; + } + Finish(net::OK, response_code, response); + return; + default: + NOTREACHED(); + }; +} + +void TwoPhaseUploader::OnURLFetchUploadProgress(const net::URLFetcher* source, + int64 current, int64 total) { + DCHECK(CalledOnValidThread()); + DVLOG(3) << __FUNCTION__ << " " << source->GetURL().spec() + << " " << current << "/" << total; + if (state_ == UPLOAD_FILE) + progress_callback_.Run(current, total); +} + +void TwoPhaseUploader::UploadMetadata() { + DCHECK(CalledOnValidThread()); + state_ = UPLOAD_METADATA; + url_fetcher_.reset(net::URLFetcher::Create(base_url_, net::URLFetcher::POST, + this)); + url_fetcher_->SetRequestContext(url_request_context_getter_); + url_fetcher_->SetExtraRequestHeaders(kStartHeader); + url_fetcher_->SetUploadData(kUploadContentType, metadata_); + url_fetcher_->Start(); +} + +void TwoPhaseUploader::UploadFile() { + DCHECK(CalledOnValidThread()); + state_ = UPLOAD_FILE; + + url_fetcher_.reset(net::URLFetcher::Create(upload_url_, net::URLFetcher::PUT, + this)); + url_fetcher_->SetRequestContext(url_request_context_getter_); + url_fetcher_->SetUploadFilePath(kUploadContentType, + file_path_, + file_task_runner_); + url_fetcher_->Start(); +} + +void TwoPhaseUploader::Finish(int net_error, + int response_code, + const std::string& response) { + DCHECK(CalledOnValidThread()); + finish_callback_.Run(state_, net_error, response_code, response); +} |