diff options
author | kinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-18 02:32:20 +0000 |
---|---|---|
committer | kinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-18 02:32:20 +0000 |
commit | 736f781feb0118e15842ffc1768e9f894c035c6e (patch) | |
tree | 0e476a225fd1f70824181941d27275332051e40b | |
parent | 43dcd3546ef707f3552bfbf0666381571a46bbc8 (diff) | |
download | chromium_src-736f781feb0118e15842ffc1768e9f894c035c6e.zip chromium_src-736f781feb0118e15842ffc1768e9f894c035c6e.tar.gz chromium_src-736f781feb0118e15842ffc1768e9f894c035c6e.tar.bz2 |
Remove upload_id and everything else unused in DriveUploader.
* Remove |upload_id|, |next_upload_id_|, |pending_uploads_|, and |RemoveUpload()|.
The integer ID was used to indirectly expose UploadFileInfo to DriveDownloadObserver, but we don't need it now.
* Remove unimplemented declaration of |InitiateUpload()|.
* Remove unused |FileOpenType| enum.
* Remove |UploadFileInfo::buf_len|. It is always 512KB.
* Remove |UploadFileInfo::entry|. It is almost unused.
* Remove |UploadFileInfo::start_position|. It is almost unused.
* Moved UploadFileInfo to .cc and added bunch of const's.
* Potential Fix: Change ReadSync to ReadUntilComplete, otherwise we can satisfy the WAPI requirement.
BUG=165110
TBR=tzik@chromium.org
Review URL: https://codereview.chromium.org/11592007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173628 0039d316-1c4b-4281-b951-d872f2087c98
4 files changed, 249 insertions, 389 deletions
diff --git a/chrome/browser/chromeos/drive/drive_file_system_unittest.cc b/chrome/browser/chromeos/drive/drive_file_system_unittest.cc index 0b73433..ae7c012 100644 --- a/chrome/browser/chromeos/drive/drive_file_system_unittest.cc +++ b/chrome/browser/chromeos/drive/drive_file_system_unittest.cc @@ -124,7 +124,7 @@ class FakeDriveUploader : public google_apis::DriveUploaderInterface { // Pretends that a new file was uploaded successfully, and returns the // contents of "gdata/uploaded_file.json" to the caller. - virtual int UploadNewFile( + virtual void UploadNewFile( const GURL& upload_location, const FilePath& drive_file_path, const FilePath& local_file_path, @@ -145,15 +145,12 @@ class FakeDriveUploader : public google_apis::DriveUploaderInterface { drive_file_path, local_file_path, base::Passed(&resource_entry))); - - const int kUploadId = 123; - return kUploadId; } // Pretends that an existing file ("drive/File 1.txt") was uploaded // successfully, and returns an entry for the file in // "gdata/root_feed.json" to the caller. - virtual int UploadExistingFile( + virtual void UploadExistingFile( const GURL& upload_location, const FilePath& drive_file_path, const FilePath& local_file_path, @@ -173,7 +170,7 @@ class FakeDriveUploader : public google_apis::DriveUploaderInterface { scoped_ptr<base::Value> value = google_apis::test_util::LoadJSONFile("gdata/root_feed.json"); if (!value.get()) - return -1; + return; base::DictionaryValue* as_dict = NULL; base::ListValue* entry_list = NULL; @@ -190,7 +187,7 @@ class FakeDriveUploader : public google_apis::DriveUploaderInterface { } } if (!resource_entry) - return -1; + return; base::MessageLoopProxy::current()->PostTask( FROM_HERE, @@ -199,9 +196,6 @@ class FakeDriveUploader : public google_apis::DriveUploaderInterface { drive_file_path, local_file_path, base::Passed(&resource_entry))); - - const int kUploadId = 123; - return kUploadId; } }; diff --git a/chrome/browser/google_apis/drive_uploader.cc b/chrome/browser/google_apis/drive_uploader.cc index 830b9a42..143cb12 100644 --- a/chrome/browser/google_apis/drive_uploader.cc +++ b/chrome/browser/google_apis/drive_uploader.cc @@ -8,8 +8,10 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/message_loop.h" #include "base/string_number_conversions.h" #include "chrome/browser/google_apis/drive_service_interface.h" +#include "chrome/browser/google_apis/drive_upload_mode.h" #include "chrome/browser/google_apis/gdata_wapi_parser.h" #include "content/public/browser/browser_thread.h" #include "net/base/file_stream.h" @@ -22,13 +24,6 @@ namespace { // Google Documents List API requires uploading in chunks of 512kB. const int64 kUploadChunkSize = 512 * 1024; -// Reads |bytes_to_read| bytes from |file_stream| to |buf|. -int ReadFileStreamOnBlockingPool(net::FileStream* file_stream, - scoped_refptr<net::IOBuffer> buf, - int bytes_to_read) { - return file_stream->ReadSync(buf->data(), bytes_to_read); -} - // Opens |path| with |file_stream| and returns the file size. // If failed, returns an error code in a negative value. int64 OpenFileStreamAndGetSizeOnBlockingPool(net::FileStream* file_stream, @@ -44,79 +39,135 @@ int64 OpenFileStreamAndGetSizeOnBlockingPool(net::FileStream* file_stream, namespace google_apis { -DriveUploader::DriveUploader(DriveServiceInterface* drive_service) - : drive_service_(drive_service), - next_upload_id_(0), - ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { - base::SequencedWorkerPool* blocking_pool = BrowserThread::GetBlockingPool(); - blocking_task_runner_ = blocking_pool->GetSequencedTaskRunner( - blocking_pool->GetSequenceToken()); -} +// Structure containing current upload information of file, passed between +// DriveServiceInterface methods and callbacks. +struct DriveUploader::UploadFileInfo { + UploadFileInfo(scoped_refptr<base::SequencedTaskRunner> task_runner, + UploadMode upload_mode, + const GURL& initial_upload_location, + const FilePath& drive_path, + const FilePath& local_path, + const std::string& title, + const std::string& content_type, + const UploadCompletionCallback& callback) + : upload_mode(upload_mode), + initial_upload_location(initial_upload_location), + drive_path(drive_path), + file_path(local_path), + title(title), + content_type(content_type), + completion_callback(callback), + content_length(0), + next_send_position(0), + file_stream(new net::FileStream(NULL)), + buf(new net::IOBuffer(kUploadChunkSize)), + blocking_task_runner(task_runner) { + } -DriveUploader::~DriveUploader() { - for (UploadFileInfoMap::iterator iter = pending_uploads_.begin(); - iter != pending_uploads_.end(); - ++iter) { - // FileStream must be closed on a file-access-allowed thread. - blocking_task_runner_->DeleteSoon( - FROM_HERE, iter->second->file_stream.release()); - delete iter->second; + ~UploadFileInfo() { + blocking_task_runner->DeleteSoon(FROM_HERE, file_stream.release()); } -} -int DriveUploader::UploadNewFile(const GURL& upload_location, - const FilePath& drive_file_path, - const FilePath& local_file_path, - const std::string& title, - const std::string& content_type, - const UploadCompletionCallback& callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(!upload_location.is_empty()); - DCHECK(!drive_file_path.empty()); - DCHECK(!local_file_path.empty()); - DCHECK(!title.empty()); - DCHECK(!content_type.empty()); - DCHECK(!callback.is_null()); - - scoped_ptr<UploadFileInfo> upload_file_info(new UploadFileInfo); - upload_file_info->upload_mode = UPLOAD_NEW_FILE; - upload_file_info->initial_upload_location = upload_location; - upload_file_info->drive_path = drive_file_path; - upload_file_info->file_path = local_file_path; - upload_file_info->title = title; - upload_file_info->content_type = content_type; - upload_file_info->completion_callback = callback; - return StartUploadFile(upload_file_info.Pass()); -} + // Bytes left to upload. + int64 SizeRemaining() const { + DCHECK(content_length >= next_send_position); + return content_length - next_send_position; + } -int DriveUploader::StartUploadFile( - scoped_ptr<UploadFileInfo> upload_file_info) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(upload_file_info.get()); - DCHECK_EQ(upload_file_info->upload_id, -1); - DCHECK_NE(UPLOAD_INVALID, upload_file_info->upload_mode); + // Useful for printf debugging. + std::string DebugString() const { + return "title=[" + title + + "], file_path=[" + file_path.AsUTF8Unsafe() + + "], content_type=[" + content_type + + "], content_length=[" + base::UintToString(content_length) + + "], drive_path=[" + drive_path.AsUTF8Unsafe() + + "]"; + } + + // Whether this is uploading a new file or updating an existing file. + const UploadMode upload_mode; + + // Location URL used to get |upload_location| with InitiateUpload. + const GURL initial_upload_location; + + // Final path in gdata. Looks like /special/drive/MyFolder/MyFile. + const FilePath drive_path; - const int upload_id = next_upload_id_++; - upload_file_info->upload_id = upload_id; + // The local file path of the file to be uploaded. + const FilePath file_path; - // Add upload_file_info to our internal map and take ownership. - pending_uploads_[upload_id] = upload_file_info.release(); - UploadFileInfo* info = GetUploadFileInfo(upload_id); - DVLOG(1) << "Uploading file: " << info->DebugString(); + // Title to be used for file to be uploaded. + const std::string title; - // Create a FileStream to make sure the file can be opened successfully. - info->file_stream.reset(new net::FileStream(NULL)); + // Content-Type of file. + const std::string content_type; - // Create buffer to hold upload data. The full file size may not be known at - // this point, so it may not be appropriate to use info->file_size. - info->buf_len = kUploadChunkSize; - info->buf = new net::IOBuffer(info->buf_len); + // Callback to be invoked once the upload has finished. + const UploadCompletionCallback completion_callback; + + // Location URL where file is to be uploaded to, returned from + // InitiateUpload. Used for the subsequent ResumeUpload requests. + GURL upload_location; + + // Header content-Length. + int64 content_length; + + // The start position of the contents to be sent as the next upload chunk. + int64 next_send_position; + + // For opening and reading from physical file. + // + // File operations are posted to |blocking_task_runner|, while the ownership + // of the stream is held in UI thread. At the point when this UploadFileInfo + // is destroyed, the ownership of the stream is passed to the worker pool. + // TODO(kinaba): We should switch to async API of FileStream once + // crbug.com/164312 is fixed. + scoped_ptr<net::FileStream> file_stream; + + // Holds current content to be uploaded. + const scoped_refptr<net::IOBuffer> buf; + + // Runner for net::FileStream tasks. + const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner; +}; + +DriveUploader::DriveUploader(DriveServiceInterface* drive_service) + : drive_service_(drive_service), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { + base::SequencedWorkerPool* blocking_pool = BrowserThread::GetBlockingPool(); + blocking_task_runner_ = blocking_pool->GetSequencedTaskRunner( + blocking_pool->GetSequenceToken()); +} + +DriveUploader::~DriveUploader() {} + +void DriveUploader::UploadNewFile(const GURL& upload_location, + const FilePath& drive_file_path, + const FilePath& local_file_path, + const std::string& title, + const std::string& content_type, + const UploadCompletionCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!upload_location.is_empty()); + DCHECK(!drive_file_path.empty()); + DCHECK(!local_file_path.empty()); + DCHECK(!title.empty()); + DCHECK(!content_type.empty()); + DCHECK(!callback.is_null()); - OpenFile(info, FILE_OPEN_START_UPLOAD); - return upload_id; + StartUploadFile(scoped_ptr<UploadFileInfo>(new UploadFileInfo( + blocking_task_runner_, + UPLOAD_NEW_FILE, + upload_location, + drive_file_path, + local_file_path, + title, + content_type, + callback + ))); } -int DriveUploader::UploadExistingFile( +void DriveUploader::UploadExistingFile( const GURL& upload_location, const FilePath& drive_file_path, const FilePath& local_file_path, @@ -129,207 +180,161 @@ int DriveUploader::UploadExistingFile( DCHECK(!content_type.empty()); DCHECK(!callback.is_null()); - scoped_ptr<UploadFileInfo> upload_file_info(new UploadFileInfo); - upload_file_info->upload_mode = UPLOAD_EXISTING_FILE; - upload_file_info->initial_upload_location = upload_location; - upload_file_info->drive_path = drive_file_path; - upload_file_info->file_path = local_file_path; - upload_file_info->content_type = content_type; - upload_file_info->completion_callback = callback; - return StartUploadFile(upload_file_info.Pass()); + StartUploadFile(scoped_ptr<UploadFileInfo>(new UploadFileInfo( + blocking_task_runner_, + UPLOAD_EXISTING_FILE, + upload_location, + drive_file_path, + local_file_path, + "", // title : not necessary for update of an existing file. + content_type, + callback + ))); } -DriveUploader::UploadFileInfo* DriveUploader::GetUploadFileInfo( - int upload_id) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - UploadFileInfoMap::const_iterator it = pending_uploads_.find(upload_id); - DVLOG_IF(1, it == pending_uploads_.end()) << "No upload found for id " - << upload_id; - return it != pending_uploads_.end() ? it->second : NULL; -} - -void DriveUploader::OpenFile(UploadFileInfo* upload_file_info, - FileOpenType open_type) { +void DriveUploader::StartUploadFile( + scoped_ptr<UploadFileInfo> upload_file_info) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK_NE(UPLOAD_INVALID, upload_file_info->upload_mode); + DVLOG(1) << "Uploading file: " << upload_file_info->DebugString(); - // Passing a raw net::FileStream* from upload_file_info->file_stream.get() is - // safe, because the FileStream is always deleted by posting the task to the - // same sequenced task runner. (See RemoveUpload() and ~DriveUploader()). - // That is, deletion won't happen until this task completes. + // Passing a raw net::FileStream* to the blocking pool is safe, because it is + // owned by |upload_file_info| in the reply callback. + UploadFileInfo* info_ptr = upload_file_info.get(); base::PostTaskAndReplyWithResult( blocking_task_runner_.get(), FROM_HERE, base::Bind(&OpenFileStreamAndGetSizeOnBlockingPool, - base::Unretained(upload_file_info->file_stream.get()), - upload_file_info->file_path), + info_ptr->file_stream.get(), + info_ptr->file_path), base::Bind(&DriveUploader::OpenCompletionCallback, weak_ptr_factory_.GetWeakPtr(), - open_type, - upload_file_info->upload_id)); + base::Passed(&upload_file_info))); } -void DriveUploader::OpenCompletionCallback(FileOpenType open_type, - int upload_id, - int64 file_size) { +void DriveUploader::OpenCompletionCallback( + scoped_ptr<UploadFileInfo> upload_file_info, int64 file_size) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); - if (!upload_file_info) - return; - if (file_size < 0) { - UploadFailed(upload_file_info, DRIVE_UPLOAD_ERROR_NOT_FOUND); + UploadFailed(upload_file_info.Pass(), DRIVE_UPLOAD_ERROR_NOT_FOUND); return; } - if (upload_file_info->initial_upload_location.is_empty()) { - UploadFailed(upload_file_info, DRIVE_UPLOAD_ERROR_ABORT); - return; - } + upload_file_info->content_length = file_size; // Open succeeded, initiate the upload. - upload_file_info->content_length = file_size; + UploadFileInfo* info_ptr = upload_file_info.get(); drive_service_->InitiateUpload( - InitiateUploadParams(upload_file_info->upload_mode, - upload_file_info->title, - upload_file_info->content_type, - upload_file_info->content_length, - upload_file_info->initial_upload_location, - upload_file_info->drive_path), + InitiateUploadParams(info_ptr->upload_mode, + info_ptr->title, + info_ptr->content_type, + info_ptr->content_length, + info_ptr->initial_upload_location, + info_ptr->drive_path), base::Bind(&DriveUploader::OnUploadLocationReceived, weak_ptr_factory_.GetWeakPtr(), - upload_file_info->upload_id)); + base::Passed(&upload_file_info))); } -void DriveUploader::OnUploadLocationReceived(int upload_id, - GDataErrorCode code, - const GURL& upload_location) { +void DriveUploader::OnUploadLocationReceived( + scoped_ptr<UploadFileInfo> upload_file_info, + GDataErrorCode code, + const GURL& upload_location) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); - if (!upload_file_info) - return; - DVLOG(1) << "Got upload location [" << upload_location.spec() << "] for [" << upload_file_info->title << "]"; if (code != HTTP_SUCCESS) { // TODO(achuith): Handle error codes from Google Docs server. - UploadFailed(upload_file_info, DRIVE_UPLOAD_ERROR_ABORT); + UploadFailed(upload_file_info.Pass(), DRIVE_UPLOAD_ERROR_ABORT); return; } upload_file_info->upload_location = upload_location; // Start the upload from the beginning of the file. - UploadNextChunk(upload_file_info); + UploadNextChunk(upload_file_info.Pass()); } -void DriveUploader::UploadNextChunk(UploadFileInfo* upload_file_info) { +void DriveUploader::UploadNextChunk( + scoped_ptr<UploadFileInfo> upload_file_info) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // Check that |upload_file_info| is in pending_uploads_. - DCHECK(upload_file_info == GetUploadFileInfo(upload_file_info->upload_id)); - DVLOG(1) << "Number of pending uploads=" << pending_uploads_.size(); - // Determine number of bytes to read for this upload iteration, which cannot - // exceed size of buf i.e. buf_len. + // Determine number of bytes to read for this upload iteration. const int bytes_to_read = std::min(upload_file_info->SizeRemaining(), - upload_file_info->buf_len); + kUploadChunkSize); if (bytes_to_read == 0) { - // This should only happen when the actual file size is 0. - DCHECK(upload_file_info->content_length == 0); - - upload_file_info->start_position = 0; - upload_file_info->end_position = 0; - // Skips file_stream->Read and error checks for 0-byte case. Immediately - // proceeds to ResumeUpload. - // TODO(kinaba): http://crbug.com/134814 - // Replace the following PostTask() to an direct method call. This is needed - // because we have to ResumeUpload after the previous InitiateUpload or - // ResumeUpload is completely finished; at this point, we are inside the - // callback function from the previous operation, which is not treated as - // finished yet. - base::MessageLoopProxy::current()->PostTask( + // net::FileStream doesn't allow to read 0 bytes, so directly proceed to the + // completion callback. PostTask is necessary because we have to finish + // InitiateUpload's callback before calling ResumeUpload, due to the + // implementation of OperationRegistry. (http://crbug.com/134814) + MessageLoop::current()->PostTask( FROM_HERE, - base::Bind(&DriveUploader::ResumeUpload, + base::Bind(&DriveUploader::ReadCompletionCallback, weak_ptr_factory_.GetWeakPtr(), - upload_file_info->upload_id)); + base::Passed(&upload_file_info), 0, 0)); return; } - // Passing a raw net::FileStream* from upload_file_info->file_stream.get() is - // safe. See the comment in OpenFile(). + // Passing a raw |file_stream| and |buf| to the blocking pool is safe, because + // they are owned by |upload_file_info| in the reply callback. + UploadFileInfo* info_ptr = upload_file_info.get(); base::PostTaskAndReplyWithResult( blocking_task_runner_.get(), FROM_HERE, - base::Bind(&ReadFileStreamOnBlockingPool, - upload_file_info->file_stream.get(), - upload_file_info->buf, + base::Bind(&net::FileStream::ReadUntilComplete, + base::Unretained(info_ptr->file_stream.get()), + info_ptr->buf->data(), bytes_to_read), base::Bind(&DriveUploader::ReadCompletionCallback, weak_ptr_factory_.GetWeakPtr(), - upload_file_info->upload_id, + base::Passed(&upload_file_info), bytes_to_read)); } -void DriveUploader::ReadCompletionCallback(int upload_id, - int bytes_to_read, - int bytes_read) { +void DriveUploader::ReadCompletionCallback( + scoped_ptr<UploadFileInfo> upload_file_info, + int bytes_to_read, + int bytes_read) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // Should be non-zero. FileStream::Read() returns 0 only at end-of-file, - // but we don't try to read from end-of-file. - DCHECK_NE(0, bytes_read); + DCHECK_EQ(bytes_to_read, bytes_read); DVLOG(1) << "ReadCompletionCallback bytes read=" << bytes_read; - UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); - if (!upload_file_info) - return; - if (bytes_read < 0) { LOG(ERROR) << "Error reading from file " << upload_file_info->file_path.value(); - UploadFailed(upload_file_info, DRIVE_UPLOAD_ERROR_ABORT); + UploadFailed(upload_file_info.Pass(), DRIVE_UPLOAD_ERROR_ABORT); return; } - upload_file_info->start_position = upload_file_info->end_position; - upload_file_info->end_position = - upload_file_info->start_position + bytes_read; - - ResumeUpload(upload_id); -} - -void DriveUploader::ResumeUpload(int upload_id) { - UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); - if (!upload_file_info) - return; + int64 start_position = upload_file_info->next_send_position; + upload_file_info->next_send_position += bytes_read; + int64 end_position = upload_file_info->next_send_position; + UploadFileInfo* info_ptr = upload_file_info.get(); drive_service_->ResumeUpload( - ResumeUploadParams(upload_file_info->upload_mode, - upload_file_info->start_position, - upload_file_info->end_position, - upload_file_info->content_length, - upload_file_info->content_type, - upload_file_info->buf, - upload_file_info->upload_location, - upload_file_info->drive_path), + ResumeUploadParams(info_ptr->upload_mode, + start_position, + end_position, + info_ptr->content_length, + info_ptr->content_type, + info_ptr->buf, + info_ptr->upload_location, + info_ptr->drive_path), base::Bind(&DriveUploader::OnResumeUploadResponseReceived, weak_ptr_factory_.GetWeakPtr(), - upload_file_info->upload_id)); + base::Passed(&upload_file_info))); } void DriveUploader::OnResumeUploadResponseReceived( - int upload_id, + scoped_ptr<UploadFileInfo> upload_file_info, const ResumeUploadResponse& response, scoped_ptr<ResourceEntry> entry) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); - if (!upload_file_info) - return; - const UploadMode upload_mode = upload_file_info->upload_mode; if ((upload_mode == UPLOAD_NEW_FILE && response.code == HTTP_CREATED) || (upload_mode == UPLOAD_EXISTING_FILE && response.code == HTTP_SUCCESS)) { @@ -337,15 +342,10 @@ void DriveUploader::OnResumeUploadResponseReceived( << upload_file_info->title << "]"; // Done uploading. - upload_file_info->entry = entry.Pass(); - upload_file_info->completion_callback.Run( - DRIVE_UPLOAD_OK, - upload_file_info->drive_path, - upload_file_info->file_path, - upload_file_info->entry.Pass()); - - // This will delete |upload_file_info|. - RemoveUpload(scoped_ptr<UploadFileInfo>(upload_file_info)); + upload_file_info->completion_callback.Run(DRIVE_UPLOAD_OK, + upload_file_info->drive_path, + upload_file_info->file_path, + entry.Pass()); return; } @@ -354,18 +354,17 @@ void DriveUploader::OnResumeUploadResponseReceived( // upload the next chunk. if (response.code != HTTP_RESUME_INCOMPLETE || response.start_position_received != 0 || - response.end_position_received != upload_file_info->end_position) { + response.end_position_received != upload_file_info->next_send_position) { // TODO(achuith): Handle error cases, e.g. // - when previously uploaded data wasn't received by Google Docs server, // i.e. when end_position_received < upload_file_info->end_position LOG(ERROR) << "UploadNextChunk http code=" << response.code << ", start_position_received=" << response.start_position_received << ", end_position_received=" << response.end_position_received - << ", expected end range=" << upload_file_info->end_position; - UploadFailed( - upload_file_info, - response.code == HTTP_FORBIDDEN ? - DRIVE_UPLOAD_ERROR_NO_SPACE : DRIVE_UPLOAD_ERROR_ABORT); + << ", expected end range=" << upload_file_info->next_send_position; + UploadFailed(upload_file_info.Pass(), + response.code == HTTP_FORBIDDEN ? + DRIVE_UPLOAD_ERROR_NO_SPACE : DRIVE_UPLOAD_ERROR_ABORT); return; } @@ -374,57 +373,19 @@ void DriveUploader::OnResumeUploadResponseReceived( << " for [" << upload_file_info->title << "]"; // Continue uploading. - UploadNextChunk(upload_file_info); + UploadNextChunk(upload_file_info.Pass()); } -void DriveUploader::UploadFailed(UploadFileInfo* upload_file_info, +void DriveUploader::UploadFailed(scoped_ptr<UploadFileInfo> upload_file_info, DriveUploadError error) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); LOG(ERROR) << "Upload failed " << upload_file_info->DebugString(); - upload_file_info->completion_callback.Run( - error, - upload_file_info->drive_path, - upload_file_info->file_path, - upload_file_info->entry.Pass()); - - // This will delete |upload_file_info|. - RemoveUpload(scoped_ptr<UploadFileInfo>(upload_file_info)); -} - -void DriveUploader::RemoveUpload(scoped_ptr<UploadFileInfo> upload_file_info) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // FileStream must be closed on a file-access-allowed thread. - blocking_task_runner_->DeleteSoon( - FROM_HERE, upload_file_info->file_stream.release()); - pending_uploads_.erase(upload_file_info->upload_id); -} - -DriveUploader::UploadFileInfo::UploadFileInfo() - : upload_id(-1), - content_length(0), - upload_mode(UPLOAD_INVALID), - file_stream(NULL), - buf_len(0), - start_position(0), - end_position(0) { -} - -DriveUploader::UploadFileInfo::~UploadFileInfo() { } - -int64 DriveUploader::UploadFileInfo::SizeRemaining() const { - DCHECK(content_length >= end_position); - return content_length - end_position; -} - -std::string DriveUploader::UploadFileInfo::DebugString() const { - return "title=[" + title + - "], file_path=[" + file_path.AsUTF8Unsafe() + - "], content_type=[" + content_type + - "], content_length=[" + base::UintToString(content_length) + - "], drive_path=[" + drive_path.AsUTF8Unsafe() + - "]"; + upload_file_info->completion_callback.Run(error, + upload_file_info->drive_path, + upload_file_info->file_path, + scoped_ptr<ResourceEntry>()); } } // namespace google_apis diff --git a/chrome/browser/google_apis/drive_uploader.h b/chrome/browser/google_apis/drive_uploader.h index a08195f..b2f5000 100644 --- a/chrome/browser/google_apis/drive_uploader.h +++ b/chrome/browser/google_apis/drive_uploader.h @@ -5,20 +5,17 @@ #ifndef CHROME_BROWSER_GOOGLE_APIS_DRIVE_UPLOADER_H_ #define CHROME_BROWSER_GOOGLE_APIS_DRIVE_UPLOADER_H_ -#include <map> #include <string> #include "base/basictypes.h" +#include "base/callback_forward.h" #include "base/memory/weak_ptr.h" #include "base/threading/sequenced_worker_pool.h" #include "chrome/browser/google_apis/drive_upload_error.h" -#include "chrome/browser/google_apis/drive_upload_mode.h" #include "chrome/browser/google_apis/gdata_errorcode.h" #include "chrome/browser/google_apis/gdata_wapi_parser.h" -#include "net/base/file_stream.h" -#include "net/base/completion_callback.h" -#include "net/base/file_stream.h" +class FilePath; class GURL; namespace google_apis { @@ -57,21 +54,21 @@ class DriveUploaderInterface { // callback: // Called when an upload is done regardless of it was successful or not. // Must not be null. - virtual int UploadNewFile(const GURL& upload_location, - const FilePath& drive_file_path, - const FilePath& local_file_path, - const std::string& title, - const std::string& content_type, - const UploadCompletionCallback& callback) = 0; + virtual void UploadNewFile(const GURL& upload_location, + const FilePath& drive_file_path, + const FilePath& local_file_path, + const std::string& title, + const std::string& content_type, + const UploadCompletionCallback& callback) = 0; // Uploads an existing file (a file that already exists on Drive). // // See comments at UploadNewFile() about common parameters. - virtual int UploadExistingFile(const GURL& upload_location, - const FilePath& drive_file_path, - const FilePath& local_file_path, - const std::string& content_type, - const UploadCompletionCallback& callback) = 0; + virtual void UploadExistingFile(const GURL& upload_location, + const FilePath& drive_file_path, + const FilePath& local_file_path, + const std::string& content_type, + const UploadCompletionCallback& callback) = 0; }; class DriveUploader : public DriveUploaderInterface { @@ -80,13 +77,13 @@ class DriveUploader : public DriveUploaderInterface { virtual ~DriveUploader(); // DriveUploaderInterface overrides. - virtual int UploadNewFile(const GURL& upload_location, - const FilePath& drive_file_path, - const FilePath& local_file_path, - const std::string& title, - const std::string& content_type, - const UploadCompletionCallback& callback) OVERRIDE; - virtual int UploadExistingFile( + virtual void UploadNewFile(const GURL& upload_location, + const FilePath& drive_file_path, + const FilePath& local_file_path, + const std::string& title, + const std::string& content_type, + const UploadCompletionCallback& callback) OVERRIDE; + virtual void UploadExistingFile( const GURL& upload_location, const FilePath& drive_file_path, const FilePath& local_file_path, @@ -94,138 +91,48 @@ class DriveUploader : public DriveUploaderInterface { const UploadCompletionCallback& callback) OVERRIDE; private: - // Structure containing current upload information of file, passed between - // DriveServiceInterface methods and callbacks. - struct UploadFileInfo { - // To be able to access UploadFileInfo from tests. - UploadFileInfo(); - ~UploadFileInfo(); - - // Bytes left to upload. - int64 SizeRemaining() const; - - // Useful for printf debugging. - std::string DebugString() const; - - int upload_id; // id of this upload. - FilePath file_path; // The path of the file to be uploaded. - - // TODO(zelirag, achuith): Make this string16. - std::string title; // Title to be used for file to be uploaded. - std::string content_type; // Content-Type of file. - int64 content_length; // Header content-Length. - - UploadMode upload_mode; - - // Location URL used to get |upload_location| with InitiateUpload. - GURL initial_upload_location; - - // Location URL where file is to be uploaded to, returned from - // InitiateUpload. Used for the subsequent ResumeUpload requests. - GURL upload_location; - - // Final path in gdata. Looks like /special/drive/MyFolder/MyFile. - FilePath drive_path; - - // TODO(achuith): Use generic stream object after FileStream is refactored - // to extend a generic stream. - // - // TODO(kinaba): We should switch to async API of FileStream once - // crbug.com/164312 is fixed. - // - // For opening and reading from physical file. - // Every file operation is posted to the sequenced worker pool, while the - // ownership of |file_stream| is held by DriveUploader in UI thread. At the - // point when DriveUploader deletes UploadFileInfo, it passes the ownership - // of the stream to sequenced worker pool. - scoped_ptr<net::FileStream> file_stream; - scoped_refptr<net::IOBuffer> buf; // Holds current content to be uploaded. - // Size of |buf|, max is 512KB; Google Docs requires size of each upload - // chunk to be a multiple of 512KB. - int64 buf_len; - - // The start and the end position of the range of contents currently stored - // in |buf|. Note that end_position is exclusive, so start_position = 0 and - // end_position = 9 means 9 bytes. - int64 start_position; - int64 end_position; - - // Will be set once the upload is complete. - scoped_ptr<ResourceEntry> entry; - - // Callback to be invoked once the upload has finished. - UploadCompletionCallback completion_callback; - }; - - // Indicates step in which we try to open a file. - // Retrying happens in FILE_OPEN_UPDATE_UPLOAD step. - enum FileOpenType { - FILE_OPEN_START_UPLOAD, - FILE_OPEN_UPDATE_UPLOAD - }; - - // Lookup UploadFileInfo* in pending_uploads_. - UploadFileInfo* GetUploadFileInfo(int upload_id) const; - - // Open the file. - void OpenFile(UploadFileInfo* upload_file_info, FileOpenType open_type); + struct UploadFileInfo; + + // Starts uploading a file with |upload_file_info|. + void StartUploadFile(scoped_ptr<UploadFileInfo> upload_file_info); // net::FileStream::Open completion callback. The result of the file open // operation is passed as |result|, and the size is stored in |file_size|. - void OpenCompletionCallback(FileOpenType open_type, - int upload_id, + void OpenCompletionCallback(scoped_ptr<UploadFileInfo> upload_file_info, int64 file_size); // DriveService callback for InitiateUpload. - void OnUploadLocationReceived(int upload_id, + void OnUploadLocationReceived(scoped_ptr<UploadFileInfo> upload_file_info, GDataErrorCode code, const GURL& upload_location); // Uploads the next chunk of data from the file. - void UploadNextChunk(UploadFileInfo* upload_file_info); + void UploadNextChunk(scoped_ptr<UploadFileInfo> upload_file_info); // net::FileStream::Read completion callback. - void ReadCompletionCallback(int upload_id, + void ReadCompletionCallback(scoped_ptr<UploadFileInfo> upload_file_info, int bytes_to_read, int bytes_read); // Calls DriveService's ResumeUpload with the current upload info. - void ResumeUpload(int upload_id); + void ResumeUpload(scoped_ptr<UploadFileInfo> upload_file_info, + int bytes_to_send); // DriveService callback for ResumeUpload. void OnResumeUploadResponseReceived( - int upload_id, + scoped_ptr<UploadFileInfo> upload_file_info, const ResumeUploadResponse& response, scoped_ptr<ResourceEntry> entry); - // Initiate the upload. - void InitiateUpload(UploadFileInfo* uploader_file_info); - // Handle failed uploads. - void UploadFailed(UploadFileInfo* upload_file_info, + void UploadFailed(scoped_ptr<UploadFileInfo> upload_file_info, DriveUploadError error); - // Removes |upload_file_info| from UploadFileInfoMap |pending_uploads_|. - // After its removal from the map, |upload_file_info| is deleted. - void RemoveUpload(scoped_ptr<UploadFileInfo> upload_file_info); - - // Starts uploading a file with |upload_file_info|. Returns a new upload - // ID assigned to |upload_file_info|. |upload_file_info| is added to - // |pending_uploads_map_|. - int StartUploadFile(scoped_ptr<UploadFileInfo> upload_file_info); - // Pointers to DriveServiceInterface object owned by DriveSystemService. // The lifetime of this object is guaranteed to exceed that of the // DriveUploader instance. DriveServiceInterface* drive_service_; - int next_upload_id_; // id counter. - - typedef std::map<int, UploadFileInfo*> UploadFileInfoMap; - // Upload file infos added to the map are deleted either in |RemoveUpload| or - // in DriveUploader dtor (i.e. we can assume |this| takes their ownership). - UploadFileInfoMap pending_uploads_; - // TaskRunner for opening, reading, and closing files. scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; diff --git a/chrome/browser/sync_file_system/drive_file_sync_client_unittest.cc b/chrome/browser/sync_file_system/drive_file_sync_client_unittest.cc index 7f93dcf..9c92d880 100644 --- a/chrome/browser/sync_file_system/drive_file_sync_client_unittest.cc +++ b/chrome/browser/sync_file_system/drive_file_sync_client_unittest.cc @@ -45,7 +45,7 @@ class FakeDriveUploader : public google_apis::DriveUploaderInterface { // Pretends that a new file was uploaded successfully, and returns the // contents of "gdata/file_entry.json" to the caller. - virtual int UploadNewFile( + virtual void UploadNewFile( const GURL& upload_location, const FilePath& drive_file_path, const FilePath& local_file_path, @@ -67,13 +67,12 @@ class FakeDriveUploader : public google_apis::DriveUploaderInterface { drive_file_path, local_file_path, base::Passed(&file_entry))); - return 1; // Return dummy upload ID. } // Pretends that an existing file ("file:resource_id") was uploaded // successfully, and returns the contents of "gdata/file_entry.json" to the // caller. - virtual int UploadExistingFile( + virtual void UploadExistingFile( const GURL& upload_location, const FilePath& drive_file_path, const FilePath& local_file_path, @@ -94,7 +93,6 @@ class FakeDriveUploader : public google_apis::DriveUploaderInterface { drive_file_path, local_file_path, base::Passed(&file_entry))); - return 1; // Return dummy upload ID. } }; |