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); |
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 NOTREACHED(); | |
Ben Chan
2012/03/28 05:29:36
NOTREACHED() ???
achuithb
2012/03/28 09:14:04
You're right - bad idea. Replaced with LOG(ERROR).
| |
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 |