Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: content/browser/download/download_resource_handler.cc

Issue 10392111: Use ByteStream in downloads system to decouple source and sink. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed lack of virtual keyword on destructor. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 kDownloadByteStreamSize = 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
55 // Static function in order to prevent any accidental accesses to
56 // DownloadResourceHandler members from the UI thread.
57 static void StartOnUIThread(
58 scoped_ptr<DownloadCreateInfo> info,
59 scoped_ptr<content::ByteStreamReader> stream,
60 scoped_refptr<DownloadFileManager> download_file_manager,
61 const DownloadRequestHandle& handle,
62 const DownloadResourceHandler::OnStartedCallback& started_cb) {
63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
64
65 DownloadManager* download_manager = handle.GetDownloadManager();
66 if (!download_manager) {
67 // NULL in unittests or if the page closed right after starting the
68 // download.
69 if (!started_cb.is_null())
70 started_cb.Run(DownloadId(), net::ERR_ACCESS_DENIED);
71 return;
72 }
73 DownloadId download_id = download_manager->delegate()->GetNextId();
74 info->download_id = download_id;
75
76 download_file_manager->StartDownload(info.Pass(), stream.Pass(), handle);
77
78 if (!started_cb.is_null())
79 started_cb.Run(download_id, net::OK);
80 }
81
52 } // namespace 82 } // namespace
53 83
54 DownloadResourceHandler::DownloadResourceHandler( 84 DownloadResourceHandler::DownloadResourceHandler(
55 int render_process_host_id, 85 int render_process_host_id,
56 int render_view_id, 86 int render_view_id,
57 int request_id, 87 int request_id,
58 const GURL& url, 88 const GURL& url,
59 DownloadFileManager* download_file_manager, 89 scoped_refptr<DownloadFileManager> download_file_manager,
60 net::URLRequest* request, 90 net::URLRequest* request,
61 const DownloadResourceHandler::OnStartedCallback& started_cb, 91 const DownloadResourceHandler::OnStartedCallback& started_cb,
62 const content::DownloadSaveInfo& save_info) 92 const content::DownloadSaveInfo& save_info)
63 : download_id_(DownloadId::Invalid()), 93 : global_id_(render_process_host_id, request_id),
64 global_id_(render_process_host_id, request_id),
65 render_view_id_(render_view_id), 94 render_view_id_(render_view_id),
66 content_length_(0), 95 content_length_(0),
67 download_file_manager_(download_file_manager), 96 download_file_manager_(download_file_manager),
68 request_(request), 97 request_(request),
69 started_cb_(started_cb), 98 started_cb_(started_cb),
70 save_info_(save_info), 99 save_info_(save_info),
71 buffer_(new content::DownloadBuffer),
72 last_buffer_size_(0), 100 last_buffer_size_(0),
73 bytes_read_(0), 101 bytes_read_(0),
74 pause_count_(0), 102 pause_count_(0),
75 was_deferred_(false), 103 was_deferred_(false),
76 on_response_started_called_(false) { 104 on_response_started_called_(false) {
77 download_stats::RecordDownloadCount(download_stats::UNTHROTTLED_COUNT); 105 download_stats::RecordDownloadCount(download_stats::UNTHROTTLED_COUNT);
78 } 106 }
79 107
80 bool DownloadResourceHandler::OnUploadProgress(int request_id, 108 bool DownloadResourceHandler::OnUploadProgress(int request_id,
81 uint64 position, 109 uint64 position,
82 uint64 size) { 110 uint64 size) {
83 return true; 111 return true;
84 } 112 }
85 113
86 // Not needed, as this event handler ought to be the final resource. 114 // Not needed, as this event handler ought to be the final resource.
87 bool DownloadResourceHandler::OnRequestRedirected( 115 bool DownloadResourceHandler::OnRequestRedirected(
88 int request_id, 116 int request_id,
89 const GURL& url, 117 const GURL& url,
90 content::ResourceResponse* response, 118 content::ResourceResponse* response,
91 bool* defer) { 119 bool* defer) {
92 return true; 120 return true;
93 } 121 }
94 122
95 // Send the download creation information to the download thread. 123 // Send the download creation information to the download thread.
96 bool DownloadResourceHandler::OnResponseStarted( 124 bool DownloadResourceHandler::OnResponseStarted(
97 int request_id, 125 int request_id,
98 content::ResourceResponse* response, 126 content::ResourceResponse* response,
99 bool* defer) { 127 bool* defer) {
128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
100 // There can be only one (call) 129 // There can be only one (call)
101 DCHECK(!on_response_started_called_); 130 DCHECK(!on_response_started_called_);
102 on_response_started_called_ = true; 131 on_response_started_called_ = true;
103 132
104 VLOG(20) << __FUNCTION__ << "()" << DebugString() 133 VLOG(20) << __FUNCTION__ << "()" << DebugString()
105 << " request_id = " << request_id; 134 << " request_id = " << request_id;
106 download_start_time_ = base::TimeTicks::Now(); 135 download_start_time_ = base::TimeTicks::Now();
107 136
108 // If it's a download, we don't want to poison the cache with it. 137 // If it's a download, we don't want to poison the cache with it.
109 request_->StopCaching(); 138 request_->StopCaching();
110 139
111 std::string content_disposition; 140 std::string content_disposition;
112 request_->GetResponseHeaderByName("content-disposition", 141 request_->GetResponseHeaderByName("content-disposition",
113 &content_disposition); 142 &content_disposition);
114 SetContentDisposition(content_disposition); 143 SetContentDisposition(content_disposition);
115 SetContentLength(response->content_length); 144 SetContentLength(response->content_length);
116 145
117 const ResourceRequestInfoImpl* request_info = 146 const ResourceRequestInfoImpl* request_info =
118 ResourceRequestInfoImpl::ForRequest(request_); 147 ResourceRequestInfoImpl::ForRequest(request_);
119 148
120 // Deleted in DownloadManager. 149 // Deleted in DownloadManager.
121 scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo( 150 scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo(
122 base::Time::Now(), 0, content_length_, DownloadItem::IN_PROGRESS, 151 base::Time::Now(), 0, content_length_, DownloadItem::IN_PROGRESS,
123 request_->net_log(), request_info->has_user_gesture(), 152 request_->net_log(), request_info->has_user_gesture(),
124 request_info->transition_type())); 153 request_info->transition_type()));
154
155 // Create the ByteStream for sending data to the download sink.
156 scoped_ptr<content::ByteStreamReader> stream_reader;
157 CreateByteStream(
158 base::MessageLoopProxy::current(),
159 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
160 kDownloadByteStreamSize, &stream_writer_, &stream_reader);
161 stream_writer_->RegisterCallback(
162 // We're refcounted, so this is a safe callback to pass around.
163 base::Bind(&DownloadResourceHandler::ResumeRequest, this));
164
125 info->url_chain = request_->url_chain(); 165 info->url_chain = request_->url_chain();
126 info->referrer_url = GURL(request_->referrer()); 166 info->referrer_url = GURL(request_->referrer());
127 info->start_time = base::Time::Now(); 167 info->start_time = base::Time::Now();
128 info->received_bytes = save_info_.offset; 168 info->received_bytes = save_info_.offset;
129 info->total_bytes = content_length_; 169 info->total_bytes = content_length_;
130 info->state = DownloadItem::IN_PROGRESS; 170 info->state = DownloadItem::IN_PROGRESS;
131 info->has_user_gesture = request_info->has_user_gesture(); 171 info->has_user_gesture = request_info->has_user_gesture();
132 info->content_disposition = content_disposition_; 172 info->content_disposition = content_disposition_;
133 info->mime_type = response->mime_type; 173 info->mime_type = response->mime_type;
134 info->remote_address = request_->GetSocketAddress().host(); 174 info->remote_address = request_->GetSocketAddress().host();
(...skipping 26 matching lines...) Expand all
161 accept_ranges_ = ""; 201 accept_ranges_ = "";
162 } 202 }
163 203
164 info->prompt_user_for_save_location = 204 info->prompt_user_for_save_location =
165 save_info_.prompt_for_save_location && save_info_.file_path.empty(); 205 save_info_.prompt_for_save_location && save_info_.file_path.empty();
166 info->referrer_charset = request_->context()->referrer_charset(); 206 info->referrer_charset = request_->context()->referrer_charset();
167 info->save_info = save_info_; 207 info->save_info = save_info_;
168 208
169 BrowserThread::PostTask( 209 BrowserThread::PostTask(
170 BrowserThread::UI, FROM_HERE, 210 BrowserThread::UI, FROM_HERE,
171 base::Bind(&DownloadResourceHandler::StartOnUIThread, this, 211 base::Bind(&StartOnUIThread,
172 base::Passed(&info), request_handle)); 212 base::Passed(info.Pass()),
213 base::Passed(stream_reader.Pass()),
214 download_file_manager_,
215 request_handle,
216 // Pass to StartOnUIThread so that variable
217 // access is always on IO thread but function
218 // is called on UI thread.
219 started_cb_));
220 // Guaranteed to be called in StartOnUIThread
221 started_cb_.Reset();
173 222
174 return true; 223 return true;
175 } 224 }
176 225
177 void DownloadResourceHandler::CallStartedCB(DownloadId id, net::Error error) { 226 void DownloadResourceHandler::CallStartedCB(DownloadId id, net::Error error) {
227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
178 if (started_cb_.is_null()) 228 if (started_cb_.is_null())
179 return; 229 return;
180 BrowserThread::PostTask( 230 BrowserThread::PostTask(
181 BrowserThread::UI, FROM_HERE, 231 BrowserThread::UI, FROM_HERE,
182 base::Bind(&CallStartedCBOnUIThread, started_cb_, id, error)); 232 base::Bind(&CallStartedCBOnUIThread, started_cb_, id, error));
183 started_cb_.Reset(); 233 started_cb_.Reset();
184 } 234 }
185 235
186 bool DownloadResourceHandler::OnWillStart(int request_id, 236 bool DownloadResourceHandler::OnWillStart(int request_id,
187 const GURL& url, 237 const GURL& url,
188 bool* defer) { 238 bool* defer) {
189 return true; 239 return true;
190 } 240 }
191 241
192 // Create a new buffer, which will be handed to the download thread for file 242 // Create a new buffer, which will be handed to the download thread for file
193 // writing and deletion. 243 // writing and deletion.
194 bool DownloadResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf, 244 bool DownloadResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
195 int* buf_size, int min_size) { 245 int* buf_size, int min_size) {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196 DCHECK(buf && buf_size); 247 DCHECK(buf && buf_size);
197 if (!read_buffer_) { 248 if (!read_buffer_) {
198 *buf_size = min_size < 0 ? kReadBufSize : min_size; 249 *buf_size = min_size < 0 ? kReadBufSize : min_size;
199 last_buffer_size_ = *buf_size; 250 last_buffer_size_ = *buf_size;
200 read_buffer_ = new net::IOBuffer(*buf_size); 251 read_buffer_ = new net::IOBuffer(*buf_size);
201 } 252 }
202 *buf = read_buffer_.get(); 253 *buf = read_buffer_.get();
203 return true; 254 return true;
204 } 255 }
205 256
206 // Pass the buffer to the download file writer. 257 // Pass the buffer to the download file writer.
207 bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read, 258 bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read,
208 bool* defer) { 259 bool* defer) {
260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
209 if (!read_buffer_) { 261 if (!read_buffer_) {
210 // Ignore spurious OnReadCompleted! Deferring from OnReadCompleted tells 262 // Ignore spurious OnReadCompleted! Deferring from OnReadCompleted tells
211 // the ResourceDispatcherHost that we did not consume the data. 263 // the ResourceDispatcherHost that we did not consume the data.
212 // ResumeDeferredRequest then repeats the last OnReadCompleted call. 264 // ResumeDeferredRequest then repeats the last OnReadCompleted call.
213 // TODO(darin): Fix the ResourceDispatcherHost to avoid this hack! 265 // TODO(darin): Fix the ResourceDispatcherHost to avoid this hack!
214 return true; 266 return true;
215 } 267 }
216 268
217 if (pause_count_ > 0) { 269 if (pause_count_ > 0) {
218 *defer = was_deferred_ = true; 270 *defer = was_deferred_ = true;
219 return true; 271 return true;
220 } 272 }
221 273
222 if (download_id_ == DownloadId::Invalid()) {
223 // We can't start saving the data before we create the file on disk and
224 // have a download id. The request will be un-paused in
225 // DownloadFileManager::CreateDownloadFile.
226 *defer = was_deferred_ = true;
227 return true;
228 }
229
230 base::TimeTicks now(base::TimeTicks::Now()); 274 base::TimeTicks now(base::TimeTicks::Now());
231 if (!last_read_time_.is_null()) { 275 if (!last_read_time_.is_null()) {
232 double seconds_since_last_read = (now - last_read_time_).InSecondsF(); 276 double seconds_since_last_read = (now - last_read_time_).InSecondsF();
233 if (now == last_read_time_) 277 if (now == last_read_time_)
234 // Use 1/10 ms as a "very small number" so that we avoid 278 // Use 1/10 ms as a "very small number" so that we avoid
235 // divide-by-zero error and still record a very high potential bandwidth. 279 // divide-by-zero error and still record a very high potential bandwidth.
236 seconds_since_last_read = 0.00001; 280 seconds_since_last_read = 0.00001;
237 281
238 double actual_bandwidth = (*bytes_read)/seconds_since_last_read; 282 double actual_bandwidth = (*bytes_read)/seconds_since_last_read;
239 double potential_bandwidth = last_buffer_size_/seconds_since_last_read; 283 double potential_bandwidth = last_buffer_size_/seconds_since_last_read;
240 download_stats::RecordBandwidth(actual_bandwidth, potential_bandwidth); 284 download_stats::RecordBandwidth(actual_bandwidth, potential_bandwidth);
241 } 285 }
242 last_read_time_ = now; 286 last_read_time_ = now;
243 287
244 if (!*bytes_read) 288 if (!*bytes_read)
245 return true; 289 return true;
246 bytes_read_ += *bytes_read; 290 bytes_read_ += *bytes_read;
247 DCHECK(read_buffer_); 291 DCHECK(read_buffer_);
248 // Swap the data.
249 net::IOBuffer* io_buffer = NULL;
250 read_buffer_.swap(&io_buffer);
251 size_t vector_size = buffer_->AddData(io_buffer, *bytes_read);
252 bool need_update = (vector_size == 1); // Buffer was empty.
253 292
254 // We are passing ownership of this buffer to the download file manager. 293 // Take the data ship it down the stream. If the stream is full, pause the
255 if (need_update) { 294 // request; the stream callback will resume it.
256 BrowserThread::PostTask( 295 if (!stream_writer_->Write(read_buffer_, *bytes_read)) {
257 BrowserThread::FILE, FROM_HERE, 296 PauseRequest();
258 base::Bind(&DownloadFileManager::UpdateDownload, 297 *defer = was_deferred_ = true;
259 download_file_manager_, download_id_, buffer_)); 298 last_stream_pause_time_ = now;
260 } 299 }
261 300
262 // We schedule a pause outside of the read loop if there is too much file 301 read_buffer_ = NULL; // Drop our reference.
263 // writing work to do.
264 if (vector_size > kLoadsToWrite) {
265 *defer = was_deferred_ = true;
266 CheckWriteProgressLater();
267 }
268 302
269 return true; 303 return true;
270 } 304 }
271 305
272 bool DownloadResourceHandler::OnResponseCompleted( 306 bool DownloadResourceHandler::OnResponseCompleted(
273 int request_id, 307 int request_id,
274 const net::URLRequestStatus& status, 308 const net::URLRequestStatus& status,
275 const std::string& security_info) { 309 const std::string& security_info) {
310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
276 VLOG(20) << __FUNCTION__ << "()" << DebugString() 311 VLOG(20) << __FUNCTION__ << "()" << DebugString()
277 << " request_id = " << request_id 312 << " request_id = " << request_id
278 << " status.status() = " << status.status() 313 << " status.status() = " << status.status()
279 << " status.error() = " << status.error(); 314 << " status.error() = " << status.error();
280 int response = status.is_success() ? request_->GetResponseCode() : 0; 315 int response_code = status.is_success() ? request_->GetResponseCode() : 0;
281 if (download_id_.IsValid()) {
282 OnResponseCompletedInternal(request_id, status, security_info, response);
283 } else {
284 // We got cancelled before the task which sets the id ran on the IO thread.
285 // Wait for it.
286 BrowserThread::PostTaskAndReply(
287 BrowserThread::UI, FROM_HERE,
288 base::Bind(&base::DoNothing),
289 base::Bind(&DownloadResourceHandler::OnResponseCompletedInternal, this,
290 request_id, status, security_info, response));
291 }
292 // Can't trust request_ being value after this point.
293 request_ = NULL;
294 return true;
295 }
296 316
297 void DownloadResourceHandler::OnResponseCompletedInternal(
298 int request_id,
299 const net::URLRequestStatus& status,
300 const std::string& security_info,
301 int response_code) {
302 // NOTE: |request_| may be a dangling pointer at this point.
303 VLOG(20) << __FUNCTION__ << "()"
304 << " request_id = " << request_id
305 << " status.status() = " << status.status()
306 << " status.error() = " << status.error();
307 net::Error error_code = net::OK; 317 net::Error error_code = net::OK;
308 if (status.status() == net::URLRequestStatus::FAILED) 318 if (status.status() == net::URLRequestStatus::FAILED)
309 error_code = static_cast<net::Error>(status.error()); // Normal case. 319 error_code = static_cast<net::Error>(status.error()); // Normal case.
310 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are 320 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are
311 // allowed since a number of servers in the wild close the connection too 321 // allowed since a number of servers in the wild close the connection too
312 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - 322 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 -
313 // treat downloads as complete in both cases, so we follow their lead. 323 // treat downloads as complete in both cases, so we follow their lead.
314 if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH || 324 if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH ||
315 error_code == net::ERR_INCOMPLETE_CHUNKED_ENCODING) { 325 error_code == net::ERR_INCOMPLETE_CHUNKED_ENCODING) {
316 error_code = net::OK; 326 error_code = net::OK;
(...skipping 23 matching lines...) Expand all
340 break; 350 break;
341 default: 351 default:
342 reason = content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; 352 reason = content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED;
343 break; 353 break;
344 } 354 }
345 } 355 }
346 } 356 }
347 357
348 download_stats::RecordAcceptsRanges(accept_ranges_, bytes_read_); 358 download_stats::RecordAcceptsRanges(accept_ranges_, bytes_read_);
349 359
350 // If the callback was already run on the UI thread, this will be a noop. 360 CallStartedCB(DownloadId(), error_code);
351 CallStartedCB(download_id_, error_code);
352 361
353 // We transfer ownership to |DownloadFileManager| to delete |buffer_|, 362 // Send the info down the stream. Conditional is in case we get
354 // so that any functions queued up on the FILE thread are executed 363 // OnResponseCompleted without OnResponseStarted.
355 // before deletion. 364 if (stream_writer_.get())
356 BrowserThread::PostTask( 365 stream_writer_->Close(reason);
357 BrowserThread::FILE, FROM_HERE, 366
358 base::Bind(&DownloadFileManager::OnResponseCompleted, 367 stream_writer_.reset(); // We no longer need the stream.
359 download_file_manager_, download_id_, reason, security_info));
360 buffer_ = NULL; // The buffer is longer needed by |DownloadResourceHandler|.
361 read_buffer_ = NULL; 368 read_buffer_ = NULL;
369
370 // Stats
371 download_stats::RecordNetworkBandwidth(
372 bytes_read_, base::TimeTicks::Now() - download_start_time_,
373 total_pause_time_);
374
375 return true;
362 } 376 }
363 377
364 void DownloadResourceHandler::OnRequestClosed() { 378 void DownloadResourceHandler::OnRequestClosed() {
379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
365 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", 380 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration",
366 base::TimeTicks::Now() - download_start_time_); 381 base::TimeTicks::Now() - download_start_time_);
367 }
368 382
369 void DownloadResourceHandler::StartOnUIThread( 383 // Can't trust request_ being valid after this point.
370 scoped_ptr<DownloadCreateInfo> info, 384 request_ = NULL;
371 const DownloadRequestHandle& handle) {
372 DownloadManager* download_manager = handle.GetDownloadManager();
373 if (!download_manager) {
374 // NULL in unittests or if the page closed right after starting the
375 // download.
376 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED);
377 return;
378 }
379 DownloadId download_id = download_manager->delegate()->GetNextId();
380 info->download_id = download_id;
381
382 // NOTE: StartDownload triggers creation of the download destination file
383 // that will hold the downloaded data. SetDownloadID unblocks the
384 // DownloadResourceHandler to begin forwarding network data to the download
385 // destination file. The sequence of these two steps is critical as creation
386 // of the downloaded destination file has to happen before we attempt to
387 // append data to it. Both of those operations happen on the FILE thread.
388
389 download_file_manager_->StartDownload(info.release(), handle);
390
391 BrowserThread::PostTask(
392 BrowserThread::IO, FROM_HERE,
393 base::Bind(&DownloadResourceHandler::SetDownloadID, this,
394 download_id));
395
396 CallStartedCB(download_id, net::OK);
397 }
398
399 void DownloadResourceHandler::SetDownloadID(content::DownloadId id) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
401
402 download_id_ = id;
403 MaybeResumeRequest();
404 } 385 }
405 386
406 // If the content-length header is not present (or contains something other 387 // If the content-length header is not present (or contains something other
407 // than numbers), the incoming content_length is -1 (unknown size). 388 // than numbers), the incoming content_length is -1 (unknown size).
408 // Set the content length to 0 to indicate unknown size to DownloadManager. 389 // Set the content length to 0 to indicate unknown size to DownloadManager.
409 void DownloadResourceHandler::SetContentLength(const int64& content_length) { 390 void DownloadResourceHandler::SetContentLength(const int64& content_length) {
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
410 content_length_ = 0; 392 content_length_ = 0;
411 if (content_length > 0) 393 if (content_length > 0)
412 content_length_ = content_length; 394 content_length_ = content_length;
413 } 395 }
414 396
415 void DownloadResourceHandler::SetContentDisposition( 397 void DownloadResourceHandler::SetContentDisposition(
416 const std::string& content_disposition) { 398 const std::string& content_disposition) {
399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
417 content_disposition_ = content_disposition; 400 content_disposition_ = content_disposition;
418 } 401 }
419 402
420 void DownloadResourceHandler::CheckWriteProgress() {
421 if (!buffer_.get())
422 return; // The download completed while we were waiting to run.
423
424 if (buffer_->size() > kLoadsToWrite) {
425 // We'll come back later and see if it's okay to unpause the request.
426 CheckWriteProgressLater();
427 return;
428 }
429
430 MaybeResumeRequest();
431 }
432
433 void DownloadResourceHandler::PauseRequest() { 403 void DownloadResourceHandler::PauseRequest() {
434 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
435 405
436 ++pause_count_; 406 ++pause_count_;
437 } 407 }
438 408
439 void DownloadResourceHandler::ResumeRequest() { 409 void DownloadResourceHandler::ResumeRequest() {
440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
441 DCHECK_LT(0, pause_count_); 411 DCHECK_LT(0, pause_count_);
442 412
443 --pause_count_; 413 --pause_count_;
444 MaybeResumeRequest(); 414
415 if (!was_deferred_)
416 return;
417 if (pause_count_ > 0)
418 return;
419
420 was_deferred_ = false;
421 if (!last_stream_pause_time_.is_null()) {
422 total_pause_time_ += (base::TimeTicks::Now() - last_stream_pause_time_);
423 last_stream_pause_time_ = base::TimeTicks();
424 }
425 ResourceDispatcherHostImpl::Get()->ResumeDeferredRequest(
426 global_id_.child_id,
427 global_id_.request_id);
445 } 428 }
446 429
447 void DownloadResourceHandler::CancelRequest() { 430 void DownloadResourceHandler::CancelRequest() {
448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
449 432
450 ResourceDispatcherHostImpl::Get()->CancelRequest( 433 ResourceDispatcherHostImpl::Get()->CancelRequest(
451 global_id_.child_id, 434 global_id_.child_id,
452 global_id_.request_id, 435 global_id_.request_id,
453 false); 436 false);
454 } 437 }
455 438
456 std::string DownloadResourceHandler::DebugString() const { 439 std::string DownloadResourceHandler::DebugString() const {
457 return base::StringPrintf("{" 440 return base::StringPrintf("{"
458 " url_ = " "\"%s\"" 441 " url_ = " "\"%s\""
459 " download_id_ = " "%d"
460 " global_id_ = {" 442 " global_id_ = {"
461 " child_id = " "%d" 443 " child_id = " "%d"
462 " request_id = " "%d" 444 " request_id = " "%d"
463 " }" 445 " }"
464 " render_view_id_ = " "%d" 446 " render_view_id_ = " "%d"
465 " save_info_.file_path = \"%" PRFilePath "\"" 447 " save_info_.file_path = \"%" PRFilePath "\""
466 " }", 448 " }",
467 request_ ? 449 request_ ?
468 request_->url().spec().c_str() : 450 request_->url().spec().c_str() :
469 "<NULL request>", 451 "<NULL request>",
470 download_id_.local(),
471 global_id_.child_id, 452 global_id_.child_id,
472 global_id_.request_id, 453 global_id_.request_id,
473 render_view_id_, 454 render_view_id_,
474 save_info_.file_path.value().c_str()); 455 save_info_.file_path.value().c_str());
475 } 456 }
476 457
477 DownloadResourceHandler::~DownloadResourceHandler() { 458 DownloadResourceHandler::~DownloadResourceHandler() {
459 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
460
478 // This won't do anything if the callback was called before. 461 // This won't do anything if the callback was called before.
479 // If it goes through, it will likely be because OnWillStart() returned 462 // If it goes through, it will likely be because OnWillStart() returned
480 // false somewhere in the chain of resource handlers. 463 // false somewhere in the chain of resource handlers.
481 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED); 464 CallStartedCB(DownloadId(), net::ERR_ACCESS_DENIED);
465
466 // Remove output stream callback if a stream exists.
467 if (stream_writer_.get())
468 stream_writer_->RegisterCallback(base::Closure());
482 } 469 }
483 470
484 void DownloadResourceHandler::CheckWriteProgressLater() {
485 if (!check_write_progress_timer_.IsRunning()) {
486 check_write_progress_timer_.Start(
487 FROM_HERE,
488 base::TimeDelta::FromMilliseconds(kThrottleTimeMs),
489 this,
490 &DownloadResourceHandler::CheckWriteProgress);
491 }
492 }
493
494 void DownloadResourceHandler::MaybeResumeRequest() {
495 if (!was_deferred_)
496 return;
497
498 if (pause_count_ > 0)
499 return;
500 if (download_id_ == DownloadId::Invalid())
501 return;
502 if (buffer_.get() && (buffer_->size() > kLoadsToWrite))
503 return;
504
505 was_deferred_ = false;
506 ResourceDispatcherHostImpl::Get()->ResumeDeferredRequest(
507 global_id_.child_id,
508 global_id_.request_id);
509 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698