Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / safe_browsing / two_phase_uploader.cc
blobaafecece4019e3dfae3eedf672e681aab0ed85a1
1 // Copyright 2013 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.
5 #include "chrome/browser/safe_browsing/two_phase_uploader.h"
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/task_runner.h"
10 #include "net/base/net_errors.h"
11 #include "net/http/http_response_headers.h"
12 #include "net/url_request/url_fetcher.h"
13 #include "net/url_request/url_fetcher_delegate.h"
14 #include "net/url_request/url_request_status.h"
16 namespace {
18 // Header sent on initial request to start the two phase upload process.
19 const char* kStartHeader = "x-goog-resumable: start";
21 // Header returned on initial response with URL to use for the second phase.
22 const char* kLocationHeader = "Location";
24 const char* kUploadContentType = "application/octet-stream";
26 class TwoPhaseUploaderImpl : public net::URLFetcherDelegate,
27 public TwoPhaseUploader {
28 public:
29 TwoPhaseUploaderImpl(net::URLRequestContextGetter* url_request_context_getter,
30 base::TaskRunner* file_task_runner,
31 const GURL& base_url,
32 const std::string& metadata,
33 const base::FilePath& file_path,
34 const ProgressCallback& progress_callback,
35 const FinishCallback& finish_callback);
36 ~TwoPhaseUploaderImpl() override;
38 // Begins the upload process.
39 void Start() override;
41 // net::URLFetcherDelegate implementation:
42 void OnURLFetchComplete(const net::URLFetcher* source) override;
43 void OnURLFetchUploadProgress(const net::URLFetcher* source,
44 int64 current,
45 int64 total) override;
47 private:
48 void UploadMetadata();
49 void UploadFile();
50 void Finish(int net_error, int response_code, const std::string& response);
52 State state_;
53 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
54 scoped_refptr<base::TaskRunner> file_task_runner_;
55 GURL base_url_;
56 GURL upload_url_;
57 std::string metadata_;
58 const base::FilePath file_path_;
59 ProgressCallback progress_callback_;
60 FinishCallback finish_callback_;
62 scoped_ptr<net::URLFetcher> url_fetcher_;
64 DISALLOW_COPY_AND_ASSIGN(TwoPhaseUploaderImpl);
67 TwoPhaseUploaderImpl::TwoPhaseUploaderImpl(
68 net::URLRequestContextGetter* url_request_context_getter,
69 base::TaskRunner* file_task_runner,
70 const GURL& base_url,
71 const std::string& metadata,
72 const base::FilePath& file_path,
73 const ProgressCallback& progress_callback,
74 const FinishCallback& finish_callback)
75 : state_(STATE_NONE),
76 url_request_context_getter_(url_request_context_getter),
77 file_task_runner_(file_task_runner),
78 base_url_(base_url),
79 metadata_(metadata),
80 file_path_(file_path),
81 progress_callback_(progress_callback),
82 finish_callback_(finish_callback) {
85 TwoPhaseUploaderImpl::~TwoPhaseUploaderImpl() {
86 DCHECK(CalledOnValidThread());
89 void TwoPhaseUploaderImpl::Start() {
90 DCHECK(CalledOnValidThread());
91 DCHECK_EQ(STATE_NONE, state_);
93 UploadMetadata();
96 void TwoPhaseUploaderImpl::OnURLFetchComplete(const net::URLFetcher* source) {
97 DCHECK(CalledOnValidThread());
98 net::URLRequestStatus status = source->GetStatus();
99 int response_code = source->GetResponseCode();
101 DVLOG(1) << __FUNCTION__ << " " << source->GetURL().spec()
102 << " " << status.status() << " " << response_code;
104 if (!status.is_success()) {
105 LOG(ERROR) << "URLFetcher failed, status=" << status.status()
106 << " err=" << status.error();
107 Finish(status.error(), response_code, std::string());
108 return;
111 std::string response;
112 source->GetResponseAsString(&response);
114 switch (state_) {
115 case UPLOAD_METADATA:
117 if (response_code != 201) {
118 LOG(ERROR) << "Invalid response to initial request: "
119 << response_code;
120 Finish(net::OK, response_code, response);
121 return;
123 std::string location;
124 if (!source->GetResponseHeaders()->EnumerateHeader(
125 NULL, kLocationHeader, &location)) {
126 LOG(ERROR) << "no location header";
127 Finish(net::OK, response_code, std::string());
128 return;
130 DVLOG(1) << "upload location: " << location;
131 upload_url_ = GURL(location);
132 UploadFile();
133 break;
135 case UPLOAD_FILE:
136 if (response_code != 200) {
137 LOG(ERROR) << "Invalid response to upload request: "
138 << response_code;
139 } else {
140 state_ = STATE_SUCCESS;
142 Finish(net::OK, response_code, response);
143 return;
144 default:
145 NOTREACHED();
149 void TwoPhaseUploaderImpl::OnURLFetchUploadProgress(
150 const net::URLFetcher* source,
151 int64 current,
152 int64 total) {
153 DCHECK(CalledOnValidThread());
154 DVLOG(3) << __FUNCTION__ << " " << source->GetURL().spec()
155 << " " << current << "/" << total;
156 if (state_ == UPLOAD_FILE && !progress_callback_.is_null())
157 progress_callback_.Run(current, total);
160 void TwoPhaseUploaderImpl::UploadMetadata() {
161 DCHECK(CalledOnValidThread());
162 state_ = UPLOAD_METADATA;
163 url_fetcher_ =
164 net::URLFetcher::Create(base_url_, net::URLFetcher::POST, this);
165 url_fetcher_->SetRequestContext(url_request_context_getter_.get());
166 url_fetcher_->SetExtraRequestHeaders(kStartHeader);
167 url_fetcher_->SetUploadData(kUploadContentType, metadata_);
168 url_fetcher_->Start();
171 void TwoPhaseUploaderImpl::UploadFile() {
172 DCHECK(CalledOnValidThread());
173 state_ = UPLOAD_FILE;
175 url_fetcher_ =
176 net::URLFetcher::Create(upload_url_, net::URLFetcher::PUT, this);
177 url_fetcher_->SetRequestContext(url_request_context_getter_.get());
178 url_fetcher_->SetUploadFilePath(
179 kUploadContentType, file_path_, 0, kuint64max, file_task_runner_);
180 url_fetcher_->Start();
183 void TwoPhaseUploaderImpl::Finish(int net_error,
184 int response_code,
185 const std::string& response) {
186 DCHECK(CalledOnValidThread());
187 finish_callback_.Run(state_, net_error, response_code, response);
190 } // namespace
192 // static
193 TwoPhaseUploaderFactory* TwoPhaseUploader::factory_ = NULL;
195 // static
196 TwoPhaseUploader* TwoPhaseUploader::Create(
197 net::URLRequestContextGetter* url_request_context_getter,
198 base::TaskRunner* file_task_runner,
199 const GURL& base_url,
200 const std::string& metadata,
201 const base::FilePath& file_path,
202 const ProgressCallback& progress_callback,
203 const FinishCallback& finish_callback) {
204 if (!TwoPhaseUploader::factory_)
205 return new TwoPhaseUploaderImpl(
206 url_request_context_getter, file_task_runner, base_url, metadata,
207 file_path, progress_callback, finish_callback);
208 return TwoPhaseUploader::factory_->CreateTwoPhaseUploader(
209 url_request_context_getter, file_task_runner, base_url, metadata,
210 file_path, progress_callback, finish_callback);