Revert 99759 - Add two new valgrind suppressions.
[chromium-blink-merge.git] / content / browser / download / drag_download_file.cc
blob69ce7a19ef82e2440b8597be7deddb8a17620d96
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/download/drag_download_file.h"
7 #include "base/file_util.h"
8 #include "base/message_loop.h"
9 #include "content/browser/browser_context.h"
10 #include "content/browser/browser_thread.h"
11 #include "content/browser/download/download_item.h"
12 #include "content/browser/download/download_stats.h"
13 #include "content/browser/tab_contents/tab_contents.h"
14 #include "net/base/file_stream.h"
16 DragDownloadFile::DragDownloadFile(
17 const FilePath& file_name_or_path,
18 linked_ptr<net::FileStream> file_stream,
19 const GURL& url,
20 const GURL& referrer,
21 const std::string& referrer_encoding,
22 TabContents* tab_contents)
23 : file_stream_(file_stream),
24 url_(url),
25 referrer_(referrer),
26 referrer_encoding_(referrer_encoding),
27 tab_contents_(tab_contents),
28 drag_message_loop_(MessageLoop::current()),
29 is_started_(false),
30 is_successful_(false),
31 download_manager_(NULL),
32 download_manager_observer_added_(false),
33 download_item_(NULL) {
34 #if defined(OS_WIN)
35 DCHECK(!file_name_or_path.empty() && !file_stream.get());
36 file_name_ = file_name_or_path;
37 #elif defined(OS_POSIX)
38 DCHECK(!file_name_or_path.empty() && file_stream.get());
39 file_path_ = file_name_or_path;
40 #endif
43 DragDownloadFile::~DragDownloadFile() {
44 AssertCurrentlyOnDragThread();
46 // Since the target application can still hold and use the dragged file,
47 // we do not know the time that it can be safely deleted. To solve this
48 // problem, we schedule it to be removed after the system is restarted.
49 #if defined(OS_WIN)
50 if (!temp_dir_path_.empty()) {
51 if (!file_path_.empty())
52 file_util::DeleteAfterReboot(file_path_);
53 file_util::DeleteAfterReboot(temp_dir_path_);
55 #endif
57 RemoveObservers();
60 void DragDownloadFile::RemoveObservers() {
61 if (download_item_) {
62 download_item_->RemoveObserver(this);
63 download_item_ = NULL;
66 if (download_manager_observer_added_) {
67 download_manager_observer_added_ = false;
68 download_manager_->RemoveObserver(this);
72 bool DragDownloadFile::Start(ui::DownloadFileObserver* observer) {
73 AssertCurrentlyOnDragThread();
75 if (is_started_)
76 return true;
77 is_started_ = true;
79 DCHECK(!observer_.get());
80 observer_ = observer;
82 if (!file_stream_.get()) {
83 // Create a temporary directory to save the temporary download file. We do
84 // not want to use the default download directory since we do not want the
85 // twisted file name shown in the download shelf if the file with the same
86 // name already exists.
87 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome"),
88 &temp_dir_path_))
89 return false;
91 file_path_ = temp_dir_path_.Append(file_name_);
94 InitiateDownload();
96 // On Windows, we need to wait till the download file is completed.
97 #if defined(OS_WIN)
98 StartNestedMessageLoop();
99 #endif
101 return is_successful_;
104 void DragDownloadFile::Stop() {
107 void DragDownloadFile::InitiateDownload() {
108 #if defined(OS_WIN)
109 // DownloadManager could only be invoked from the UI thread.
110 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
111 BrowserThread::PostTask(
112 BrowserThread::UI, FROM_HERE,
113 NewRunnableMethod(this,
114 &DragDownloadFile::InitiateDownload));
115 return;
117 #endif
119 download_manager_ = tab_contents_->browser_context()->GetDownloadManager();
120 download_manager_observer_added_ = true;
121 download_manager_->AddObserver(this);
123 DownloadSaveInfo save_info;
124 save_info.file_path = file_path_;
125 save_info.file_stream = file_stream_;
126 download_manager_->DownloadUrlToFile(url_,
127 referrer_,
128 referrer_encoding_,
129 save_info,
130 tab_contents_);
131 download_stats::RecordDownloadCount(
132 download_stats::INITIATED_BY_DRAG_N_DROP_COUNT);
135 void DragDownloadFile::DownloadCompleted(bool is_successful) {
136 #if defined(OS_WIN)
137 // If not in drag-and-drop thread, defer the running to it.
138 if (drag_message_loop_ != MessageLoop::current()) {
139 drag_message_loop_->PostTask(
140 FROM_HERE,
141 NewRunnableMethod(this,
142 &DragDownloadFile::DownloadCompleted,
143 is_successful));
144 return;
146 #endif
148 is_successful_ = is_successful;
150 // Call the observer.
151 DCHECK(observer_);
152 if (is_successful)
153 observer_->OnDownloadCompleted(file_path_);
154 else
155 observer_->OnDownloadAborted();
157 // Release the observer since we do not need it any more.
158 observer_ = NULL;
160 // On Windows, we need to stop the waiting.
161 #if defined(OS_WIN)
162 QuitNestedMessageLoop();
163 #endif
166 void DragDownloadFile::ModelChanged() {
167 AssertCurrentlyOnUIThread();
169 if (download_item_)
170 return;
172 std::vector<DownloadItem*> downloads;
173 download_manager_->GetTemporaryDownloads(file_path_.DirName(), &downloads);
174 for (std::vector<DownloadItem*>::const_iterator i = downloads.begin();
175 i != downloads.end(); ++i) {
176 if ((*i)->original_url() == url_) {
177 download_item_ = *i;
178 download_item_->AddObserver(this);
179 break;
184 void DragDownloadFile::OnDownloadUpdated(DownloadItem* download) {
185 AssertCurrentlyOnUIThread();
186 if (download->IsCancelled() || download->state() == DownloadItem::REMOVING) {
187 RemoveObservers();
188 DownloadCompleted(false);
189 } else if (download->IsComplete()) {
190 RemoveObservers();
191 DownloadCompleted(true);
193 // Ignore other states.
196 void DragDownloadFile::AssertCurrentlyOnDragThread() {
197 // Only do the check on Windows where two threads are involved.
198 #if defined(OS_WIN)
199 DCHECK(drag_message_loop_ == MessageLoop::current());
200 #endif
203 void DragDownloadFile::AssertCurrentlyOnUIThread() {
204 // Only do the check on Windows where two threads are involved.
205 #if defined(OS_WIN)
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
207 #endif
210 #if defined(OS_WIN)
211 void DragDownloadFile::StartNestedMessageLoop() {
212 AssertCurrentlyOnDragThread();
214 bool old_state = MessageLoop::current()->NestableTasksAllowed();
215 MessageLoop::current()->SetNestableTasksAllowed(true);
216 is_running_nested_message_loop_ = true;
217 MessageLoop::current()->Run();
218 MessageLoop::current()->SetNestableTasksAllowed(old_state);
221 void DragDownloadFile::QuitNestedMessageLoop() {
222 AssertCurrentlyOnDragThread();
224 if (is_running_nested_message_loop_) {
225 is_running_nested_message_loop_ = false;
226 MessageLoop::current()->Quit();
229 #endif