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