OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/download/download_file.h" | 5 #include "chrome/browser/download/download_file.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/path_service.h" | 8 #include "base/path_service.h" |
9 #include "base/stl_util-inl.h" | 9 #include "base/stl_util-inl.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
11 #include "base/task.h" | 11 #include "base/task.h" |
12 #include "base/thread.h" | 12 #include "base/thread.h" |
13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
14 #include "chrome/browser/browser_process.h" | 14 #include "chrome/browser/chrome_thread.h" |
15 #include "chrome/browser/download/download_manager.h" | 15 #include "chrome/browser/download/download_manager.h" |
16 #include "chrome/browser/net/chrome_url_request_context.h" | 16 #include "chrome/browser/net/chrome_url_request_context.h" |
17 #include "chrome/browser/profile.h" | 17 #include "chrome/browser/profile.h" |
18 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" | 18 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" |
19 #include "chrome/browser/tab_contents/tab_util.h" | 19 #include "chrome/browser/tab_contents/tab_util.h" |
20 #include "chrome/browser/tab_contents/tab_contents.h" | 20 #include "chrome/browser/tab_contents/tab_contents.h" |
21 #include "chrome/common/chrome_paths.h" | 21 #include "chrome/common/chrome_paths.h" |
22 #include "chrome/common/platform_util.h" | 22 #include "chrome/common/platform_util.h" |
23 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
24 #include "net/base/io_buffer.h" | 24 #include "net/base/io_buffer.h" |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 #elif defined(OS_MACOSX) | 152 #elif defined(OS_MACOSX) |
153 file_metadata::AddQuarantineMetadataToFile(full_path_, source_url_, | 153 file_metadata::AddQuarantineMetadataToFile(full_path_, source_url_, |
154 referrer_url_); | 154 referrer_url_); |
155 file_metadata::AddOriginMetadataToFile(full_path_, source_url_, | 155 file_metadata::AddOriginMetadataToFile(full_path_, source_url_, |
156 referrer_url_); | 156 referrer_url_); |
157 #endif | 157 #endif |
158 } | 158 } |
159 | 159 |
160 // DownloadFileManager implementation ------------------------------------------ | 160 // DownloadFileManager implementation ------------------------------------------ |
161 | 161 |
162 DownloadFileManager::DownloadFileManager(MessageLoop* ui_loop, | 162 DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh) |
163 ResourceDispatcherHost* rdh) | |
164 : next_id_(0), | 163 : next_id_(0), |
165 ui_loop_(ui_loop), | |
166 file_loop_(NULL), | |
167 io_loop_(NULL), | |
168 resource_dispatcher_host_(rdh) { | 164 resource_dispatcher_host_(rdh) { |
169 } | 165 } |
170 | 166 |
171 DownloadFileManager::~DownloadFileManager() { | 167 DownloadFileManager::~DownloadFileManager() { |
172 // Check for clean shutdown. | 168 // Check for clean shutdown. |
173 DCHECK(downloads_.empty()); | 169 DCHECK(downloads_.empty()); |
174 ui_progress_.clear(); | 170 ui_progress_.clear(); |
175 } | 171 } |
176 | 172 |
177 void DownloadFileManager::Initialize() { | |
178 io_loop_ = g_browser_process->io_thread()->message_loop(); | |
179 file_loop_ = g_browser_process->file_thread()->message_loop(); | |
180 } | |
181 | |
182 // Called during the browser shutdown process to clean up any state (open files, | 173 // Called during the browser shutdown process to clean up any state (open files, |
183 // timers) that live on the download_thread_. | 174 // timers) that live on the download_thread_. |
184 void DownloadFileManager::Shutdown() { | 175 void DownloadFileManager::Shutdown() { |
185 DCHECK(MessageLoop::current() == ui_loop_); | 176 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
186 StopUpdateTimer(); | 177 StopUpdateTimer(); |
187 file_loop_->PostTask(FROM_HERE, | 178 ChromeThread::PostTask( |
188 NewRunnableMethod(this, | 179 ChromeThread::FILE, FROM_HERE, |
189 &DownloadFileManager::OnShutdown)); | 180 NewRunnableMethod(this, &DownloadFileManager::OnShutdown)); |
190 } | 181 } |
191 | 182 |
192 // Cease download thread operations. | 183 // Cease download thread operations. |
193 void DownloadFileManager::OnShutdown() { | 184 void DownloadFileManager::OnShutdown() { |
194 DCHECK(MessageLoop::current() == file_loop_); | 185 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
195 // Delete any partial downloads during shutdown. | 186 // Delete any partial downloads during shutdown. |
196 for (DownloadFileMap::iterator it = downloads_.begin(); | 187 for (DownloadFileMap::iterator it = downloads_.begin(); |
197 it != downloads_.end(); ++it) { | 188 it != downloads_.end(); ++it) { |
198 DownloadFile* download = it->second; | 189 DownloadFile* download = it->second; |
199 if (download->in_progress()) | 190 if (download->in_progress()) |
200 download->Cancel(); | 191 download->Cancel(); |
201 delete download; | 192 delete download; |
202 } | 193 } |
203 downloads_.clear(); | 194 downloads_.clear(); |
204 } | 195 } |
205 | 196 |
206 // Lookup one in-progress download. | 197 // Lookup one in-progress download. |
207 DownloadFile* DownloadFileManager::LookupDownload(int id) { | 198 DownloadFile* DownloadFileManager::LookupDownload(int id) { |
208 DownloadFileMap::iterator it = downloads_.find(id); | 199 DownloadFileMap::iterator it = downloads_.find(id); |
209 return it == downloads_.end() ? NULL : it->second; | 200 return it == downloads_.end() ? NULL : it->second; |
210 } | 201 } |
211 | 202 |
212 // The UI progress is updated on the file thread and removed on the UI thread. | 203 // The UI progress is updated on the file thread and removed on the UI thread. |
213 void DownloadFileManager::RemoveDownloadFromUIProgress(int id) { | 204 void DownloadFileManager::RemoveDownloadFromUIProgress(int id) { |
214 DCHECK(MessageLoop::current() == ui_loop_); | 205 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
215 AutoLock lock(progress_lock_); | 206 AutoLock lock(progress_lock_); |
216 if (ui_progress_.find(id) != ui_progress_.end()) | 207 if (ui_progress_.find(id) != ui_progress_.end()) |
217 ui_progress_.erase(id); | 208 ui_progress_.erase(id); |
218 } | 209 } |
219 | 210 |
220 // Throttle updates to the UI thread by only posting update notifications at a | 211 // Throttle updates to the UI thread by only posting update notifications at a |
221 // regularly controlled interval. | 212 // regularly controlled interval. |
222 void DownloadFileManager::StartUpdateTimer() { | 213 void DownloadFileManager::StartUpdateTimer() { |
223 DCHECK(MessageLoop::current() == ui_loop_); | 214 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
224 if (!update_timer_.IsRunning()) { | 215 if (!update_timer_.IsRunning()) { |
225 update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), | 216 update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), |
226 this, &DownloadFileManager::UpdateInProgressDownloads); | 217 this, &DownloadFileManager::UpdateInProgressDownloads); |
227 } | 218 } |
228 } | 219 } |
229 | 220 |
230 void DownloadFileManager::StopUpdateTimer() { | 221 void DownloadFileManager::StopUpdateTimer() { |
231 DCHECK(MessageLoop::current() == ui_loop_); | 222 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
232 update_timer_.Stop(); | 223 update_timer_.Stop(); |
233 } | 224 } |
234 | 225 |
235 // Called on the IO thread once the ResourceDispatcherHost has decided that a | 226 // Called on the IO thread once the ResourceDispatcherHost has decided that a |
236 // request is a download. | 227 // request is a download. |
237 int DownloadFileManager::GetNextId() { | 228 int DownloadFileManager::GetNextId() { |
238 DCHECK(MessageLoop::current() == io_loop_); | 229 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
239 return next_id_++; | 230 return next_id_++; |
240 } | 231 } |
241 | 232 |
242 // Notifications sent from the IO thread and run on the download thread: | 233 // Notifications sent from the IO thread and run on the download thread: |
243 | 234 |
244 // The IO thread created 'info', but the download thread (this method) uses it | 235 // The IO thread created 'info', but the download thread (this method) uses it |
245 // to create a DownloadFile, then passes 'info' to the UI thread where it is | 236 // to create a DownloadFile, then passes 'info' to the UI thread where it is |
246 // finally consumed and deleted. | 237 // finally consumed and deleted. |
247 void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { | 238 void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { |
248 DCHECK(MessageLoop::current() == file_loop_); | 239 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
249 DCHECK(info); | 240 DCHECK(info); |
250 | 241 |
251 DownloadFile* download = new DownloadFile(info); | 242 DownloadFile* download = new DownloadFile(info); |
252 if (!download->Initialize()) { | 243 if (!download->Initialize()) { |
253 // Couldn't open, cancel the operation. The UI thread does not yet know | 244 // Couldn't open, cancel the operation. The UI thread does not yet know |
254 // about this download so we have to clean up 'info'. We need to get back | 245 // about this download so we have to clean up 'info'. We need to get back |
255 // to the IO thread to cancel the network request and CancelDownloadRequest | 246 // to the IO thread to cancel the network request and CancelDownloadRequest |
256 // on the UI thread is the safe way to do that. | 247 // on the UI thread is the safe way to do that. |
257 ChromeThread::PostTask( | 248 ChromeThread::PostTask( |
258 ChromeThread::IO, FROM_HERE, | 249 ChromeThread::IO, FROM_HERE, |
259 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, | 250 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, |
260 resource_dispatcher_host_, | 251 resource_dispatcher_host_, |
261 info->child_id, | 252 info->child_id, |
262 info->request_id)); | 253 info->request_id)); |
263 delete info; | 254 delete info; |
264 delete download; | 255 delete download; |
265 return; | 256 return; |
266 } | 257 } |
267 | 258 |
268 DCHECK(LookupDownload(info->download_id) == NULL); | 259 DCHECK(LookupDownload(info->download_id) == NULL); |
269 downloads_[info->download_id] = download; | 260 downloads_[info->download_id] = download; |
270 info->path = download->full_path(); | 261 info->path = download->full_path(); |
271 { | 262 { |
272 AutoLock lock(progress_lock_); | 263 AutoLock lock(progress_lock_); |
273 ui_progress_[info->download_id] = info->received_bytes; | 264 ui_progress_[info->download_id] = info->received_bytes; |
274 } | 265 } |
275 | 266 |
276 ui_loop_->PostTask(FROM_HERE, | 267 ChromeThread::PostTask( |
277 NewRunnableMethod(this, | 268 ChromeThread::UI, FROM_HERE, |
278 &DownloadFileManager::OnStartDownload, | 269 NewRunnableMethod(this, &DownloadFileManager::OnStartDownload, info)); |
279 info)); | |
280 } | 270 } |
281 | 271 |
282 // We don't forward an update to the UI thread here, since we want to throttle | 272 // We don't forward an update to the UI thread here, since we want to throttle |
283 // the UI update rate via a periodic timer. If the user has cancelled the | 273 // the UI update rate via a periodic timer. If the user has cancelled the |
284 // download (in the UI thread), we may receive a few more updates before the IO | 274 // download (in the UI thread), we may receive a few more updates before the IO |
285 // thread gets the cancel message: we just delete the data since the | 275 // thread gets the cancel message: we just delete the data since the |
286 // DownloadFile has been deleted. | 276 // DownloadFile has been deleted. |
287 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { | 277 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { |
288 DCHECK(MessageLoop::current() == file_loop_); | 278 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
289 std::vector<DownloadBuffer::Contents> contents; | 279 std::vector<DownloadBuffer::Contents> contents; |
290 { | 280 { |
291 AutoLock auto_lock(buffer->lock); | 281 AutoLock auto_lock(buffer->lock); |
292 contents.swap(buffer->contents); | 282 contents.swap(buffer->contents); |
293 } | 283 } |
294 | 284 |
295 DownloadFile* download = LookupDownload(id); | 285 DownloadFile* download = LookupDownload(id); |
296 for (size_t i = 0; i < contents.size(); ++i) { | 286 for (size_t i = 0; i < contents.size(); ++i) { |
297 net::IOBuffer* data = contents[i].first; | 287 net::IOBuffer* data = contents[i].first; |
298 const int data_len = contents[i].second; | 288 const int data_len = contents[i].second; |
299 if (download) | 289 if (download) |
300 download->AppendDataToFile(data->data(), data_len); | 290 download->AppendDataToFile(data->data(), data_len); |
301 data->Release(); | 291 data->Release(); |
302 } | 292 } |
303 | 293 |
304 if (download) { | 294 if (download) { |
305 AutoLock lock(progress_lock_); | 295 AutoLock lock(progress_lock_); |
306 ui_progress_[download->id()] = download->bytes_so_far(); | 296 ui_progress_[download->id()] = download->bytes_so_far(); |
307 } | 297 } |
308 } | 298 } |
309 | 299 |
310 void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) { | 300 void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) { |
311 DCHECK(MessageLoop::current() == file_loop_); | 301 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
312 delete buffer; | 302 delete buffer; |
313 DownloadFileMap::iterator it = downloads_.find(id); | 303 DownloadFileMap::iterator it = downloads_.find(id); |
314 if (it != downloads_.end()) { | 304 if (it != downloads_.end()) { |
315 DownloadFile* download = it->second; | 305 DownloadFile* download = it->second; |
316 download->set_in_progress(false); | 306 download->set_in_progress(false); |
317 | 307 |
318 ui_loop_->PostTask(FROM_HERE, | 308 ChromeThread::PostTask( |
319 NewRunnableMethod(this, | 309 ChromeThread::UI, FROM_HERE, |
320 &DownloadFileManager::OnDownloadFinished, | 310 NewRunnableMethod( |
321 id, | 311 this, &DownloadFileManager::OnDownloadFinished, |
322 download->bytes_so_far())); | 312 id, download->bytes_so_far())); |
323 | 313 |
324 // We need to keep the download around until the UI thread has finalized | 314 // We need to keep the download around until the UI thread has finalized |
325 // the name. | 315 // the name. |
326 if (download->path_renamed()) { | 316 if (download->path_renamed()) { |
327 downloads_.erase(it); | 317 downloads_.erase(it); |
328 delete download; | 318 delete download; |
329 } | 319 } |
330 } | 320 } |
331 | 321 |
332 if (downloads_.empty()) | 322 if (downloads_.empty()) |
333 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 323 ChromeThread::PostTask( |
334 this, &DownloadFileManager::StopUpdateTimer)); | 324 ChromeThread::UI, FROM_HERE, |
| 325 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); |
335 } | 326 } |
336 | 327 |
337 // This method will be sent via a user action, or shutdown on the UI thread, and | 328 // This method will be sent via a user action, or shutdown on the UI thread, and |
338 // run on the download thread. Since this message has been sent from the UI | 329 // run on the download thread. Since this message has been sent from the UI |
339 // thread, the download may have already completed and won't exist in our map. | 330 // thread, the download may have already completed and won't exist in our map. |
340 void DownloadFileManager::CancelDownload(int id) { | 331 void DownloadFileManager::CancelDownload(int id) { |
341 DCHECK(MessageLoop::current() == file_loop_); | 332 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
342 DownloadFileMap::iterator it = downloads_.find(id); | 333 DownloadFileMap::iterator it = downloads_.find(id); |
343 if (it != downloads_.end()) { | 334 if (it != downloads_.end()) { |
344 DownloadFile* download = it->second; | 335 DownloadFile* download = it->second; |
345 download->set_in_progress(false); | 336 download->set_in_progress(false); |
346 | 337 |
347 download->Cancel(); | 338 download->Cancel(); |
348 | 339 |
349 ui_loop_->PostTask(FROM_HERE, | 340 ChromeThread::PostTask( |
350 NewRunnableMethod(this, | 341 ChromeThread::UI, FROM_HERE, |
351 &DownloadFileManager::RemoveDownloadFromUIProgress, | 342 NewRunnableMethod( |
352 download->id())); | 343 this, &DownloadFileManager::RemoveDownloadFromUIProgress, |
| 344 download->id())); |
353 | 345 |
354 if (download->path_renamed()) { | 346 if (download->path_renamed()) { |
355 downloads_.erase(it); | 347 downloads_.erase(it); |
356 delete download; | 348 delete download; |
357 } | 349 } |
358 } | 350 } |
359 | 351 |
360 if (downloads_.empty()) | 352 if (downloads_.empty()) { |
361 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 353 ChromeThread::PostTask( |
362 this, &DownloadFileManager::StopUpdateTimer)); | 354 ChromeThread::UI, FROM_HERE, |
| 355 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); |
| 356 } |
363 } | 357 } |
364 | 358 |
365 // Our periodic timer has fired so send the UI thread updates on all in progress | 359 // Our periodic timer has fired so send the UI thread updates on all in progress |
366 // downloads. | 360 // downloads. |
367 void DownloadFileManager::UpdateInProgressDownloads() { | 361 void DownloadFileManager::UpdateInProgressDownloads() { |
368 DCHECK(MessageLoop::current() == ui_loop_); | 362 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
369 AutoLock lock(progress_lock_); | 363 AutoLock lock(progress_lock_); |
370 ProgressMap::iterator it = ui_progress_.begin(); | 364 ProgressMap::iterator it = ui_progress_.begin(); |
371 for (; it != ui_progress_.end(); ++it) { | 365 for (; it != ui_progress_.end(); ++it) { |
372 const int id = it->first; | 366 const int id = it->first; |
373 DownloadManager* manager = LookupManager(id); | 367 DownloadManager* manager = LookupManager(id); |
374 if (manager) | 368 if (manager) |
375 manager->UpdateDownload(id, it->second); | 369 manager->UpdateDownload(id, it->second); |
376 } | 370 } |
377 } | 371 } |
378 | 372 |
379 // Notifications sent from the download thread and run on the UI thread. | 373 // Notifications sent from the download thread and run on the UI thread. |
380 | 374 |
381 // Lookup the DownloadManager for this TabContents' profile and inform it of | 375 // Lookup the DownloadManager for this TabContents' profile and inform it of |
382 // a new download. | 376 // a new download. |
383 // TODO(paulg): When implementing download restart via the Downloads tab, | 377 // TODO(paulg): When implementing download restart via the Downloads tab, |
384 // there will be no 'render_process_id' or 'render_view_id'. | 378 // there will be no 'render_process_id' or 'render_view_id'. |
385 void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) { | 379 void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) { |
386 DCHECK(MessageLoop::current() == ui_loop_); | 380 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
387 DownloadManager* manager = DownloadManagerFromRenderIds(info->child_id, | 381 DownloadManager* manager = DownloadManagerFromRenderIds(info->child_id, |
388 info->render_view_id); | 382 info->render_view_id); |
389 if (!manager) { | 383 if (!manager) { |
390 ChromeThread::PostTask( | 384 ChromeThread::PostTask( |
391 ChromeThread::IO, FROM_HERE, | 385 ChromeThread::IO, FROM_HERE, |
392 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, | 386 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, |
393 resource_dispatcher_host_, | 387 resource_dispatcher_host_, |
394 info->child_id, | 388 info->child_id, |
395 info->request_id)); | 389 info->request_id)); |
396 delete info; | 390 delete info; |
(...skipping 19 matching lines...) Expand all Loading... |
416 NOTREACHED(); | 410 NOTREACHED(); |
417 | 411 |
418 // StartDownload will clean up |info|. | 412 // StartDownload will clean up |info|. |
419 manager->StartDownload(info); | 413 manager->StartDownload(info); |
420 } | 414 } |
421 | 415 |
422 // Update the Download Manager with the finish state, and remove the request | 416 // Update the Download Manager with the finish state, and remove the request |
423 // tracking entries. | 417 // tracking entries. |
424 void DownloadFileManager::OnDownloadFinished(int id, | 418 void DownloadFileManager::OnDownloadFinished(int id, |
425 int64 bytes_so_far) { | 419 int64 bytes_so_far) { |
426 DCHECK(MessageLoop::current() == ui_loop_); | 420 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
427 DownloadManager* manager = LookupManager(id); | 421 DownloadManager* manager = LookupManager(id); |
428 if (manager) | 422 if (manager) |
429 manager->DownloadFinished(id, bytes_so_far); | 423 manager->DownloadFinished(id, bytes_so_far); |
430 RemoveDownload(id, manager); | 424 RemoveDownload(id, manager); |
431 RemoveDownloadFromUIProgress(id); | 425 RemoveDownloadFromUIProgress(id); |
432 } | 426 } |
433 | 427 |
434 void DownloadFileManager::DownloadUrl( | 428 void DownloadFileManager::DownloadUrl( |
435 const GURL& url, | 429 const GURL& url, |
436 const GURL& referrer, | 430 const GURL& referrer, |
437 const std::string& referrer_charset, | 431 const std::string& referrer_charset, |
438 int render_process_host_id, | 432 int render_process_host_id, |
439 int render_view_id, | 433 int render_view_id, |
440 URLRequestContextGetter* request_context_getter) { | 434 URLRequestContextGetter* request_context_getter) { |
441 DCHECK(MessageLoop::current() == ui_loop_); | 435 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
442 base::Thread* thread = g_browser_process->io_thread(); | 436 ChromeThread::PostTask( |
443 if (thread) { | 437 ChromeThread::IO, FROM_HERE, |
444 thread->message_loop()->PostTask(FROM_HERE, | |
445 NewRunnableMethod(this, | 438 NewRunnableMethod(this, |
446 &DownloadFileManager::OnDownloadUrl, | 439 &DownloadFileManager::OnDownloadUrl, |
447 url, | 440 url, |
448 referrer, | 441 referrer, |
449 referrer_charset, | 442 referrer_charset, |
450 render_process_host_id, | 443 render_process_host_id, |
451 render_view_id, | 444 render_view_id, |
452 request_context_getter)); | 445 request_context_getter)); |
453 } | |
454 } | 446 } |
455 | 447 |
456 // Relate a download ID to its owning DownloadManager. | 448 // Relate a download ID to its owning DownloadManager. |
457 DownloadManager* DownloadFileManager::LookupManager(int download_id) { | 449 DownloadManager* DownloadFileManager::LookupManager(int download_id) { |
458 DCHECK(MessageLoop::current() == ui_loop_); | 450 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
459 DownloadManagerMap::iterator it = managers_.find(download_id); | 451 DownloadManagerMap::iterator it = managers_.find(download_id); |
460 if (it != managers_.end()) | 452 if (it != managers_.end()) |
461 return it->second; | 453 return it->second; |
462 return NULL; | 454 return NULL; |
463 } | 455 } |
464 | 456 |
465 // Utility function for look up table maintenance, called on the UI thread. | 457 // Utility function for look up table maintenance, called on the UI thread. |
466 // A manager may have multiple downloads in progress, so we just look up the | 458 // A manager may have multiple downloads in progress, so we just look up the |
467 // one download (id) and remove it from the set, and remove the set if it | 459 // one download (id) and remove it from the set, and remove the set if it |
468 // becomes empty. | 460 // becomes empty. |
469 void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) { | 461 void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) { |
470 DCHECK(MessageLoop::current() == ui_loop_); | 462 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
471 if (manager) { | 463 if (manager) { |
472 RequestMap::iterator it = requests_.find(manager); | 464 RequestMap::iterator it = requests_.find(manager); |
473 if (it != requests_.end()) { | 465 if (it != requests_.end()) { |
474 DownloadRequests& downloads = it->second; | 466 DownloadRequests& downloads = it->second; |
475 DownloadRequests::iterator rit = downloads.find(id); | 467 DownloadRequests::iterator rit = downloads.find(id); |
476 if (rit != downloads.end()) | 468 if (rit != downloads.end()) |
477 downloads.erase(rit); | 469 downloads.erase(rit); |
478 if (downloads.empty()) | 470 if (downloads.empty()) |
479 requests_.erase(it); | 471 requests_.erase(it); |
480 } | 472 } |
(...skipping 17 matching lines...) Expand all Loading... |
498 Profile* profile = contents->profile(); | 490 Profile* profile = contents->profile(); |
499 if (profile) | 491 if (profile) |
500 return profile->GetDownloadManager(); | 492 return profile->GetDownloadManager(); |
501 } | 493 } |
502 | 494 |
503 return NULL; | 495 return NULL; |
504 } | 496 } |
505 | 497 |
506 // Called by DownloadManagers in their destructor, and only on the UI thread. | 498 // Called by DownloadManagers in their destructor, and only on the UI thread. |
507 void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) { | 499 void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) { |
508 DCHECK(MessageLoop::current() == ui_loop_); | 500 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
509 DCHECK(manager); | 501 DCHECK(manager); |
510 RequestMap::iterator it = requests_.find(manager); | 502 RequestMap::iterator it = requests_.find(manager); |
511 if (it == requests_.end()) | 503 if (it == requests_.end()) |
512 return; | 504 return; |
513 | 505 |
514 const DownloadRequests& requests = it->second; | 506 const DownloadRequests& requests = it->second; |
515 DownloadRequests::const_iterator i = requests.begin(); | 507 DownloadRequests::const_iterator i = requests.begin(); |
516 for (; i != requests.end(); ++i) { | 508 for (; i != requests.end(); ++i) { |
517 DownloadManagerMap::iterator dit = managers_.find(*i); | 509 DownloadManagerMap::iterator dit = managers_.find(*i); |
518 if (dit != managers_.end()) { | 510 if (dit != managers_.end()) { |
519 DCHECK(dit->second == manager); | 511 DCHECK(dit->second == manager); |
520 managers_.erase(dit); | 512 managers_.erase(dit); |
521 } | 513 } |
522 } | 514 } |
523 | 515 |
524 requests_.erase(it); | 516 requests_.erase(it); |
525 } | 517 } |
526 | 518 |
527 | 519 |
528 // Notifications from the UI thread and run on the IO thread | 520 // Notifications from the UI thread and run on the IO thread |
529 | 521 |
530 // Initiate a request for URL to be downloaded. | 522 // Initiate a request for URL to be downloaded. |
531 void DownloadFileManager::OnDownloadUrl( | 523 void DownloadFileManager::OnDownloadUrl( |
532 const GURL& url, | 524 const GURL& url, |
533 const GURL& referrer, | 525 const GURL& referrer, |
534 const std::string& referrer_charset, | 526 const std::string& referrer_charset, |
535 int render_process_host_id, | 527 int render_process_host_id, |
536 int render_view_id, | 528 int render_view_id, |
537 URLRequestContextGetter* request_context_getter) { | 529 URLRequestContextGetter* request_context_getter) { |
538 DCHECK(MessageLoop::current() == io_loop_); | 530 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
539 | 531 |
540 URLRequestContext* context = request_context_getter->GetURLRequestContext(); | 532 URLRequestContext* context = request_context_getter->GetURLRequestContext(); |
541 context->set_referrer_charset(referrer_charset); | 533 context->set_referrer_charset(referrer_charset); |
542 | 534 |
543 resource_dispatcher_host_->BeginDownload(url, | 535 resource_dispatcher_host_->BeginDownload(url, |
544 referrer, | 536 referrer, |
545 render_process_host_id, | 537 render_process_host_id, |
546 render_view_id, | 538 render_view_id, |
547 context); | 539 context); |
548 } | 540 } |
549 | 541 |
550 // Actions from the UI thread and run on the download thread | 542 // Actions from the UI thread and run on the download thread |
551 | 543 |
552 // Open a download, or show it in a file explorer window. We run on this | 544 // Open a download, or show it in a file explorer window. We run on this |
553 // thread to avoid blocking the UI with (potentially) slow Shell operations. | 545 // thread to avoid blocking the UI with (potentially) slow Shell operations. |
554 // TODO(paulg): File 'stat' operations. | 546 // TODO(paulg): File 'stat' operations. |
555 #if !defined(OS_MACOSX) | 547 #if !defined(OS_MACOSX) |
556 void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) { | 548 void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) { |
557 DCHECK(MessageLoop::current() == file_loop_); | 549 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
558 platform_util::ShowItemInFolder(full_path); | 550 platform_util::ShowItemInFolder(full_path); |
559 } | 551 } |
560 #endif | 552 #endif |
561 | 553 |
562 // Launches the selected download using ShellExecute 'open' verb. For windows, | 554 // Launches the selected download using ShellExecute 'open' verb. For windows, |
563 // if there is a valid parent window, the 'safer' version will be used which can | 555 // if there is a valid parent window, the 'safer' version will be used which can |
564 // display a modal dialog asking for user consent on dangerous files. | 556 // display a modal dialog asking for user consent on dangerous files. |
565 #if !defined(OS_MACOSX) | 557 #if !defined(OS_MACOSX) |
566 void DownloadFileManager::OnOpenDownloadInShell(const FilePath& full_path, | 558 void DownloadFileManager::OnOpenDownloadInShell(const FilePath& full_path, |
567 const GURL& url, | 559 const GURL& url, |
568 gfx::NativeView parent_window) { | 560 gfx::NativeView parent_window) { |
569 DCHECK(MessageLoop::current() == file_loop_); | 561 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
570 #if defined(OS_WIN) | 562 #if defined(OS_WIN) |
571 if (NULL != parent_window) { | 563 if (NULL != parent_window) { |
572 win_util::SaferOpenItemViaShell(parent_window, L"", full_path, | 564 win_util::SaferOpenItemViaShell(parent_window, L"", full_path, |
573 UTF8ToWide(url.spec())); | 565 UTF8ToWide(url.spec())); |
574 return; | 566 return; |
575 } | 567 } |
576 #endif | 568 #endif |
577 platform_util::OpenItem(full_path); | 569 platform_util::OpenItem(full_path); |
578 } | 570 } |
579 #endif // OS_MACOSX | 571 #endif // OS_MACOSX |
580 | 572 |
581 // The DownloadManager in the UI thread has provided a final name for the | 573 // The DownloadManager in the UI thread has provided a final name for the |
582 // download specified by 'id'. Rename the in progress download, and remove it | 574 // download specified by 'id'. Rename the in progress download, and remove it |
583 // from our table if it has been completed or cancelled already. | 575 // from our table if it has been completed or cancelled already. |
584 void DownloadFileManager::OnFinalDownloadName(int id, | 576 void DownloadFileManager::OnFinalDownloadName(int id, |
585 const FilePath& full_path, | 577 const FilePath& full_path, |
586 DownloadManager* manager) { | 578 DownloadManager* manager) { |
587 DCHECK(MessageLoop::current() == file_loop_); | 579 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
588 DownloadFileMap::iterator it = downloads_.find(id); | 580 DownloadFileMap::iterator it = downloads_.find(id); |
589 if (it == downloads_.end()) | 581 if (it == downloads_.end()) |
590 return; | 582 return; |
591 | 583 |
592 file_util::CreateDirectory(full_path.DirName()); | 584 file_util::CreateDirectory(full_path.DirName()); |
593 | 585 |
594 DownloadFile* download = it->second; | 586 DownloadFile* download = it->second; |
595 if (download->Rename(full_path)) { | 587 if (download->Rename(full_path)) { |
596 #if defined(OS_MACOSX) | 588 #if defined(OS_MACOSX) |
597 // Done here because we only want to do this once; see | 589 // Done here because we only want to do this once; see |
598 // http://crbug.com/13120 for details. | 590 // http://crbug.com/13120 for details. |
599 download->AnnotateWithSourceInformation(); | 591 download->AnnotateWithSourceInformation(); |
600 #endif | 592 #endif |
601 ui_loop_->PostTask(FROM_HERE, | 593 ChromeThread::PostTask( |
602 NewRunnableMethod(manager, | 594 ChromeThread::UI, FROM_HERE, |
603 &DownloadManager::DownloadRenamedToFinalName, | 595 NewRunnableMethod( |
604 id, | 596 manager, &DownloadManager::DownloadRenamedToFinalName, id, |
605 full_path)); | 597 full_path)); |
606 } else { | 598 } else { |
607 // Error. Between the time the UI thread generated 'full_path' to the time | 599 // Error. Between the time the UI thread generated 'full_path' to the time |
608 // this code runs, something happened that prevents us from renaming. | 600 // this code runs, something happened that prevents us from renaming. |
609 DownloadManagerMap::iterator dmit = managers_.find(download->id()); | 601 DownloadManagerMap::iterator dmit = managers_.find(download->id()); |
610 if (dmit != managers_.end()) { | 602 if (dmit != managers_.end()) { |
611 DownloadManager* dlm = dmit->second; | 603 DownloadManager* dlm = dmit->second; |
612 ui_loop_->PostTask(FROM_HERE, | 604 ChromeThread::PostTask( |
613 NewRunnableMethod(dlm, | 605 ChromeThread::UI, FROM_HERE, |
614 &DownloadManager::DownloadCancelled, | 606 NewRunnableMethod(dlm, &DownloadManager::DownloadCancelled, id)); |
615 id)); | |
616 } else { | 607 } else { |
617 ChromeThread::PostTask( | 608 ChromeThread::PostTask( |
618 ChromeThread::IO, FROM_HERE, | 609 ChromeThread::IO, FROM_HERE, |
619 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, | 610 NewRunnableFunction(&DownloadManager::OnCancelDownloadRequest, |
620 resource_dispatcher_host_, | 611 resource_dispatcher_host_, |
621 download->child_id(), | 612 download->child_id(), |
622 download->request_id())); | 613 download->request_id())); |
623 } | 614 } |
624 } | 615 } |
625 | 616 |
626 // If the download has completed before we got this final name, we remove it | 617 // If the download has completed before we got this final name, we remove it |
627 // from our in progress map. | 618 // from our in progress map. |
628 if (!download->in_progress()) { | 619 if (!download->in_progress()) { |
629 downloads_.erase(it); | 620 downloads_.erase(it); |
630 delete download; | 621 delete download; |
631 } | 622 } |
632 | 623 |
633 if (downloads_.empty()) | 624 if (downloads_.empty()) { |
634 ui_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 625 ChromeThread::PostTask( |
635 this, &DownloadFileManager::StopUpdateTimer)); | 626 ChromeThread::UI, FROM_HERE, |
| 627 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); |
| 628 } |
636 } | 629 } |
637 | 630 |
638 // static | 631 // static |
639 void DownloadFileManager::DeleteFile(const FilePath& path) { | 632 void DownloadFileManager::DeleteFile(const FilePath& path) { |
640 // Make sure we only delete files. | 633 // Make sure we only delete files. |
641 if (!file_util::DirectoryExists(path)) | 634 if (!file_util::DirectoryExists(path)) |
642 file_util::Delete(path, false); | 635 file_util::Delete(path, false); |
643 } | 636 } |
OLD | NEW |