| 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()); | 
| +  } | 
| +} | 
|  |