Home | History | Annotate | Download | only in plugins
      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.
      4 
      5 #include "chrome/browser/plugins/plugin_installer.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/process/process.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "chrome/browser/download/download_service.h"
     12 #include "chrome/browser/download/download_service_factory.h"
     13 #include "chrome/browser/download/download_stats.h"
     14 #include "chrome/browser/platform_util.h"
     15 #include "chrome/browser/plugins/plugin_installer_observer.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "content/public/browser/browser_context.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "content/public/browser/download_item.h"
     20 #include "content/public/browser/download_save_info.h"
     21 #include "content/public/browser/render_process_host.h"
     22 #include "content/public/browser/render_view_host.h"
     23 #include "content/public/browser/resource_context.h"
     24 #include "content/public/browser/resource_dispatcher_host.h"
     25 #include "content/public/browser/web_contents.h"
     26 #include "content/public/common/referrer.h"
     27 #include "net/url_request/url_request.h"
     28 #include "net/url_request/url_request_context.h"
     29 
     30 using content::BrowserContext;
     31 using content::BrowserThread;
     32 using content::DownloadItem;
     33 using content::ResourceDispatcherHost;
     34 
     35 namespace {
     36 
     37 void BeginDownload(
     38     const GURL& url,
     39     content::ResourceContext* resource_context,
     40     int render_process_host_id,
     41     int render_view_host_routing_id,
     42     const ResourceDispatcherHost::DownloadStartedCallback& callback) {
     43   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     44 
     45   ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get();
     46   scoped_ptr<net::URLRequest> request(
     47       resource_context->GetRequestContext()->CreateRequest(url, NULL));
     48   net::Error error = rdh->BeginDownload(
     49       request.Pass(),
     50       content::Referrer(),
     51       false,  // is_content_initiated
     52       resource_context,
     53       render_process_host_id,
     54       render_view_host_routing_id,
     55       true,  // prefer_cache
     56       scoped_ptr<content::DownloadSaveInfo>(new content::DownloadSaveInfo()),
     57       content::DownloadItem::kInvalidId,
     58       callback);
     59 
     60   if (error != net::OK) {
     61     BrowserThread::PostTask(
     62         BrowserThread::UI, FROM_HERE,
     63         base::Bind(callback, static_cast<DownloadItem*>(NULL), error));
     64   }
     65 }
     66 
     67 }  // namespace
     68 
     69 PluginInstaller::PluginInstaller()
     70     : state_(INSTALLER_STATE_IDLE) {
     71 }
     72 
     73 PluginInstaller::~PluginInstaller() {
     74 }
     75 
     76 void PluginInstaller::OnDownloadUpdated(DownloadItem* download) {
     77   DownloadItem::DownloadState state = download->GetState();
     78   switch (state) {
     79     case DownloadItem::IN_PROGRESS:
     80       return;
     81     case DownloadItem::COMPLETE: {
     82       DCHECK_EQ(INSTALLER_STATE_DOWNLOADING, state_);
     83       state_ = INSTALLER_STATE_IDLE;
     84       FOR_EACH_OBSERVER(PluginInstallerObserver, observers_,
     85                         DownloadFinished());
     86       break;
     87     }
     88     case DownloadItem::CANCELLED: {
     89       DownloadCancelled();
     90       break;
     91     }
     92     case DownloadItem::INTERRUPTED: {
     93       content::DownloadInterruptReason reason = download->GetLastReason();
     94       DownloadError(content::InterruptReasonDebugString(reason));
     95       break;
     96     }
     97     case DownloadItem::MAX_DOWNLOAD_STATE: {
     98       NOTREACHED();
     99       return;
    100     }
    101   }
    102   download->RemoveObserver(this);
    103 }
    104 
    105 void PluginInstaller::OnDownloadDestroyed(DownloadItem* download) {
    106   DCHECK_EQ(INSTALLER_STATE_DOWNLOADING, state_);
    107   state_ = INSTALLER_STATE_IDLE;
    108   download->RemoveObserver(this);
    109 }
    110 
    111 void PluginInstaller::AddObserver(PluginInstallerObserver* observer) {
    112   observers_.AddObserver(observer);
    113 }
    114 
    115 void PluginInstaller::RemoveObserver(PluginInstallerObserver* observer) {
    116   observers_.RemoveObserver(observer);
    117   if (observers_.size() == weak_observers_.size()) {
    118     FOR_EACH_OBSERVER(WeakPluginInstallerObserver, weak_observers_,
    119                       OnlyWeakObserversLeft());
    120   }
    121 }
    122 
    123 void PluginInstaller::AddWeakObserver(WeakPluginInstallerObserver* observer) {
    124   weak_observers_.AddObserver(observer);
    125 }
    126 
    127 void PluginInstaller::RemoveWeakObserver(
    128     WeakPluginInstallerObserver* observer) {
    129   weak_observers_.RemoveObserver(observer);
    130 }
    131 
    132 void PluginInstaller::StartInstalling(const GURL& plugin_url,
    133                                       content::WebContents* web_contents) {
    134   DCHECK_EQ(INSTALLER_STATE_IDLE, state_);
    135   state_ = INSTALLER_STATE_DOWNLOADING;
    136   FOR_EACH_OBSERVER(PluginInstallerObserver, observers_, DownloadStarted());
    137   Profile* profile =
    138       Profile::FromBrowserContext(web_contents->GetBrowserContext());
    139   RecordDownloadSource(DOWNLOAD_INITIATED_BY_PLUGIN_INSTALLER);
    140   BrowserThread::PostTask(
    141       BrowserThread::IO, FROM_HERE,
    142       base::Bind(&BeginDownload,
    143                  plugin_url,
    144                  profile->GetResourceContext(),
    145                  web_contents->GetRenderProcessHost()->GetID(),
    146                  web_contents->GetRenderViewHost()->GetRoutingID(),
    147                  base::Bind(&PluginInstaller::DownloadStarted,
    148                             base::Unretained(this))));
    149 }
    150 
    151 void PluginInstaller::DownloadStarted(content::DownloadItem* item,
    152                                       net::Error error) {
    153   if (!item) {
    154     DCHECK_NE(net::OK, error);
    155     std::string msg =
    156         base::StringPrintf("Error %d: %s", error, net::ErrorToString(error));
    157     DownloadError(msg);
    158     return;
    159   }
    160   DCHECK_EQ(net::OK, error);
    161   item->SetOpenWhenComplete(true);
    162   item->AddObserver(this);
    163 }
    164 
    165 void PluginInstaller::OpenDownloadURL(const GURL& plugin_url,
    166                                       content::WebContents* web_contents) {
    167   DCHECK_EQ(INSTALLER_STATE_IDLE, state_);
    168   web_contents->OpenURL(content::OpenURLParams(
    169       plugin_url,
    170       content::Referrer(web_contents->GetURL(),
    171                         WebKit::WebReferrerPolicyDefault),
    172       NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_TYPED, false));
    173   FOR_EACH_OBSERVER(PluginInstallerObserver, observers_, DownloadFinished());
    174 }
    175 
    176 void PluginInstaller::DownloadError(const std::string& msg) {
    177   DCHECK_EQ(INSTALLER_STATE_DOWNLOADING, state_);
    178   state_ = INSTALLER_STATE_IDLE;
    179   FOR_EACH_OBSERVER(PluginInstallerObserver, observers_, DownloadError(msg));
    180 }
    181 
    182 void PluginInstaller::DownloadCancelled() {
    183   DCHECK_EQ(INSTALLER_STATE_DOWNLOADING, state_);
    184   state_ = INSTALLER_STATE_IDLE;
    185   FOR_EACH_OBSERVER(PluginInstallerObserver, observers_, DownloadCancelled());
    186 }
    187