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

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

Powered by Google App Engine
This is Rietveld 408576698