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 "content/browser/download/download_resource_handler.h" | 5 #include "content/browser/download/download_resource_handler.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop_proxy.h" | |
| 11 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 12 #include "base/metrics/stats_counters.h" | 13 #include "base/metrics/stats_counters.h" |
| 13 #include "base/stringprintf.h" | 14 #include "base/stringprintf.h" |
| 14 #include "content/browser/download/download_buffer.h" | |
| 15 #include "content/browser/download/download_create_info.h" | 15 #include "content/browser/download/download_create_info.h" |
| 16 #include "content/browser/download/download_file_manager.h" | 16 #include "content/browser/download/download_file_manager.h" |
| 17 #include "content/browser/download/download_interrupt_reasons_impl.h" | 17 #include "content/browser/download/download_interrupt_reasons_impl.h" |
| 18 #include "content/browser/download/download_manager_impl.h" | 18 #include "content/browser/download/download_manager_impl.h" |
| 19 #include "content/browser/download/download_request_handle.h" | 19 #include "content/browser/download/download_request_handle.h" |
| 20 #include "content/browser/download/byte_stream.h" | |
| 20 #include "content/browser/download/download_stats.h" | 21 #include "content/browser/download/download_stats.h" |
| 21 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" | 22 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" |
| 22 #include "content/browser/renderer_host/resource_request_info_impl.h" | 23 #include "content/browser/renderer_host/resource_request_info_impl.h" |
| 23 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
| 24 #include "content/public/browser/download_interrupt_reasons.h" | 25 #include "content/public/browser/download_interrupt_reasons.h" |
| 25 #include "content/public/browser/download_item.h" | 26 #include "content/public/browser/download_item.h" |
| 26 #include "content/public/browser/download_manager_delegate.h" | 27 #include "content/public/browser/download_manager_delegate.h" |
| 27 #include "content/public/common/resource_response.h" | 28 #include "content/public/common/resource_response.h" |
| 28 #include "net/base/io_buffer.h" | 29 #include "net/base/io_buffer.h" |
| 29 #include "net/base/net_errors.h" | 30 #include "net/base/net_errors.h" |
| 30 #include "net/http/http_response_headers.h" | 31 #include "net/http/http_response_headers.h" |
| 31 #include "net/url_request/url_request_context.h" | 32 #include "net/url_request/url_request_context.h" |
| 32 | 33 |
| 33 using content::BrowserThread; | 34 using content::BrowserThread; |
| 34 using content::DownloadId; | 35 using content::DownloadId; |
| 35 using content::DownloadItem; | 36 using content::DownloadItem; |
| 36 using content::DownloadManager; | 37 using content::DownloadManager; |
| 37 using content::ResourceDispatcherHostImpl; | 38 using content::ResourceDispatcherHostImpl; |
| 38 using content::ResourceRequestInfoImpl; | 39 using content::ResourceRequestInfoImpl; |
| 39 | 40 |
| 40 namespace { | 41 namespace { |
| 41 | 42 |
| 43 static const int kDownloadPipeSize = 100 * 1024; | |
| 44 | |
| 42 void CallStartedCBOnUIThread( | 45 void CallStartedCBOnUIThread( |
| 43 const DownloadResourceHandler::OnStartedCallback& started_cb, | 46 const DownloadResourceHandler::OnStartedCallback& started_cb, |
| 44 DownloadId id, | 47 DownloadId id, |
| 45 net::Error error) { | 48 net::Error error) { |
| 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 47 if (started_cb.is_null()) | 50 if (started_cb.is_null()) |
| 48 return; | 51 return; |
| 49 started_cb.Run(id, error); | 52 started_cb.Run(id, error); |
| 50 } | 53 } |
| 51 | 54 |
| 52 } // namespace | 55 } // namespace |
| 53 | 56 |
| 54 DownloadResourceHandler::DownloadResourceHandler( | 57 DownloadResourceHandler::DownloadResourceHandler( |
| 55 int render_process_host_id, | 58 int render_process_host_id, |
| 56 int render_view_id, | 59 int render_view_id, |
| 57 int request_id, | 60 int request_id, |
| 58 const GURL& url, | 61 const GURL& url, |
| 59 DownloadFileManager* download_file_manager, | 62 DownloadFileManager* download_file_manager, |
| 60 net::URLRequest* request, | 63 net::URLRequest* request, |
| 61 const DownloadResourceHandler::OnStartedCallback& started_cb, | 64 const DownloadResourceHandler::OnStartedCallback& started_cb, |
| 62 const content::DownloadSaveInfo& save_info) | 65 const content::DownloadSaveInfo& save_info) |
| 63 : download_id_(DownloadId::Invalid()), | 66 : download_id_(DownloadId::Invalid()), |
| 64 global_id_(render_process_host_id, request_id), | 67 global_id_(render_process_host_id, request_id), |
| 65 render_view_id_(render_view_id), | 68 render_view_id_(render_view_id), |
| 66 content_length_(0), | 69 content_length_(0), |
| 67 download_file_manager_(download_file_manager), | 70 download_file_manager_(download_file_manager), |
| 68 request_(request), | 71 request_(request), |
| 69 started_cb_(started_cb), | 72 started_cb_(started_cb), |
| 70 save_info_(save_info), | 73 save_info_(save_info), |
| 71 buffer_(new content::DownloadBuffer), | |
| 72 last_buffer_size_(0), | 74 last_buffer_size_(0), |
| 73 bytes_read_(0), | 75 bytes_read_(0), |
| 74 pause_count_(0), | 76 pause_count_(0), |
| 75 was_deferred_(false) { | 77 was_deferred_(false) { |
| 76 download_stats::RecordDownloadCount(download_stats::UNTHROTTLED_COUNT); | 78 download_stats::RecordDownloadCount(download_stats::UNTHROTTLED_COUNT); |
| 77 } | 79 } |
| 78 | 80 |
| 79 bool DownloadResourceHandler::OnUploadProgress(int request_id, | 81 bool DownloadResourceHandler::OnUploadProgress(int request_id, |
| 80 uint64 position, | 82 uint64 position, |
| 81 uint64 size) { | 83 uint64 size) { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 110 SetContentLength(response->content_length); | 112 SetContentLength(response->content_length); |
| 111 | 113 |
| 112 const ResourceRequestInfoImpl* request_info = | 114 const ResourceRequestInfoImpl* request_info = |
| 113 ResourceRequestInfoImpl::ForRequest(request_); | 115 ResourceRequestInfoImpl::ForRequest(request_); |
| 114 | 116 |
| 115 // Deleted in DownloadManager. | 117 // Deleted in DownloadManager. |
| 116 scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo( | 118 scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo( |
| 117 base::Time::Now(), 0, content_length_, DownloadItem::IN_PROGRESS, | 119 base::Time::Now(), 0, content_length_, DownloadItem::IN_PROGRESS, |
| 118 request_->net_log(), request_info->has_user_gesture(), | 120 request_->net_log(), request_info->has_user_gesture(), |
| 119 request_info->transition_type())); | 121 request_info->transition_type())); |
| 122 | |
| 123 // Create the ByteStream pipe for sending data to the download sink. | |
| 124 scoped_ptr<content::ByteStreamOutput> pipe_output; | |
|
darin (slow to review)
2012/05/24 22:01:36
I am very concerned with this use of Input and Out
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
Done.
| |
| 125 CreateByteStream( | |
| 126 base::MessageLoopProxy::current(), | |
| 127 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), | |
| 128 kDownloadPipeSize, &pipe_input_, &pipe_output); | |
|
darin (slow to review)
2012/05/24 22:01:36
nit: you call the variables pipe_{input,output}, w
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
I didn't put a lot of thought into the naming, act
| |
| 129 pipe_input_->RegisterCallback( | |
| 130 // We're refcounted, so this is a safe callback to pass around. | |
| 131 base::Bind(&DownloadResourceHandler::ResumeRequest, this)); | |
| 132 | |
| 120 info->url_chain = request_->url_chain(); | 133 info->url_chain = request_->url_chain(); |
| 121 info->referrer_url = GURL(request_->referrer()); | 134 info->referrer_url = GURL(request_->referrer()); |
| 122 info->start_time = base::Time::Now(); | 135 info->start_time = base::Time::Now(); |
| 123 info->received_bytes = save_info_.offset; | 136 info->received_bytes = save_info_.offset; |
| 124 info->total_bytes = content_length_; | 137 info->total_bytes = content_length_; |
| 125 info->state = DownloadItem::IN_PROGRESS; | 138 info->state = DownloadItem::IN_PROGRESS; |
| 126 info->has_user_gesture = request_info->has_user_gesture(); | 139 info->has_user_gesture = request_info->has_user_gesture(); |
| 127 info->content_disposition = content_disposition_; | 140 info->content_disposition = content_disposition_; |
| 128 info->mime_type = response->mime_type; | 141 info->mime_type = response->mime_type; |
| 129 info->remote_address = request_->GetSocketAddress().host(); | 142 info->remote_address = request_->GetSocketAddress().host(); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 157 } | 170 } |
| 158 | 171 |
| 159 info->prompt_user_for_save_location = | 172 info->prompt_user_for_save_location = |
| 160 save_info_.prompt_for_save_location && save_info_.file_path.empty(); | 173 save_info_.prompt_for_save_location && save_info_.file_path.empty(); |
| 161 info->referrer_charset = request_->context()->referrer_charset(); | 174 info->referrer_charset = request_->context()->referrer_charset(); |
| 162 info->save_info = save_info_; | 175 info->save_info = save_info_; |
| 163 | 176 |
| 164 BrowserThread::PostTask( | 177 BrowserThread::PostTask( |
| 165 BrowserThread::UI, FROM_HERE, | 178 BrowserThread::UI, FROM_HERE, |
| 166 base::Bind(&DownloadResourceHandler::StartOnUIThread, this, | 179 base::Bind(&DownloadResourceHandler::StartOnUIThread, this, |
| 167 base::Passed(&info), request_handle)); | 180 base::Passed(info.Pass()), |
| 181 base::Passed(pipe_output.Pass()), | |
| 182 request_handle, | |
| 183 started_cb_)); | |
|
benjhayden
2012/05/24 15:35:57
Can you comment why you're passing started_cb_ to
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
Done.
| |
| 184 // Guaranteed to be called in StartOnUIThread | |
| 185 started_cb_.Reset(); | |
| 168 | 186 |
| 169 return true; | 187 return true; |
| 170 } | 188 } |
| 171 | 189 |
| 172 void DownloadResourceHandler::CallStartedCB(DownloadId id, net::Error error) { | 190 void DownloadResourceHandler::CallStartedCB(DownloadId id, net::Error error) { |
| 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
|
benjhayden
2012/05/24 15:35:57
Can you add this annotation to *all* the methods?
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
I did almost all the methods; I skipped the ones w
| |
| 173 if (started_cb_.is_null()) | 192 if (started_cb_.is_null()) |
| 174 return; | 193 return; |
| 175 BrowserThread::PostTask( | 194 BrowserThread::PostTask( |
| 176 BrowserThread::UI, FROM_HERE, | 195 BrowserThread::UI, FROM_HERE, |
| 177 base::Bind(&CallStartedCBOnUIThread, started_cb_, id, error)); | 196 base::Bind(&CallStartedCBOnUIThread, started_cb_, id, error)); |
| 178 started_cb_.Reset(); | 197 started_cb_.Reset(); |
| 179 } | 198 } |
| 180 | 199 |
| 181 bool DownloadResourceHandler::OnWillStart(int request_id, | 200 bool DownloadResourceHandler::OnWillStart(int request_id, |
| 182 const GURL& url, | 201 const GURL& url, |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 207 // ResumeDeferredRequest then repeats the last OnReadCompleted call. | 226 // ResumeDeferredRequest then repeats the last OnReadCompleted call. |
| 208 // TODO(darin): Fix the ResourceDispatcherHost to avoid this hack! | 227 // TODO(darin): Fix the ResourceDispatcherHost to avoid this hack! |
| 209 return true; | 228 return true; |
| 210 } | 229 } |
| 211 | 230 |
| 212 if (pause_count_ > 0) { | 231 if (pause_count_ > 0) { |
| 213 *defer = was_deferred_ = true; | 232 *defer = was_deferred_ = true; |
| 214 return true; | 233 return true; |
| 215 } | 234 } |
| 216 | 235 |
| 217 if (download_id_ == DownloadId::Invalid()) { | |
| 218 // We can't start saving the data before we create the file on disk and | |
| 219 // have a download id. The request will be un-paused in | |
| 220 // DownloadFileManager::CreateDownloadFile. | |
| 221 *defer = was_deferred_ = true; | |
| 222 return true; | |
| 223 } | |
| 224 | |
| 225 base::TimeTicks now(base::TimeTicks::Now()); | 236 base::TimeTicks now(base::TimeTicks::Now()); |
| 226 if (!last_read_time_.is_null()) { | 237 if (!last_read_time_.is_null()) { |
| 227 double seconds_since_last_read = (now - last_read_time_).InSecondsF(); | 238 double seconds_since_last_read = (now - last_read_time_).InSecondsF(); |
| 228 if (now == last_read_time_) | 239 if (now == last_read_time_) |
| 229 // Use 1/10 ms as a "very small number" so that we avoid | 240 // Use 1/10 ms as a "very small number" so that we avoid |
| 230 // divide-by-zero error and still record a very high potential bandwidth. | 241 // divide-by-zero error and still record a very high potential bandwidth. |
| 231 seconds_since_last_read = 0.00001; | 242 seconds_since_last_read = 0.00001; |
| 232 | 243 |
| 233 double actual_bandwidth = (*bytes_read)/seconds_since_last_read; | 244 double actual_bandwidth = (*bytes_read)/seconds_since_last_read; |
| 234 double potential_bandwidth = last_buffer_size_/seconds_since_last_read; | 245 double potential_bandwidth = last_buffer_size_/seconds_since_last_read; |
| 235 download_stats::RecordBandwidth(actual_bandwidth, potential_bandwidth); | 246 download_stats::RecordBandwidth(actual_bandwidth, potential_bandwidth); |
| 236 } | 247 } |
| 237 last_read_time_ = now; | 248 last_read_time_ = now; |
| 238 | 249 |
| 239 if (!*bytes_read) | 250 if (!*bytes_read) |
| 240 return true; | 251 return true; |
| 241 bytes_read_ += *bytes_read; | 252 bytes_read_ += *bytes_read; |
| 242 DCHECK(read_buffer_); | 253 DCHECK(read_buffer_); |
| 243 // Swap the data. | |
| 244 net::IOBuffer* io_buffer = NULL; | |
| 245 read_buffer_.swap(&io_buffer); | |
| 246 size_t vector_size = buffer_->AddData(io_buffer, *bytes_read); | |
| 247 bool need_update = (vector_size == 1); // Buffer was empty. | |
| 248 | 254 |
| 249 // We are passing ownership of this buffer to the download file manager. | 255 // Take the data ship it down the pipe. If the pipe is full, pause the |
| 250 if (need_update) { | 256 // request; the pipe callback will resume it. |
| 251 BrowserThread::PostTask( | 257 if (!pipe_input_->Write(read_buffer_, *bytes_read)) { |
| 252 BrowserThread::FILE, FROM_HERE, | 258 *defer = was_deferred_ = true; |
| 253 base::Bind(&DownloadFileManager::UpdateDownload, | 259 pause_count_++; |
|
darin (slow to review)
2012/05/24 22:01:36
I'd call PauseRequest() here.
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
Feels a little weird, since the *defer = true impl
| |
| 254 download_file_manager_, download_id_, buffer_)); | 260 last_pause_time_ = now; |
| 255 } | 261 } |
| 256 | 262 |
| 257 // We schedule a pause outside of the read loop if there is too much file | 263 read_buffer_ = NULL; // Drop our reference. |
| 258 // writing work to do. | |
| 259 if (vector_size > kLoadsToWrite) { | |
| 260 *defer = was_deferred_ = true; | |
| 261 CheckWriteProgressLater(); | |
| 262 } | |
| 263 | 264 |
| 264 return true; | 265 return true; |
| 265 } | 266 } |
| 266 | 267 |
| 267 bool DownloadResourceHandler::OnResponseCompleted( | 268 bool DownloadResourceHandler::OnResponseCompleted( |
| 268 int request_id, | 269 int request_id, |
| 269 const net::URLRequestStatus& status, | 270 const net::URLRequestStatus& status, |
| 270 const std::string& security_info) { | 271 const std::string& security_info) { |
| 271 VLOG(20) << __FUNCTION__ << "()" << DebugString() | 272 VLOG(20) << __FUNCTION__ << "()" << DebugString() |
| 272 << " request_id = " << request_id | 273 << " request_id = " << request_id |
| 273 << " status.status() = " << status.status() | 274 << " status.status() = " << status.status() |
| 274 << " status.error() = " << status.error(); | 275 << " status.error() = " << status.error(); |
| 275 int response = status.is_success() ? request_->GetResponseCode() : 0; | 276 int response_code = status.is_success() ? request_->GetResponseCode() : 0; |
| 276 if (download_id_.IsValid()) { | |
| 277 OnResponseCompletedInternal(request_id, status, security_info, response); | |
| 278 } else { | |
| 279 // We got cancelled before the task which sets the id ran on the IO thread. | |
| 280 // Wait for it. | |
| 281 BrowserThread::PostTaskAndReply( | |
| 282 BrowserThread::UI, FROM_HERE, | |
| 283 base::Bind(&base::DoNothing), | |
| 284 base::Bind(&DownloadResourceHandler::OnResponseCompletedInternal, this, | |
| 285 request_id, status, security_info, response)); | |
| 286 } | |
| 287 // Can't trust request_ being value after this point. | |
| 288 request_ = NULL; | |
| 289 return true; | |
| 290 } | |
| 291 | 277 |
| 292 void DownloadResourceHandler::OnResponseCompletedInternal( | |
| 293 int request_id, | |
| 294 const net::URLRequestStatus& status, | |
| 295 const std::string& security_info, | |
| 296 int response_code) { | |
| 297 // NOTE: |request_| may be a dangling pointer at this point. | |
| 298 VLOG(20) << __FUNCTION__ << "()" | |
| 299 << " request_id = " << request_id | |
| 300 << " status.status() = " << status.status() | |
| 301 << " status.error() = " << status.error(); | |
| 302 net::Error error_code = net::OK; | 278 net::Error error_code = net::OK; |
| 303 if (status.status() == net::URLRequestStatus::FAILED) | 279 if (status.status() == net::URLRequestStatus::FAILED) |
| 304 error_code = static_cast<net::Error>(status.error()); // Normal case. | 280 error_code = static_cast<net::Error>(status.error()); // Normal case. |
| 305 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are | 281 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are |
| 306 // allowed since a number of servers in the wild close the connection too | 282 // allowed since a number of servers in the wild close the connection too |
| 307 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - | 283 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - |
| 308 // treat downloads as complete in both cases, so we follow their lead. | 284 // treat downloads as complete in both cases, so we follow their lead. |
| 309 if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH || | 285 if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH || |
| 310 error_code == net::ERR_INCOMPLETE_CHUNKED_ENCODING) { | 286 error_code == net::ERR_INCOMPLETE_CHUNKED_ENCODING) { |
| 311 error_code = net::OK; | 287 error_code = net::OK; |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 335 break; | 311 break; |
| 336 default: | 312 default: |
| 337 reason = content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; | 313 reason = content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; |
| 338 break; | 314 break; |
| 339 } | 315 } |
| 340 } | 316 } |
| 341 } | 317 } |
| 342 | 318 |
| 343 download_stats::RecordAcceptsRanges(accept_ranges_, bytes_read_); | 319 download_stats::RecordAcceptsRanges(accept_ranges_, bytes_read_); |
| 344 | 320 |
| 345 // If the callback was already run on the UI thread, this will be a noop. | 321 CallStartedCB(DownloadId(), error_code); |
| 346 CallStartedCB(download_id_, error_code); | |
| 347 | 322 |
| 348 // We transfer ownership to |DownloadFileManager| to delete |buffer_|, | 323 // Send the info down the pipe. Conditional is in case we get |
| 349 // so that any functions queued up on the FILE thread are executed | 324 // OnResponseCompleted without OnResponseStarted. |
| 350 // before deletion. | 325 if (pipe_input_.get()) |
| 351 BrowserThread::PostTask( | 326 pipe_input_->Close(reason); |
| 352 BrowserThread::FILE, FROM_HERE, | 327 |
| 353 base::Bind(&DownloadFileManager::OnResponseCompleted, | 328 pipe_input_.reset(); // We no longer need the pipe. |
| 354 download_file_manager_, download_id_, reason, security_info)); | |
| 355 buffer_ = NULL; // The buffer is longer needed by |DownloadResourceHandler|. | |
| 356 read_buffer_ = NULL; | 329 read_buffer_ = NULL; |
| 330 | |
| 331 // Can't trust request_ being valid after this point. | |
| 332 request_ = NULL; | |
|
darin (slow to review)
2012/05/24 22:01:36
technically, the purpose of OnRequestClosed is to
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
Done. The code's a bit stale, anyway, as we no lo
| |
| 333 | |
| 334 // Stats | |
| 335 download_stats::RecordNetworkBandwidth( | |
| 336 bytes_read_, base::TimeTicks::Now() - download_start_time_, | |
| 337 total_pause_time_); | |
| 338 | |
| 339 return true; | |
| 357 } | 340 } |
| 358 | 341 |
| 359 void DownloadResourceHandler::OnRequestClosed() { | 342 void DownloadResourceHandler::OnRequestClosed() { |
| 360 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", | 343 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", |
| 361 base::TimeTicks::Now() - download_start_time_); | 344 base::TimeTicks::Now() - download_start_time_); |
| 362 } | 345 } |
| 363 | 346 |
| 364 void DownloadResourceHandler::StartOnUIThread( | 347 void DownloadResourceHandler::StartOnUIThread( |
|
benjhayden
2012/05/24 15:35:57
If you want to avoid accessing member variables ou
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
Done.
| |
| 365 scoped_ptr<DownloadCreateInfo> info, | 348 scoped_ptr<DownloadCreateInfo> info, |
| 366 const DownloadRequestHandle& handle) { | 349 scoped_ptr<content::ByteStreamOutput> pipe, |
| 350 const DownloadRequestHandle& handle, | |
| 351 const OnStartedCallback& started_cb) { | |
| 367 DownloadManager* download_manager = handle.GetDownloadManager(); | 352 DownloadManager* download_manager = handle.GetDownloadManager(); |
| 368 if (!download_manager) { | 353 if (!download_manager) { |
| 369 // NULL in unittests or if the page closed right after starting the | 354 // NULL in unittests or if the page closed right after starting the |
| 370 // download. | 355 // download. |
| 371 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED); | 356 if (!started_cb.is_null()) |
| 357 started_cb.Run(DownloadId(), net::ERR_ACCESS_DENIED); | |
| 372 return; | 358 return; |
| 373 } | 359 } |
| 374 DownloadId download_id = download_manager->delegate()->GetNextId(); | 360 DownloadId download_id = download_manager->delegate()->GetNextId(); |
| 375 info->download_id = download_id; | 361 info->download_id = download_id; |
| 376 | 362 |
| 377 // NOTE: StartDownload triggers creation of the download destination file | |
| 378 // that will hold the downloaded data. SetDownloadID unblocks the | |
| 379 // DownloadResourceHandler to begin forwarding network data to the download | |
| 380 // destination file. The sequence of these two steps is critical as creation | |
| 381 // of the downloaded destination file has to happen before we attempt to | |
| 382 // append data to it. Both of those operations happen on the FILE thread. | |
| 383 | |
| 384 download_file_manager_->StartDownload(info.release(), handle); | |
| 385 | |
| 386 BrowserThread::PostTask( | 363 BrowserThread::PostTask( |
| 387 BrowserThread::IO, FROM_HERE, | 364 BrowserThread::IO, FROM_HERE, |
| 388 base::Bind(&DownloadResourceHandler::SetDownloadID, this, | 365 base::Bind(&DownloadResourceHandler::SetDownloadID, this, |
| 389 download_id)); | 366 download_id)); |
| 390 | 367 |
| 391 CallStartedCB(download_id, net::OK); | 368 download_file_manager_->StartDownload(info.Pass(), pipe.Pass(), handle); |
| 369 | |
| 370 if (!started_cb.is_null()) | |
| 371 started_cb.Run(download_id, net::OK); | |
| 392 } | 372 } |
| 393 | 373 |
| 394 void DownloadResourceHandler::SetDownloadID(content::DownloadId id) { | 374 void DownloadResourceHandler::SetDownloadID(content::DownloadId id) { |
| 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 396 | 376 |
| 397 download_id_ = id; | 377 download_id_ = id; |
| 398 MaybeResumeRequest(); | 378 MaybeResumeRequest(); |
|
darin (slow to review)
2012/05/24 22:01:36
do we still need this call to MaybeResumeRequest?
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
I believe not. It was in for a while because we w
| |
| 399 } | 379 } |
| 400 | 380 |
| 401 // If the content-length header is not present (or contains something other | 381 // If the content-length header is not present (or contains something other |
| 402 // than numbers), the incoming content_length is -1 (unknown size). | 382 // than numbers), the incoming content_length is -1 (unknown size). |
| 403 // Set the content length to 0 to indicate unknown size to DownloadManager. | 383 // Set the content length to 0 to indicate unknown size to DownloadManager. |
| 404 void DownloadResourceHandler::SetContentLength(const int64& content_length) { | 384 void DownloadResourceHandler::SetContentLength(const int64& content_length) { |
| 405 content_length_ = 0; | 385 content_length_ = 0; |
| 406 if (content_length > 0) | 386 if (content_length > 0) |
| 407 content_length_ = content_length; | 387 content_length_ = content_length; |
| 408 } | 388 } |
| 409 | 389 |
| 410 void DownloadResourceHandler::SetContentDisposition( | 390 void DownloadResourceHandler::SetContentDisposition( |
| 411 const std::string& content_disposition) { | 391 const std::string& content_disposition) { |
| 412 content_disposition_ = content_disposition; | 392 content_disposition_ = content_disposition; |
| 413 } | 393 } |
| 414 | 394 |
| 415 void DownloadResourceHandler::CheckWriteProgress() { | |
| 416 if (!buffer_.get()) | |
| 417 return; // The download completed while we were waiting to run. | |
| 418 | |
| 419 if (buffer_->size() > kLoadsToWrite) { | |
| 420 // We'll come back later and see if it's okay to unpause the request. | |
| 421 CheckWriteProgressLater(); | |
| 422 return; | |
| 423 } | |
| 424 | |
| 425 MaybeResumeRequest(); | |
| 426 } | |
| 427 | |
| 428 void DownloadResourceHandler::PauseRequest() { | 395 void DownloadResourceHandler::PauseRequest() { |
| 429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 430 | 397 |
| 431 ++pause_count_; | 398 ++pause_count_; |
| 432 } | 399 } |
| 433 | 400 |
| 434 void DownloadResourceHandler::ResumeRequest() { | 401 void DownloadResourceHandler::ResumeRequest() { |
| 435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 436 DCHECK_LT(0, pause_count_); | 403 DCHECK_LT(0, pause_count_); |
| 437 | 404 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 467 global_id_.request_id, | 434 global_id_.request_id, |
| 468 render_view_id_, | 435 render_view_id_, |
| 469 save_info_.file_path.value().c_str()); | 436 save_info_.file_path.value().c_str()); |
| 470 } | 437 } |
| 471 | 438 |
| 472 DownloadResourceHandler::~DownloadResourceHandler() { | 439 DownloadResourceHandler::~DownloadResourceHandler() { |
| 473 // This won't do anything if the callback was called before. | 440 // This won't do anything if the callback was called before. |
| 474 // If it goes through, it will likely be because OnWillStart() returned | 441 // If it goes through, it will likely be because OnWillStart() returned |
| 475 // false somewhere in the chain of resource handlers. | 442 // false somewhere in the chain of resource handlers. |
| 476 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED); | 443 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED); |
| 477 } | |
| 478 | 444 |
| 479 void DownloadResourceHandler::CheckWriteProgressLater() { | 445 // Remove output pipe callback if a pipe exists. |
| 480 if (!check_write_progress_timer_.IsRunning()) { | 446 if (pipe_input_.get()) |
| 481 check_write_progress_timer_.Start( | 447 pipe_input_->RegisterCallback(base::Closure()); |
| 482 FROM_HERE, | |
| 483 base::TimeDelta::FromMilliseconds(kThrottleTimeMs), | |
| 484 this, | |
| 485 &DownloadResourceHandler::CheckWriteProgress); | |
| 486 } | |
| 487 } | 448 } |
| 488 | 449 |
| 489 void DownloadResourceHandler::MaybeResumeRequest() { | 450 void DownloadResourceHandler::MaybeResumeRequest() { |
|
darin (slow to review)
2012/05/24 22:01:36
i'd probably just fold this code into ResumeReques
Randy Smith (Not in Mondays)
2012/05/26 02:36:54
Done.
| |
| 490 if (!was_deferred_) | 451 if (!was_deferred_) |
| 491 return; | 452 return; |
| 492 | |
| 493 if (pause_count_ > 0) | 453 if (pause_count_ > 0) |
| 494 return; | 454 return; |
| 495 if (download_id_ == DownloadId::Invalid()) | |
| 496 return; | |
| 497 if (buffer_.get() && (buffer_->size() > kLoadsToWrite)) | |
| 498 return; | |
| 499 | 455 |
| 500 was_deferred_ = false; | 456 was_deferred_ = false; |
| 501 ResourceDispatcherHostImpl::Get()->ResumeDeferredRequest( | 457 ResourceDispatcherHostImpl::Get()->ResumeDeferredRequest( |
| 502 global_id_.child_id, | 458 global_id_.child_id, |
| 503 global_id_.request_id); | 459 global_id_.request_id); |
| 504 } | 460 } |
| OLD | NEW |