Index: chrome/browser/extensions/extension_downloads.cc |
diff --git a/chrome/browser/extensions/extension_downloads.cc b/chrome/browser/extensions/extension_downloads.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..17730a737b67a42ee8060c6a7b27b00b750229f6 |
--- /dev/null |
+++ b/chrome/browser/extensions/extension_downloads.cc |
@@ -0,0 +1,415 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/extensions/extension_downloads.h" |
+ |
+#include <algorithm> |
+ |
+#include "base/bind.h" |
+#include "base/logging.h" |
+#include "base/stl_util-inl.h" |
+#include "base/values.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/download/download_create_info.h" |
+#include "chrome/browser/extensions/extension_event_router.h" |
+#include "chrome/browser/download/download_file_manager.h" |
+#include "chrome/browser/download/download_item.h" |
+#include "chrome/browser/download/download_manager.h" |
+#include "chrome/browser/download/download_query.h" |
+#include "chrome/browser/download/download_util.h" |
+#include "chrome/browser/icon_loader.h" |
+#include "chrome/browser/icon_manager.h" |
+#include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
+#include "chrome/browser/ui/browser_list.h" |
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
+#include "content/browser/renderer_host/render_view_host.h" |
+#include "content/browser/renderer_host/resource_dispatcher_host.h" |
+ |
+bool DownloadsDownloadFunction::RunImpl() { |
+ EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_)); |
+ EXTENSION_FUNCTION_VALIDATE(options_->GetString("url", &url_)); |
+ if (url_.empty()) { |
+ error_ = "'url' cannot be empty."; |
+ return false; |
+ } |
+ rdh_ = g_browser_process->resource_dispatcher_host(); |
+ if (rdh_ == NULL) { |
+ error_ = "I'm afraid I can't do that."; |
+ return false; |
+ } |
+ VLOG(1) << __FUNCTION__ << " " << url_; |
+ products_ = new DictionaryValue(); |
+ result_.reset(products_); |
+ options_->GetString("filename", &filename_); |
+ options_->GetBoolean("save_as", &save_as_); |
+ options_->GetString("method", &method_); |
+ options_->GetDictionary("headers", &extra_headers_); |
+ options_->GetString("body", &post_body_); |
+ // TODO sanity check method_, extra_headers_, filename_ |
+ dl_man_ = profile()->GetDownloadManager(); |
+ tab_contents_ = BrowserList::GetLastActive()->GetSelectedTabContentsWrapper() |
+ ->tab_contents(); |
+ resource_context_ = &profile()->GetResourceContext(); |
+ render_process_host_id_ = tab_contents_->GetRenderProcessHost()->id(); |
+ render_view_host_routing_id_ = tab_contents_->render_view_host() |
+ ->routing_id(); |
+ VLOG(1) << __FUNCTION__ << " " << url_; |
+ if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, NewRunnableMethod( |
+ this, &DownloadsDownloadFunction::BeginDownloadOnIOThread))) { |
+ error_ = "I'm afraid I can't do that."; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+void DownloadsDownloadFunction::BeginDownloadOnIOThread() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ DVLOG(1) << __FUNCTION__ << " " << url_; |
+ DownloadSaveInfo save_info; |
+ save_info.file_path = FilePath(filename_); |
+ net::URLRequest* request = new net::URLRequest(GURL(url_), rdh_); |
+ if (method_.empty()) { |
+ method_ = "GET"; |
+ } |
+ request->set_method(method_); |
+ if (extra_headers_ != NULL) { |
+ DictionaryValue::key_iterator headers_end = extra_headers_->end_keys(); |
+ for (DictionaryValue::key_iterator headers_iter = |
+ extra_headers_->begin_keys(); |
+ headers_iter != headers_end; ++headers_iter) { |
+ std::string value; |
+ if (extra_headers_->GetStringWithoutPathExpansion( |
+ *headers_iter, &value)) { |
+ request->SetExtraRequestHeaderByName( |
+ *headers_iter, value, false/*overwrite*/); |
+ } |
+ } |
+ } |
+ if (!post_body_.empty()) { |
+ request->AppendBytesToUpload(post_body_.data(), post_body_.size()); |
+ } |
+ rdh_->BeginDownload( |
+ request, |
+ save_info, |
+ save_as_, |
+ base::Bind(&DownloadsDownloadFunction::OnStarted, this), |
+ render_process_host_id_, |
+ render_view_host_routing_id_, |
+ *resource_context_); |
+} |
+ |
+void DownloadsDownloadFunction::OnStarted(int dl_id, int error) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ VLOG(1) << __FUNCTION__ << " " << url_ << " " << dl_id << " " << error; |
+ dl_id_ = dl_id; |
+ dl_error_ = error; |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod( |
+ this, &DownloadsDownloadFunction::RespondOnUIThread)); |
+} |
+ |
+void DownloadsDownloadFunction::RespondOnUIThread() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ VLOG(1) << __FUNCTION__ << " " << url_ << " " << dl_man_ << " " << filename_ |
+ << " " << dl_id_ << " " << dl_error_ << " " << method_; |
+ if (dl_id_ >= 0) { |
+ products_->Set("id", Value::CreateIntegerValue(dl_id_)); |
+ } else { |
+ products_->Set("error", Value::CreateIntegerValue(dl_error_)); |
+ } |
+ SendResponse(true); |
+} |
+ |
+bool DownloadsSearchFunction::RunImpl() { |
+ DictionaryValue* query_json = NULL; |
+ EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json)); |
+ CHECK(query_json); |
+ download_util::DownloadQuery query(*query_json); |
+ DownloadManager* dlman = profile()->GetDownloadManager(); |
+ if (dlman == NULL) { |
+ error_ = "I'm afraid I can't do that."; |
+ return false; |
+ } |
+ ListValue* results = new ListValue(); |
+ if (!dlman->Search( |
+ download_util::DownloadQuery(*query_json), |
+ NULL/*DownloadItem results*/, |
+ true/*merge_parent_manager*/, |
+ &error_, |
+ results)) { |
+ VLOG(1) << __PRETTY_FUNCTION__ << " " << error_; |
+ return false; |
+ } |
+ result_.reset(results); |
+ return true; |
+} |
+ |
+bool DownloadsPauseFunction::RunImpl() { |
+ int dl_id = 0; |
+ EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
+ DownloadManager* dlman = profile()->GetDownloadManager(); |
+ if (dlman == NULL) { |
+ error_ = "I'm afraid I can't do that."; |
+ return false; |
+ } |
+ DownloadItem* item = dlman->GetDownloadItem(dl_id); |
+ if (item == NULL) { |
+ error_ = "Non-existent download"; |
+ return false; |
+ } |
+ VLOG(1) << __FUNCTION__ << " " << item; |
+ if (!item->is_paused()) { |
+ item->TogglePause(); |
+ } |
+ return true; |
+} |
+ |
+bool DownloadsResumeFunction::RunImpl() { |
+ int dl_id = 0; |
+ EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
+ DownloadManager* dlman = profile()->GetDownloadManager(); |
+ if (dlman == NULL) { |
+ error_ = "I'm afraid I can't do that."; |
+ return false; |
+ } |
+ DownloadItem* item = dlman->GetDownloadItem(dl_id); |
+ if (item == NULL) { |
+ error_ = "Non-existent download"; |
+ return false; |
+ } |
+ VLOG(1) << __FUNCTION__ << " " << item; |
+ if (item->is_paused()) { |
+ item->TogglePause(); |
+ } |
+ return true; |
+} |
+ |
+bool DownloadsCancelFunction::RunImpl() { |
+ int dl_id = 0; |
+ EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
+ DownloadManager* dlman = profile()->GetDownloadManager(); |
+ if (dlman == NULL) { |
+ error_ = "I'm afraid I can't do that."; |
+ return false; |
+ } |
+ DownloadItem* item = dlman->GetDownloadItem(dl_id); |
+ if (item == NULL) { |
+ error_ = "Non-existent download"; |
+ return false; |
+ } |
+ VLOG(1) << __FUNCTION__ << " " << item; |
+ item->Cancel(true); |
+ return true; |
+} |
+ |
+bool DownloadsEraseFunction::RunImpl() { |
+ return true; |
+} |
+ |
+bool DownloadsSetDestinationFunction::RunImpl() { |
+ int dl_id = 0; |
+ std::string rel_dest_path; |
+ if ((args_.get() == NULL) || |
+ (args_->GetSize() < 2) || |
+ !args_->GetInteger(0, &dl_id) || |
+ (dl_id == 0) || |
+ !args_->GetString(1, &rel_dest_path) || |
+ rel_dest_path.empty()) return false; |
+ DownloadManager* dlman = profile()->GetDownloadManager(); |
+ DownloadItem* item = dlman->GetDownloadItem(dl_id); |
+ if (item == NULL) return false; |
+ VLOG(1) << __FUNCTION__ << " " << dl_id << " " << item << " " |
+ << rel_dest_path; |
+ return true; |
+} |
+ |
+bool DownloadsAcceptDangerFunction::RunImpl() { |
+ int dl_id = 0; |
+ EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
+ DownloadManager* dlman = profile()->GetDownloadManager(); |
+ if (dlman == NULL) { |
+ error_ = "I'm afraid I can't do that."; |
+ return false; |
+ } |
+ DownloadItem* item = dlman->GetDownloadItem(dl_id); |
+ if (item == NULL) { |
+ error_ = "Non-existent download"; |
+ return false; |
+ } |
+ VLOG(1) << __FUNCTION__ << " " << item; |
+ item->Cancel(true); |
+ return true; |
+} |
+ |
+bool DownloadsShowFunction::RunImpl() { |
+ int dl_id = 0; |
+ if ((args_.get() == NULL) || |
+ (args_->GetSize() < 1) || |
+ !args_->GetInteger(0, &dl_id) || |
+ (dl_id == 0)) return false; |
+ DownloadManager* dlman = profile()->GetDownloadManager(); |
+ DownloadItem* item = dlman->GetDownloadItem(dl_id); |
+ if (item == NULL) return false; |
+ VLOG(1) << __FUNCTION__ << " " << item; |
+ return true; |
+} |
+ |
+bool DownloadsDragFunction::RunImpl() { |
+ int dl_id = 0; |
+ if ((args_.get() == NULL) || |
+ (args_->GetSize() < 1) || |
+ !args_->GetInteger(0, &dl_id) || |
+ (dl_id == 0)) return false; |
+ DownloadManager* dlman = profile()->GetDownloadManager(); |
+ DownloadItem* item = dlman->GetDownloadItem(dl_id); |
+ if (item == NULL) return false; |
+ IconManager* im = g_browser_process->icon_manager(); |
+ gfx::Image* icon = im->LookupIcon(item->GetUserVerifiedFilePath(), |
+ IconLoader::NORMAL); |
+ gfx::NativeView view = BrowserList::GetLastActive() |
+ ->GetSelectedTabContentsWrapper()->tab_contents()->GetNativeView(); |
+ download_util::DragDownload(item, icon, view); |
+ VLOG(1) << __FUNCTION__ << " " << dl_id; |
+ return true; |
+} |
+ |
+struct DownloadsEventRouter::EventListener { |
+ std::string ext_id; |
+ base::WeakPtr<IPC::Message::Sender> ipc_sender; |
+ |
+ EventListener(std::string eid, base::WeakPtr<IPC::Message::Sender> ipcs) |
+ : ext_id(eid), |
+ ipc_sender(ipcs) { |
+ } |
+ ~EventListener() {} |
+ |
+ void SendEvent() { |
+ } |
+ |
+ // Comparator to work with std::set. |
+ bool operator<(const EventListener& that) const { |
+ return ext_id < that.ext_id; |
+ } |
+ |
+ // Allow copy and assign. |
+}; |
+ |
+class DownloadsEventRouter::ManagerObserver |
+ : public DownloadManager::Observer { |
+ public: |
+ ManagerObserver(DownloadsEventRouter* router, |
+ ProfileId profile_id, |
+ DownloadManager* manager) |
+ : router_(router), |
+ profile_id_(profile_id), |
+ manager_(manager) { |
+ DCHECK(router); |
+ DCHECK(manager_); |
+ manager_->AddObserver(this); |
+ } |
+ ~ManagerObserver() { |
+ if (manager_) manager_->RemoveObserver(this); |
+ } |
+ |
+ virtual void ModelChanged() { |
+ DCHECK(manager_); |
+ DVLOG(1) << __FUNCTION__ << " " << manager_ << " " << profile_id_ << " " << router_; |
+ router_->DispatchEvent(DownloadsEventRouter::CHANGED, profile_id_, 0); |
+ } |
+ |
+ virtual void ManagerGoingDown() { |
+ manager_ = NULL; |
+ } |
+ |
+ private: |
+ DownloadsEventRouter* router_; |
+ ProfileId profile_id_; |
+ DownloadManager* manager_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ManagerObserver); |
+}; |
+ |
+class DownloadsEventRouter::ItemObserver : public DownloadItem::Observer { |
+ public: |
+ ItemObserver() {} |
+ ~ItemObserver() {} |
+ |
+ virtual void OnDownloadUpdated(DownloadItem* download) { |
+ DVLOG(1) << __FUNCTION__ << " " << download->id(); |
+ } |
+ |
+ virtual void OnDownloadOpened(DownloadItem* download) { |
+ DVLOG(1) << __FUNCTION__ << " " << download->id(); |
+ } |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(ItemObserver); |
+}; |
+ |
+DownloadsEventRouter::DownloadsEventRouter() { |
+} |
+ |
+DownloadsEventRouter::~DownloadsEventRouter() { |
+} |
+ |
+DownloadsEventRouter* DownloadsEventRouter::GetInstance() { |
+ return Singleton<DownloadsEventRouter>::get(); |
+} |
+ |
+void DownloadsEventRouter::AddEventListener( |
+ EventType event_type, |
+ ProfileId profile_id, |
+ const std::string& extension_id, |
+ base::WeakPtr<IPC::Message::Sender> ipc_sender) { |
+ DVLOG(1) << __FUNCTION__ |
+ << " " << event_type |
+ << " " << profile_id |
+ << " " << extension_id |
+ << " " << BrowserThread::CurrentlyOn(BrowserThread::UI); |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
+ DCHECK(BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &DownloadsEventRouter::AddEventListener, |
+ event_type, profile_id, extension_id, ipc_sender))); |
+ return; |
+ } |
+ Profile* profile = reinterpret_cast<Profile*>(profile_id); // XXX |
+ DownloadManager* dlman = profile->GetDownloadManager(); |
+ DCHECK(dlman); |
+ listeners_[profile_id][event_type].insert(EventListener( |
+ extension_id, ipc_sender)); |
+ if (manager_observers_.find(profile_id) == manager_observers_.end()) { |
+ manager_observers_[profile_id] = new ManagerObserver(this, profile_id, dlman); |
+ } |
+} |
+ |
+void DownloadsEventRouter::DispatchEvent( |
+ EventType event_type, |
+ ProfileId profile_id, |
+ int download_id) { |
+ DVLOG(1) << __FUNCTION__ |
+ << " " << event_type |
+ << " " << profile_id |
+ << " " << download_id |
+ << " " << BrowserThread::CurrentlyOn(BrowserThread::IO); |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
+ DCHECK(BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
+ NewRunnableMethod(this, &DownloadsEventRouter::DispatchEvent, |
+ event_type, profile_id, download_id))); |
+ return; |
+ } |
+ LOG(ERROR) << __FUNCTION__ << " " << event_type << " " << profile_id << " " << download_id; |
+ if (event_type == CREATED) { |
+ //item_observers_[profile_id].insert(ItemObserver(this, profile_id)); |
+ } else if (event_type == ERASED) { |
+ //item_observers_[profile_id]; |
+ } |
+ const ListenerSet& listeners = listeners_[profile_id][event_type]; |
+ for (ListenerSet::iterator listener = listeners.begin(); |
+ listener != listeners.end(); ++listener) { |
+ //(*listener)->ipc_sender->Send(new ExtensionMsg_MessageInvoke( |
+ //MSG_ROUTING_CONTROL, (*listener)->ext_id, kDispatchEvent, args, event_url)); |
+ //ExtensionEventRouter::DispatchEvent( |
+ // (*listener)->ipc_sender.get(), (*listener)->ext_id, (*it)->sub_event_name, |
+ // json_args, GURL()); |
+ } |
+} |