12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/two_phase_uploader.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/basictypes.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/task_runner.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_errors.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/http/http_response_headers.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_fetcher.h" 13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request_status.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Header sent on initial request to start the two phase upload process. 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char* kStartHeader = "x-goog-resumable: start"; 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Header returned on initial response with URL to use for the second phase. 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char* kLocationHeader = "Location"; 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char* kUploadContentType = "application/octet-stream"; 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 26b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class TwoPhaseUploaderImpl : public net::URLFetcherDelegate, 27b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) public TwoPhaseUploader { 28b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) public: 29b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) TwoPhaseUploaderImpl(net::URLRequestContextGetter* url_request_context_getter, 30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::TaskRunner* file_task_runner, 31b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const GURL& base_url, 32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const std::string& metadata, 33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const base::FilePath& file_path, 34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const ProgressCallback& progress_callback, 35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const FinishCallback& finish_callback); 36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual ~TwoPhaseUploaderImpl(); 37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Begins the upload process. 39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual void Start() OVERRIDE; 40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // net::URLFetcherDelegate implementation: 42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; 43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual void OnURLFetchUploadProgress(const net::URLFetcher* source, 44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int64 current, 45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int64 total) OVERRIDE; 46b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) private: 48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void UploadMetadata(); 49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void UploadFile(); 50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void Finish(int net_error, int response_code, const std::string& response); 51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 52b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) State state_; 53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; 54b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) scoped_refptr<base::TaskRunner> file_task_runner_; 55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) GURL base_url_; 56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) GURL upload_url_; 57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) std::string metadata_; 58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const base::FilePath file_path_; 59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ProgressCallback progress_callback_; 60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) FinishCallback finish_callback_; 61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) scoped_ptr<net::URLFetcher> url_fetcher_; 63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(TwoPhaseUploaderImpl); 65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}; 66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TwoPhaseUploaderImpl::TwoPhaseUploaderImpl( 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequestContextGetter* url_request_context_getter, 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TaskRunner* file_task_runner, 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GURL& base_url, 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& metadata, 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& file_path, 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ProgressCallback& progress_callback, 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const FinishCallback& finish_callback) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : state_(STATE_NONE), 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_request_context_getter_(url_request_context_getter), 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_task_runner_(file_task_runner), 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base_url_(base_url), 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) metadata_(metadata), 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_path_(file_path), 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) progress_callback_(progress_callback), 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) finish_callback_(finish_callback) { 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TwoPhaseUploaderImpl::~TwoPhaseUploaderImpl() { 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void TwoPhaseUploaderImpl::Start() { 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(STATE_NONE, state_); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UploadMetadata(); 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void TwoPhaseUploaderImpl::OnURLFetchComplete(const net::URLFetcher* source) { 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequestStatus status = source->GetStatus(); 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int response_code = source->GetResponseCode(); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << __FUNCTION__ << " " << source->GetURL().spec() 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << " " << status.status() << " " << response_code; 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!status.is_success()) { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "URLFetcher failed, status=" << status.status() 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << " err=" << status.error(); 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Finish(status.error(), response_code, std::string()); 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string response; 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source->GetResponseAsString(&response); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (state_) { 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case UPLOAD_METADATA: 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (response_code != 201) { 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Invalid response to initial request: " 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << response_code; 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Finish(net::OK, response_code, response); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string location; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!source->GetResponseHeaders()->EnumerateHeader( 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NULL, kLocationHeader, &location)) { 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "no location header"; 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Finish(net::OK, response_code, std::string()); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "upload location: " << location; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) upload_url_ = GURL(location); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UploadFile(); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case UPLOAD_FILE: 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (response_code != 200) { 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Invalid response to upload request: " 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << response_code; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = STATE_SUCCESS; 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Finish(net::OK, response_code, response); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void TwoPhaseUploaderImpl::OnURLFetchUploadProgress( 150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const net::URLFetcher* source, 151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int64 current, 152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int64 total) { 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(3) << __FUNCTION__ << " " << source->GetURL().spec() 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << " " << current << "/" << total; 1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (state_ == UPLOAD_FILE && !progress_callback_.is_null()) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) progress_callback_.Run(current, total); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void TwoPhaseUploaderImpl::UploadMetadata() { 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = UPLOAD_METADATA; 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_fetcher_.reset(net::URLFetcher::Create(base_url_, net::URLFetcher::POST, 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this)); 165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) url_fetcher_->SetRequestContext(url_request_context_getter_.get()); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_fetcher_->SetExtraRequestHeaders(kStartHeader); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_fetcher_->SetUploadData(kUploadContentType, metadata_); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_fetcher_->Start(); 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 171b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void TwoPhaseUploaderImpl::UploadFile() { 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = UPLOAD_FILE; 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_fetcher_.reset(net::URLFetcher::Create(upload_url_, net::URLFetcher::PUT, 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this)); 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) url_fetcher_->SetRequestContext(url_request_context_getter_.get()); 178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) url_fetcher_->SetUploadFilePath( 179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) kUploadContentType, file_path_, 0, kuint64max, file_task_runner_); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_fetcher_->Start(); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 183b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void TwoPhaseUploaderImpl::Finish(int net_error, 184b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int response_code, 185b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const std::string& response) { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) finish_callback_.Run(state_, net_error, response_code, response); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 189b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 190b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} // namespace 191b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 192b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// static 193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TwoPhaseUploaderFactory* TwoPhaseUploader::factory_ = NULL; 194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// static 196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)TwoPhaseUploader* TwoPhaseUploader::Create( 197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) net::URLRequestContextGetter* url_request_context_getter, 198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::TaskRunner* file_task_runner, 199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const GURL& base_url, 200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const std::string& metadata, 201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const base::FilePath& file_path, 202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const ProgressCallback& progress_callback, 203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const FinishCallback& finish_callback) { 204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (!TwoPhaseUploader::factory_) 205b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return new TwoPhaseUploaderImpl( 206b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) url_request_context_getter, file_task_runner, base_url, metadata, 207b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) file_path, progress_callback, finish_callback); 208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return TwoPhaseUploader::factory_->CreateTwoPhaseUploader( 209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) url_request_context_getter, file_task_runner, base_url, metadata, 210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) file_path, progress_callback, finish_callback); 211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 212