Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / browser / download / drag_download_file.cc
blobd81b04ccf6b8c7d41a1d763d794467b723b468fc
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
3 // found in the LICENSE file.
5 #include "content/browser/download/drag_download_file.h"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/browser/download/download_stats.h"
10 #include "content/browser/web_contents/web_contents_impl.h"
11 #include "content/public/browser/browser_context.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/download_item.h"
14 #include "content/public/browser/download_save_info.h"
15 #include "content/public/browser/download_url_parameters.h"
16 #include "net/base/file_stream.h"
18 namespace content {
20 namespace {
22 typedef base::Callback<void(bool)> OnCompleted;
24 } // namespace
26 // On windows, DragDownloadFile runs on a thread other than the UI thread.
27 // DownloadItem and DownloadManager may not be accessed on any thread other than
28 // the UI thread. DragDownloadFile may run on either the "drag" thread or the UI
29 // thread depending on the platform, but DragDownloadFileUI strictly always runs
30 // on the UI thread. On platforms where DragDownloadFile runs on the UI thread,
31 // none of the PostTasks are necessary, but it simplifies the code to do them
32 // anyway.
33 class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
34 public:
35 DragDownloadFileUI(const GURL& url,
36 const Referrer& referrer,
37 const std::string& referrer_encoding,
38 WebContents* web_contents,
39 base::MessageLoop* on_completed_loop,
40 const OnCompleted& on_completed)
41 : on_completed_loop_(on_completed_loop),
42 on_completed_(on_completed),
43 url_(url),
44 referrer_(referrer),
45 referrer_encoding_(referrer_encoding),
46 web_contents_(web_contents),
47 download_item_(NULL),
48 weak_ptr_factory_(this) {
49 DCHECK(on_completed_loop_);
50 DCHECK(!on_completed_.is_null());
51 DCHECK(web_contents_);
52 // May be called on any thread.
53 // Do not call weak_ptr_factory_.GetWeakPtr() outside the UI thread.
56 void InitiateDownload(scoped_ptr<net::FileStream> file_stream,
57 const base::FilePath& file_path) {
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59 DownloadManager* download_manager =
60 BrowserContext::GetDownloadManager(web_contents_->GetBrowserContext());
62 RecordDownloadSource(INITIATED_BY_DRAG_N_DROP);
63 scoped_ptr<content::DownloadUrlParameters> params(
64 DownloadUrlParameters::FromWebContents(web_contents_, url_));
65 params->set_referrer(referrer_);
66 params->set_referrer_encoding(referrer_encoding_);
67 params->set_callback(base::Bind(&DragDownloadFileUI::OnDownloadStarted,
68 weak_ptr_factory_.GetWeakPtr()));
69 params->set_file_path(file_path);
70 params->set_file_stream(file_stream.Pass()); // Nulls file_stream.
71 download_manager->DownloadUrl(params.Pass());
74 void Cancel() {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
76 if (download_item_)
77 download_item_->Cancel(true);
80 void Delete() {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
82 delete this;
85 private:
86 virtual ~DragDownloadFileUI() {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
88 if (download_item_)
89 download_item_->RemoveObserver(this);
92 void OnDownloadStarted(DownloadItem* item, net::Error error) {
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
94 if (!item) {
95 DCHECK_NE(net::OK, error);
96 on_completed_loop_->PostTask(FROM_HERE, base::Bind(on_completed_, false));
97 return;
99 DCHECK_EQ(net::OK, error);
100 download_item_ = item;
101 download_item_->AddObserver(this);
104 // DownloadItem::Observer:
105 virtual void OnDownloadUpdated(DownloadItem* item) OVERRIDE {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
107 DCHECK_EQ(download_item_, item);
108 DownloadItem::DownloadState state = download_item_->GetState();
109 if (state == DownloadItem::COMPLETE ||
110 state == DownloadItem::CANCELLED ||
111 state == DownloadItem::INTERRUPTED) {
112 if (!on_completed_.is_null()) {
113 on_completed_loop_->PostTask(FROM_HERE, base::Bind(
114 on_completed_, state == DownloadItem::COMPLETE));
115 on_completed_.Reset();
117 download_item_->RemoveObserver(this);
118 download_item_ = NULL;
120 // Ignore other states.
123 virtual void OnDownloadDestroyed(DownloadItem* item) OVERRIDE {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
125 DCHECK_EQ(download_item_, item);
126 if (!on_completed_.is_null()) {
127 const bool is_complete =
128 download_item_->GetState() == DownloadItem::COMPLETE;
129 on_completed_loop_->PostTask(FROM_HERE, base::Bind(
130 on_completed_, is_complete));
131 on_completed_.Reset();
133 download_item_->RemoveObserver(this);
134 download_item_ = NULL;
137 base::MessageLoop* on_completed_loop_;
138 OnCompleted on_completed_;
139 GURL url_;
140 Referrer referrer_;
141 std::string referrer_encoding_;
142 WebContents* web_contents_;
143 DownloadItem* download_item_;
145 // Only used in the callback from DownloadManager::DownloadUrl().
146 base::WeakPtrFactory<DragDownloadFileUI> weak_ptr_factory_;
148 DISALLOW_COPY_AND_ASSIGN(DragDownloadFileUI);
151 DragDownloadFile::DragDownloadFile(const base::FilePath& file_path,
152 scoped_ptr<net::FileStream> file_stream,
153 const GURL& url,
154 const Referrer& referrer,
155 const std::string& referrer_encoding,
156 WebContents* web_contents)
157 : file_path_(file_path),
158 file_stream_(file_stream.Pass()),
159 drag_message_loop_(base::MessageLoop::current()),
160 state_(INITIALIZED),
161 drag_ui_(NULL),
162 weak_ptr_factory_(this) {
163 drag_ui_ = new DragDownloadFileUI(
164 url,
165 referrer,
166 referrer_encoding,
167 web_contents,
168 drag_message_loop_,
169 base::Bind(&DragDownloadFile::DownloadCompleted,
170 weak_ptr_factory_.GetWeakPtr()));
171 DCHECK(!file_path_.empty());
174 DragDownloadFile::~DragDownloadFile() {
175 CheckThread();
177 // This is the only place that drag_ui_ can be deleted from. Post a message to
178 // the UI thread so that it calls RemoveObserver on the right thread, and so
179 // that this task will run after the InitiateDownload task runs on the UI
180 // thread.
181 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
182 &DragDownloadFileUI::Delete, base::Unretained(drag_ui_)));
183 drag_ui_ = NULL;
186 void DragDownloadFile::Start(ui::DownloadFileObserver* observer) {
187 CheckThread();
189 if (state_ != INITIALIZED)
190 return;
191 state_ = STARTED;
193 DCHECK(!observer_.get());
194 observer_ = observer;
195 DCHECK(observer_.get());
197 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
198 &DragDownloadFileUI::InitiateDownload, base::Unretained(drag_ui_),
199 base::Passed(&file_stream_), file_path_));
202 bool DragDownloadFile::Wait() {
203 CheckThread();
204 if (state_ == STARTED)
205 nested_loop_.Run();
206 return state_ == SUCCESS;
209 void DragDownloadFile::Stop() {
210 CheckThread();
211 if (drag_ui_) {
212 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
213 &DragDownloadFileUI::Cancel, base::Unretained(drag_ui_)));
217 void DragDownloadFile::DownloadCompleted(bool is_successful) {
218 CheckThread();
220 state_ = is_successful ? SUCCESS : FAILURE;
222 if (is_successful)
223 observer_->OnDownloadCompleted(file_path_);
224 else
225 observer_->OnDownloadAborted();
227 // Release the observer since we do not need it any more.
228 observer_ = NULL;
230 if (nested_loop_.running())
231 nested_loop_.Quit();
234 void DragDownloadFile::CheckThread() {
235 #if defined(OS_WIN)
236 DCHECK(drag_message_loop_ == base::MessageLoop::current());
237 #else
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239 #endif
242 } // namespace content