Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/gdata/gdata_uploader.h" | 5 #include "chrome/browser/chromeos/gdata/gdata_uploader.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 | 32 |
| 33 GDataUploader::GDataUploader(GDataFileSystem* file_system) | 33 GDataUploader::GDataUploader(GDataFileSystem* file_system) |
| 34 : file_system_(file_system), | 34 : file_system_(file_system), |
| 35 next_upload_id_(0), | 35 next_upload_id_(0), |
| 36 ALLOW_THIS_IN_INITIALIZER_LIST(uploader_factory_(this)) { | 36 ALLOW_THIS_IN_INITIALIZER_LIST(uploader_factory_(this)) { |
| 37 } | 37 } |
| 38 | 38 |
| 39 GDataUploader::~GDataUploader() { | 39 GDataUploader::~GDataUploader() { |
| 40 } | 40 } |
| 41 | 41 |
| 42 void GDataUploader::UploadFile(UploadFileInfo* upload_file_info) { | 42 int GDataUploader::UploadFile(scoped_ptr<UploadFileInfo> upload_file_info) { |
| 43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 44 DCHECK(upload_file_info); | 44 DCHECK(upload_file_info.get()); |
| 45 DCHECK_EQ(upload_file_info->upload_id, -1); | 45 DCHECK_EQ(upload_file_info->upload_id, -1); |
| 46 DCHECK(!upload_file_info->file_path.empty()); | |
| 47 DCHECK_NE(upload_file_info->file_size, 0); | |
| 48 DCHECK(!upload_file_info->gdata_path.empty()); | |
| 49 DCHECK(!upload_file_info->title.empty()); | |
| 50 DCHECK(!upload_file_info->content_type.empty()); | |
| 46 | 51 |
| 47 upload_file_info->upload_id = next_upload_id_++; | 52 const int upload_id = next_upload_id_++; |
| 53 upload_file_info->upload_id = upload_id; | |
| 48 // Add upload_file_info to our internal map and take ownership. | 54 // Add upload_file_info to our internal map and take ownership. |
| 49 pending_uploads_[upload_file_info->upload_id] = upload_file_info; | 55 pending_uploads_[upload_id] = upload_file_info.release(); |
| 50 DVLOG(1) << "Uploading file: " << upload_file_info->DebugString(); | 56 |
| 57 UploadFileInfo* info = GetUploadFileInfo(upload_id); | |
| 58 DVLOG(1) << "Uploading file: " << info->DebugString(); | |
| 51 | 59 |
| 52 // Create a FileStream to make sure the file can be opened successfully. | 60 // Create a FileStream to make sure the file can be opened successfully. |
| 53 upload_file_info->file_stream = new net::FileStream(NULL); | 61 info->file_stream = new net::FileStream(NULL); |
| 54 | 62 |
| 55 // Create buffer to hold upload data. | 63 // Create buffer to hold upload data. |
| 56 upload_file_info->buf_len = std::min(upload_file_info->file_size, | 64 info->buf_len = std::min(info->file_size, kUploadChunkSize); |
| 57 kUploadChunkSize); | 65 info->buf = new net::IOBuffer(info->buf_len); |
| 58 upload_file_info->buf = new net::IOBuffer(upload_file_info->buf_len); | |
| 59 | 66 |
| 60 OpenFile(upload_file_info); | 67 OpenFile(info); |
| 68 return upload_id; | |
| 61 } | 69 } |
| 62 | 70 |
| 63 void GDataUploader::UpdateUpload(int upload_id, | 71 void GDataUploader::UpdateUpload(int upload_id, |
| 64 content::DownloadItem* download) { | 72 content::DownloadItem* download) { |
| 65 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); | 73 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); |
| 66 if (!upload_file_info) | 74 if (!upload_file_info) |
| 67 return; | 75 return; |
| 68 | 76 |
| 69 const int64 file_size = download->GetReceivedBytes(); | 77 const int64 file_size = download->GetReceivedBytes(); |
| 70 | 78 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 94 if (upload_file_info->file_path != download->GetFullPath()) | 102 if (upload_file_info->file_path != download->GetFullPath()) |
| 95 upload_file_info->num_file_open_tries = 0; | 103 upload_file_info->num_file_open_tries = 0; |
| 96 upload_file_info->file_path = download->GetFullPath(); | 104 upload_file_info->file_path = download->GetFullPath(); |
| 97 // Disallow further retries. | 105 // Disallow further retries. |
| 98 upload_file_info->should_retry_file_open = false; | 106 upload_file_info->should_retry_file_open = false; |
| 99 | 107 |
| 100 OpenFile(upload_file_info); | 108 OpenFile(upload_file_info); |
| 101 } | 109 } |
| 102 | 110 |
| 103 if (download->IsComplete()) | 111 if (download->IsComplete()) |
| 104 UploadComplete(upload_file_info); | 112 MoveFileToCache(upload_file_info); |
| 105 } | 113 } |
| 106 | 114 |
| 107 int64 GDataUploader::GetUploadedBytes(int upload_id) const { | 115 int64 GDataUploader::GetUploadedBytes(int upload_id) const { |
| 108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 109 UploadFileInfo* upload_info = GetUploadFileInfo(upload_id); | 117 UploadFileInfo* upload_info = GetUploadFileInfo(upload_id); |
| 110 // We return the start_range as the count of uploaded bytes since that is the | 118 // We return the start_range as the count of uploaded bytes since that is the |
| 111 // start of the next or currently uploading chunk. | 119 // start of the next or currently uploading chunk. |
| 112 // TODO(asanka): Use a finer grained progress value than this. We end up | 120 // TODO(asanka): Use a finer grained progress value than this. We end up |
| 113 // reporting progress in kUploadChunkSize increments. | 121 // reporting progress in kUploadChunkSize increments. |
| 114 return upload_info ? upload_info->start_range : 0; | 122 return upload_info ? upload_info->start_range : 0; |
| 115 } | 123 } |
| 116 | 124 |
| 117 UploadFileInfo* GDataUploader::GetUploadFileInfo(int upload_id) const { | 125 UploadFileInfo* GDataUploader::GetUploadFileInfo(int upload_id) const { |
| 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 119 | 127 |
| 120 UploadFileInfoMap::const_iterator it = pending_uploads_.find(upload_id); | 128 UploadFileInfoMap::const_iterator it = pending_uploads_.find(upload_id); |
| 121 DVLOG_IF(1, it == pending_uploads_.end()) << "No upload found for id " | 129 DVLOG_IF(1, it == pending_uploads_.end()) << "No upload found for id " |
| 122 << upload_id; | 130 << upload_id; |
| 123 return it != pending_uploads_.end() ? it->second : NULL; | 131 return it != pending_uploads_.end() ? it->second : NULL; |
| 124 } | 132 } |
| 125 | 133 |
| 126 void GDataUploader::RemovePendingUpload(UploadFileInfo* upload_file_info) { | |
| 127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 128 | |
| 129 pending_uploads_.erase(upload_file_info->upload_id); | |
| 130 if (!upload_file_info->completion_callback.is_null()) { | |
| 131 upload_file_info->completion_callback.Run( | |
| 132 base::PLATFORM_FILE_ERROR_ABORT, NULL); | |
| 133 } | |
| 134 | |
| 135 file_system_->CancelOperation(upload_file_info->gdata_path); | |
| 136 | |
| 137 // The file stream is closed by the destructor asynchronously. | |
| 138 delete upload_file_info->file_stream; | |
| 139 delete upload_file_info; | |
| 140 } | |
| 141 | |
| 142 void GDataUploader::OpenFile(UploadFileInfo* upload_file_info) { | 134 void GDataUploader::OpenFile(UploadFileInfo* upload_file_info) { |
| 143 // Open the file asynchronously. | 135 // Open the file asynchronously. |
| 144 const int rv = upload_file_info->file_stream->Open( | 136 const int rv = upload_file_info->file_stream->Open( |
| 145 upload_file_info->file_path, | 137 upload_file_info->file_path, |
| 146 base::PLATFORM_FILE_OPEN | | 138 base::PLATFORM_FILE_OPEN | |
| 147 base::PLATFORM_FILE_READ | | 139 base::PLATFORM_FILE_READ | |
| 148 base::PLATFORM_FILE_ASYNC, | 140 base::PLATFORM_FILE_ASYNC, |
| 149 base::Bind(&GDataUploader::OpenCompletionCallback, | 141 base::Bind(&GDataUploader::OpenCompletionCallback, |
| 150 uploader_factory_.GetWeakPtr(), | 142 uploader_factory_.GetWeakPtr(), |
| 151 upload_file_info->upload_id)); | 143 upload_file_info->upload_id)); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 169 | 161 |
| 170 DVLOG(1) << "Error opening \"" << upload_file_info->file_path.value() | 162 DVLOG(1) << "Error opening \"" << upload_file_info->file_path.value() |
| 171 << "\" for reading: " << net::ErrorToString(result) | 163 << "\" for reading: " << net::ErrorToString(result) |
| 172 << ", tries=" << upload_file_info->num_file_open_tries; | 164 << ", tries=" << upload_file_info->num_file_open_tries; |
| 173 | 165 |
| 174 // Stop trying to open this file if we exceed kMaxFileOpenTries. | 166 // Stop trying to open this file if we exceed kMaxFileOpenTries. |
| 175 const bool exceeded_max_attempts = | 167 const bool exceeded_max_attempts = |
| 176 upload_file_info->num_file_open_tries >= kMaxFileOpenTries; | 168 upload_file_info->num_file_open_tries >= kMaxFileOpenTries; |
| 177 upload_file_info->should_retry_file_open = !exceeded_max_attempts; | 169 upload_file_info->should_retry_file_open = !exceeded_max_attempts; |
| 178 if (exceeded_max_attempts) | 170 if (exceeded_max_attempts) |
| 179 RemovePendingUpload(upload_file_info); | 171 UploadFailed(upload_file_info); |
| 180 | 172 |
| 181 return; | 173 return; |
| 182 } | 174 } |
| 183 | 175 |
| 184 // Open succeeded, initiate the upload. | 176 // Open succeeded, initiate the upload. |
| 185 upload_file_info->should_retry_file_open = false; | 177 upload_file_info->should_retry_file_open = false; |
| 186 file_system_->InitiateUpload( | 178 file_system_->InitiateUpload( |
| 187 upload_file_info->title, | 179 upload_file_info->title, |
| 188 upload_file_info->content_type, | 180 upload_file_info->content_type, |
| 189 upload_file_info->content_length, | 181 upload_file_info->content_length, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 202 | 194 |
| 203 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); | 195 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); |
| 204 if (!upload_file_info) | 196 if (!upload_file_info) |
| 205 return; | 197 return; |
| 206 | 198 |
| 207 DVLOG(1) << "Got upload location [" << upload_location.spec() | 199 DVLOG(1) << "Got upload location [" << upload_location.spec() |
| 208 << "] for [" << upload_file_info->title << "]"; | 200 << "] for [" << upload_file_info->title << "]"; |
| 209 | 201 |
| 210 if (code != HTTP_SUCCESS) { | 202 if (code != HTTP_SUCCESS) { |
| 211 // TODO(achuith): Handle error codes from Google Docs server. | 203 // TODO(achuith): Handle error codes from Google Docs server. |
| 212 RemovePendingUpload(upload_file_info); | 204 UploadFailed(upload_file_info); |
| 213 NOTREACHED(); | |
| 214 return; | 205 return; |
| 215 } | 206 } |
| 216 | 207 |
| 217 upload_file_info->upload_location = upload_location; | 208 upload_file_info->upload_location = upload_location; |
| 218 | 209 |
| 219 // Start the upload from the beginning of the file. | 210 // Start the upload from the beginning of the file. |
| 220 UploadNextChunk(upload_file_info); | 211 UploadNextChunk(upload_file_info); |
| 221 } | 212 } |
| 222 | 213 |
| 223 void GDataUploader::UploadNextChunk(UploadFileInfo* upload_file_info) { | 214 void GDataUploader::UploadNextChunk(UploadFileInfo* upload_file_info) { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 301 if (!upload_file_info) | 292 if (!upload_file_info) |
| 302 return; | 293 return; |
| 303 | 294 |
| 304 if (response.code == HTTP_CREATED) { | 295 if (response.code == HTTP_CREATED) { |
| 305 DVLOG(1) << "Successfully created uploaded file=[" | 296 DVLOG(1) << "Successfully created uploaded file=[" |
| 306 << upload_file_info->title; | 297 << upload_file_info->title; |
| 307 | 298 |
| 308 // Done uploading. | 299 // Done uploading. |
| 309 upload_file_info->entry = entry.Pass(); | 300 upload_file_info->entry = entry.Pass(); |
| 310 if (!upload_file_info->completion_callback.is_null()) { | 301 if (!upload_file_info->completion_callback.is_null()) { |
| 311 upload_file_info->completion_callback.Run( | 302 upload_file_info->completion_callback.Run(base::PLATFORM_FILE_OK, |
| 312 base::PLATFORM_FILE_OK, | 303 upload_file_info); |
|
asanka
2012/03/28 22:02:33
Minor Nit: Perhaps have a way to assert that we on
achuithb
2012/03/28 23:27:11
I've put the Reset back in.
| |
| 313 upload_file_info->entry.get()); | |
| 314 upload_file_info->completion_callback.Reset(); | |
| 315 } | 304 } |
| 305 // TODO(achuith): DeleteUpload() here and let clients call | |
| 306 // GDataFileSystem::AddUploadedFile. | |
| 316 return; | 307 return; |
| 317 } | 308 } |
| 318 | 309 |
| 319 // If code is 308 (RESUME_INCOMPLETE) and range_received is what has been | 310 // If code is 308 (RESUME_INCOMPLETE) and range_received is what has been |
| 320 // previously uploaded (i.e. = upload_file_info->end_range), proceed to | 311 // previously uploaded (i.e. = upload_file_info->end_range), proceed to |
| 321 // upload the next chunk. | 312 // upload the next chunk. |
| 322 if (response.code != HTTP_RESUME_INCOMPLETE || | 313 if (response.code != HTTP_RESUME_INCOMPLETE || |
| 323 response.start_range_received != 0 || | 314 response.start_range_received != 0 || |
| 324 response.end_range_received != upload_file_info->end_range) { | 315 response.end_range_received != upload_file_info->end_range) { |
| 325 // TODO(achuith): Handle error cases, e.g. | 316 // TODO(achuith): Handle error cases, e.g. |
| 326 // - when previously uploaded data wasn't received by Google Docs server, | 317 // - when previously uploaded data wasn't received by Google Docs server, |
| 327 // i.e. when end_range_received < upload_file_info->end_range | 318 // i.e. when end_range_received < upload_file_info->end_range |
| 328 // - when quota is exceeded, which is 1GB for files not converted to Google | 319 // - when quota is exceeded, which is 1GB for files not converted to Google |
| 329 // Docs format; even though the quota-exceeded content length | 320 // Docs format; even though the quota-exceeded content length |
| 330 // is specified in the header when posting request to get upload | 321 // is specified in the header when posting request to get upload |
| 331 // location, the server allows us to upload all chunks of entire file | 322 // location, the server allows us to upload all chunks of entire file |
| 332 // successfully, but instead of returning 201 (CREATED) status code after | 323 // successfully, but instead of returning 201 (CREATED) status code after |
| 333 // receiving the last chunk, it returns 403 (FORBIDDEN); response content | 324 // receiving the last chunk, it returns 403 (FORBIDDEN); response content |
| 334 // then will indicate quote exceeded exception. | 325 // then will indicate quote exceeded exception. |
| 335 NOTREACHED() << "UploadNextChunk http code=" << response.code | 326 NOTREACHED() << "UploadNextChunk http code=" << response.code |
| 336 << ", start_range_received=" << response.start_range_received | 327 << ", start_range_received=" << response.start_range_received |
| 337 << ", end_range_received=" << response.end_range_received | 328 << ", end_range_received=" << response.end_range_received |
| 338 << ", expected end range=" << upload_file_info->end_range; | 329 << ", expected end range=" << upload_file_info->end_range; |
| 339 | 330 |
| 340 RemovePendingUpload(upload_file_info); | 331 UploadFailed(upload_file_info); |
| 341 return; | 332 return; |
| 342 } | 333 } |
| 343 | 334 |
| 344 DVLOG(1) << "Received range " << response.start_range_received | 335 DVLOG(1) << "Received range " << response.start_range_received |
| 345 << "-" << response.end_range_received | 336 << "-" << response.end_range_received |
| 346 << " for [" << upload_file_info->title << "]"; | 337 << " for [" << upload_file_info->title << "]"; |
| 347 | 338 |
| 348 // Continue uploading. | 339 // Continue uploading. |
| 349 UploadNextChunk(upload_file_info); | 340 UploadNextChunk(upload_file_info); |
| 350 } | 341 } |
| 351 | 342 |
| 352 void GDataUploader::UploadComplete(UploadFileInfo* upload_file_info) { | 343 void GDataUploader::MoveFileToCache(UploadFileInfo* upload_file_info) { |
| 353 DVLOG(1) << "UploadComplete " << upload_file_info->file_path.value(); | 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 354 file_system_->AddUploadedFile(upload_file_info->gdata_path.DirName(), | 345 if (upload_file_info->entry == NULL) |
| 355 upload_file_info->entry.get(), | 346 return; |
| 356 upload_file_info->file_path, | 347 |
| 357 GDataFileSystemInterface::FILE_OPERATION_MOVE); | 348 DVLOG(1) << "MoveFileToCache " << upload_file_info->file_path.value(); |
| 358 RemovePendingUpload(upload_file_info); | 349 file_system_->AddUploadedFile( |
| 350 upload_file_info->gdata_path.DirName(), | |
| 351 upload_file_info->entry.get(), | |
| 352 upload_file_info->file_path, | |
| 353 GDataFileSystemInterface::FILE_OPERATION_MOVE); | |
| 354 DeleteUpload(upload_file_info); | |
| 355 } | |
| 356 | |
| 357 void GDataUploader::UploadFailed(UploadFileInfo* upload_file_info) { | |
| 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 359 LOG(ERROR) << "Upload failed " << upload_file_info->DebugString(); | |
| 360 if (!upload_file_info->completion_callback.is_null()) { | |
| 361 upload_file_info->completion_callback.Run(base::PLATFORM_FILE_ERROR_ABORT, | |
| 362 upload_file_info); | |
| 363 } | |
| 364 file_system_->CancelOperation(upload_file_info->gdata_path); | |
| 365 DeleteUpload(upload_file_info); | |
| 366 } | |
| 367 | |
| 368 void GDataUploader::DeleteUpload(UploadFileInfo* upload_file_info) { | |
| 369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 370 | |
| 371 DVLOG(1) << "Deleting upload " << upload_file_info->gdata_path.value(); | |
| 372 pending_uploads_.erase(upload_file_info->upload_id); | |
| 373 | |
| 374 // The file stream is closed by the destructor asynchronously. | |
| 375 delete upload_file_info->file_stream; | |
| 376 delete upload_file_info; | |
| 359 } | 377 } |
| 360 | 378 |
| 361 } // namespace gdata | 379 } // namespace gdata |
| OLD | NEW |