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/drive/drive_uploader.h" | 5 #include "chrome/browser/drive/drive_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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 struct DriveUploader::UploadFileInfo { | 48 struct DriveUploader::UploadFileInfo { |
49 UploadFileInfo(const base::FilePath& local_path, | 49 UploadFileInfo(const base::FilePath& local_path, |
50 const std::string& content_type, | 50 const std::string& content_type, |
51 const UploadCompletionCallback& callback, | 51 const UploadCompletionCallback& callback, |
52 const ProgressCallback& progress_callback) | 52 const ProgressCallback& progress_callback) |
53 : file_path(local_path), | 53 : file_path(local_path), |
54 content_type(content_type), | 54 content_type(content_type), |
55 completion_callback(callback), | 55 completion_callback(callback), |
56 progress_callback(progress_callback), | 56 progress_callback(progress_callback), |
57 content_length(0), | 57 content_length(0), |
| 58 next_start_position(-1), |
58 power_save_blocker(content::PowerSaveBlocker::Create( | 59 power_save_blocker(content::PowerSaveBlocker::Create( |
59 content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, | 60 content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, |
60 "Upload in progress")), | 61 "Upload in progress")), |
61 cancelled(false), | 62 cancelled(false), |
62 weak_ptr_factory_(this) { | 63 weak_ptr_factory_(this) { |
63 } | 64 } |
64 | 65 |
65 ~UploadFileInfo() { | 66 ~UploadFileInfo() { |
66 } | 67 } |
67 | 68 |
(...skipping 22 matching lines...) Expand all Loading... |
90 // Callback to periodically notify the upload progress. | 91 // Callback to periodically notify the upload progress. |
91 const ProgressCallback progress_callback; | 92 const ProgressCallback progress_callback; |
92 | 93 |
93 // Location URL where file is to be uploaded to, returned from | 94 // Location URL where file is to be uploaded to, returned from |
94 // InitiateUpload. Used for the subsequent ResumeUpload requests. | 95 // InitiateUpload. Used for the subsequent ResumeUpload requests. |
95 GURL upload_location; | 96 GURL upload_location; |
96 | 97 |
97 // Header content-Length. | 98 // Header content-Length. |
98 int64 content_length; | 99 int64 content_length; |
99 | 100 |
| 101 int64 next_start_position; |
| 102 |
100 // Blocks system suspend while upload is in progress. | 103 // Blocks system suspend while upload is in progress. |
101 scoped_ptr<content::PowerSaveBlocker> power_save_blocker; | 104 scoped_ptr<content::PowerSaveBlocker> power_save_blocker; |
102 | 105 |
103 // Fields for implementing cancellation. |cancel_callback| is non-null if | 106 // Fields for implementing cancellation. |cancel_callback| is non-null if |
104 // there is an in-flight HTTP request. In that case, |cancell_callback| will | 107 // there is an in-flight HTTP request. In that case, |cancell_callback| will |
105 // cancel the operation. |cancelled| is initially false and turns to true | 108 // cancel the operation. |cancelled| is initially false and turns to true |
106 // once Cancel() is called. DriveUploader will check this field before after | 109 // once Cancel() is called. DriveUploader will check this field before after |
107 // an async task other than HTTP requests and cancels the subsequent requests | 110 // an async task other than HTTP requests and cancels the subsequent requests |
108 // if this is flagged to true. | 111 // if this is flagged to true. |
109 CancelCallback cancel_callback; | 112 CancelCallback cancel_callback; |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 if (code == HTTP_PRECONDITION) { | 291 if (code == HTTP_PRECONDITION) { |
289 // ETag mismatch. | 292 // ETag mismatch. |
290 UploadFailed(upload_file_info.Pass(), HTTP_CONFLICT); | 293 UploadFailed(upload_file_info.Pass(), HTTP_CONFLICT); |
291 return; | 294 return; |
292 } | 295 } |
293 UploadFailed(upload_file_info.Pass(), code); | 296 UploadFailed(upload_file_info.Pass(), code); |
294 return; | 297 return; |
295 } | 298 } |
296 | 299 |
297 upload_file_info->upload_location = upload_location; | 300 upload_file_info->upload_location = upload_location; |
298 UploadNextChunk(upload_file_info.Pass(), 0); // start_position | 301 upload_file_info->next_start_position = 0; |
| 302 UploadNextChunk(upload_file_info.Pass()); |
299 } | 303 } |
300 | 304 |
301 void DriveUploader::StartGetUploadStatus( | 305 void DriveUploader::StartGetUploadStatus( |
302 scoped_ptr<UploadFileInfo> upload_file_info) { | 306 scoped_ptr<UploadFileInfo> upload_file_info) { |
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
304 DCHECK(upload_file_info); | 308 DCHECK(upload_file_info); |
305 | 309 |
306 UploadFileInfo* info_ptr = upload_file_info.get(); | 310 UploadFileInfo* info_ptr = upload_file_info.get(); |
307 info_ptr->cancel_callback = drive_service_->GetUploadStatus( | 311 info_ptr->cancel_callback = drive_service_->GetUploadStatus( |
308 info_ptr->upload_location, | 312 info_ptr->upload_location, |
309 info_ptr->content_length, | 313 info_ptr->content_length, |
310 base::Bind(&DriveUploader::OnUploadRangeResponseReceived, | 314 base::Bind(&DriveUploader::OnUploadRangeResponseReceived, |
311 weak_ptr_factory_.GetWeakPtr(), | 315 weak_ptr_factory_.GetWeakPtr(), |
312 base::Passed(&upload_file_info))); | 316 base::Passed(&upload_file_info))); |
313 } | 317 } |
314 | 318 |
315 void DriveUploader::UploadNextChunk( | 319 void DriveUploader::UploadNextChunk( |
316 scoped_ptr<UploadFileInfo> upload_file_info, | 320 scoped_ptr<UploadFileInfo> upload_file_info) { |
317 int64 start_position) { | |
318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
319 DCHECK(upload_file_info); | 322 DCHECK(upload_file_info); |
320 DCHECK_GE(start_position, 0); | 323 DCHECK_GE(upload_file_info->next_start_position, 0); |
321 DCHECK_LE(start_position, upload_file_info->content_length); | 324 DCHECK_LE(upload_file_info->next_start_position, |
| 325 upload_file_info->content_length); |
322 | 326 |
323 if (upload_file_info->cancelled) { | 327 if (upload_file_info->cancelled) { |
324 UploadFailed(upload_file_info.Pass(), GDATA_CANCELLED); | 328 UploadFailed(upload_file_info.Pass(), GDATA_CANCELLED); |
325 return; | 329 return; |
326 } | 330 } |
327 | 331 |
328 // Limit the size of data uploaded per each request by kUploadChunkSize. | 332 // Limit the size of data uploaded per each request by kUploadChunkSize. |
329 const int64 end_position = std::min(upload_file_info->content_length, | 333 const int64 end_position = std::min( |
330 start_position + kUploadChunkSize); | 334 upload_file_info->content_length, |
| 335 upload_file_info->next_start_position + kUploadChunkSize); |
331 | 336 |
332 UploadFileInfo* info_ptr = upload_file_info.get(); | 337 UploadFileInfo* info_ptr = upload_file_info.get(); |
333 info_ptr->cancel_callback = drive_service_->ResumeUpload( | 338 info_ptr->cancel_callback = drive_service_->ResumeUpload( |
334 info_ptr->upload_location, | 339 info_ptr->upload_location, |
335 start_position, | 340 info_ptr->next_start_position, |
336 end_position, | 341 end_position, |
337 info_ptr->content_length, | 342 info_ptr->content_length, |
338 info_ptr->content_type, | 343 info_ptr->content_type, |
339 info_ptr->file_path, | 344 info_ptr->file_path, |
340 base::Bind(&DriveUploader::OnUploadRangeResponseReceived, | 345 base::Bind(&DriveUploader::OnUploadRangeResponseReceived, |
341 weak_ptr_factory_.GetWeakPtr(), | 346 weak_ptr_factory_.GetWeakPtr(), |
342 base::Passed(&upload_file_info)), | 347 base::Passed(&upload_file_info)), |
343 base::Bind(&DriveUploader::OnUploadProgress, | 348 base::Bind(&DriveUploader::OnUploadProgress, |
344 weak_ptr_factory_.GetWeakPtr(), | 349 weak_ptr_factory_.GetWeakPtr(), |
345 info_ptr->progress_callback, | 350 info_ptr->progress_callback, |
346 start_position, | 351 info_ptr->next_start_position, |
347 info_ptr->content_length)); | 352 info_ptr->content_length)); |
348 } | 353 } |
349 | 354 |
350 void DriveUploader::OnUploadRangeResponseReceived( | 355 void DriveUploader::OnUploadRangeResponseReceived( |
351 scoped_ptr<UploadFileInfo> upload_file_info, | 356 scoped_ptr<UploadFileInfo> upload_file_info, |
352 const UploadRangeResponse& response, | 357 const UploadRangeResponse& response, |
353 scoped_ptr<ResourceEntry> entry) { | 358 scoped_ptr<ResourceEntry> entry) { |
354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
355 | 360 |
356 if (response.code == HTTP_CREATED || response.code == HTTP_SUCCESS) { | 361 if (response.code == HTTP_CREATED || response.code == HTTP_SUCCESS) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 UploadFailed( | 395 UploadFailed( |
391 upload_file_info.Pass(), | 396 upload_file_info.Pass(), |
392 response.code == HTTP_FORBIDDEN ? GDATA_NO_SPACE : response.code); | 397 response.code == HTTP_FORBIDDEN ? GDATA_NO_SPACE : response.code); |
393 return; | 398 return; |
394 } | 399 } |
395 | 400 |
396 DVLOG(1) << "Received range " << response.start_position_received | 401 DVLOG(1) << "Received range " << response.start_position_received |
397 << "-" << response.end_position_received | 402 << "-" << response.end_position_received |
398 << " for [" << upload_file_info->file_path.value() << "]"; | 403 << " for [" << upload_file_info->file_path.value() << "]"; |
399 | 404 |
400 UploadNextChunk(upload_file_info.Pass(), response.end_position_received); | 405 upload_file_info->next_start_position = response.end_position_received; |
| 406 UploadNextChunk(upload_file_info.Pass()); |
401 } | 407 } |
402 | 408 |
403 void DriveUploader::OnUploadProgress(const ProgressCallback& callback, | 409 void DriveUploader::OnUploadProgress(const ProgressCallback& callback, |
404 int64 start_position, | 410 int64 start_position, |
405 int64 total_size, | 411 int64 total_size, |
406 int64 progress_of_chunk, | 412 int64 progress_of_chunk, |
407 int64 total_of_chunk) { | 413 int64 total_of_chunk) { |
408 if (!callback.is_null()) | 414 if (!callback.is_null()) |
409 callback.Run(start_position + progress_of_chunk, total_size); | 415 callback.Run(start_position + progress_of_chunk, total_size); |
410 } | 416 } |
411 | 417 |
412 void DriveUploader::UploadFailed(scoped_ptr<UploadFileInfo> upload_file_info, | 418 void DriveUploader::UploadFailed(scoped_ptr<UploadFileInfo> upload_file_info, |
413 GDataErrorCode error) { | 419 GDataErrorCode error) { |
414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
415 | 421 |
416 LOG(ERROR) << "Upload failed " << upload_file_info->DebugString(); | 422 LOG(ERROR) << "Upload failed " << upload_file_info->DebugString(); |
417 | 423 |
| 424 if (upload_file_info->next_start_position < 0) { |
| 425 // Discard the upload location because no request could succeed with it. |
| 426 // Maybe it's obsolete. |
| 427 upload_file_info->upload_location = GURL(); |
| 428 } |
| 429 |
418 upload_file_info->completion_callback.Run( | 430 upload_file_info->completion_callback.Run( |
419 error, upload_file_info->upload_location, scoped_ptr<ResourceEntry>()); | 431 error, upload_file_info->upload_location, scoped_ptr<ResourceEntry>()); |
420 } | 432 } |
421 | 433 |
422 } // namespace drive | 434 } // namespace drive |
OLD | NEW |