plugin_installer.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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.h"
10#include "chrome/browser/download/download_service.h"
11#include "chrome/browser/download/download_service_factory.h"
12#include "chrome/browser/download/download_util.h"
13#include "chrome/browser/platform_util.h"
14#include "chrome/browser/plugins/plugin_installer_observer.h"
15#include "chrome/browser/profiles/profile.h"
16#include "content/public/browser/browser_context.h"
17#include "content/public/browser/browser_thread.h"
18#include "content/public/browser/download_id.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
30using content::BrowserContext;
31using content::BrowserThread;
32using content::DownloadItem;
33using content::ResourceDispatcherHost;
34
35namespace {
36
37void 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::DownloadId::Invalid(),
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
69PluginInstaller::PluginInstaller()
70    : state_(INSTALLER_STATE_IDLE) {
71}
72
73PluginInstaller::~PluginInstaller() {
74}
75
76void 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
105void PluginInstaller::OnDownloadDestroyed(DownloadItem* download) {
106  DCHECK_EQ(INSTALLER_STATE_DOWNLOADING, state_);
107  state_ = INSTALLER_STATE_IDLE;
108  download->RemoveObserver(this);
109}
110
111void PluginInstaller::AddObserver(PluginInstallerObserver* observer) {
112  observers_.AddObserver(observer);
113}
114
115void 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
123void PluginInstaller::AddWeakObserver(WeakPluginInstallerObserver* observer) {
124  weak_observers_.AddObserver(observer);
125}
126
127void PluginInstaller::RemoveWeakObserver(
128    WeakPluginInstallerObserver* observer) {
129  weak_observers_.RemoveObserver(observer);
130}
131
132void 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  download_util::RecordDownloadSource(
140      download_util::INITIATED_BY_PLUGIN_INSTALLER);
141  BrowserThread::PostTask(
142      BrowserThread::IO, FROM_HERE,
143      base::Bind(&BeginDownload,
144                 plugin_url,
145                 profile->GetResourceContext(),
146                 web_contents->GetRenderProcessHost()->GetID(),
147                 web_contents->GetRenderViewHost()->GetRoutingID(),
148                 base::Bind(&PluginInstaller::DownloadStarted,
149                            base::Unretained(this))));
150}
151
152void PluginInstaller::DownloadStarted(content::DownloadItem* item,
153                                      net::Error error) {
154  if (!item) {
155    DCHECK_NE(net::OK, error);
156    std::string msg =
157        base::StringPrintf("Error %d: %s", error, net::ErrorToString(error));
158    DownloadError(msg);
159    return;
160  }
161  DCHECK_EQ(net::OK, error);
162  item->SetOpenWhenComplete(true);
163  item->AddObserver(this);
164}
165
166void PluginInstaller::OpenDownloadURL(const GURL& plugin_url,
167                                      content::WebContents* web_contents) {
168  DCHECK_EQ(INSTALLER_STATE_IDLE, state_);
169  web_contents->OpenURL(content::OpenURLParams(
170      plugin_url,
171      content::Referrer(web_contents->GetURL(),
172                        WebKit::WebReferrerPolicyDefault),
173      NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_TYPED, false));
174  FOR_EACH_OBSERVER(PluginInstallerObserver, observers_, DownloadFinished());
175}
176
177void PluginInstaller::DownloadError(const std::string& msg) {
178  DCHECK_EQ(INSTALLER_STATE_DOWNLOADING, state_);
179  state_ = INSTALLER_STATE_IDLE;
180  FOR_EACH_OBSERVER(PluginInstallerObserver, observers_, DownloadError(msg));
181}
182
183void PluginInstaller::DownloadCancelled() {
184  DCHECK_EQ(INSTALLER_STATE_DOWNLOADING, state_);
185  state_ = INSTALLER_STATE_IDLE;
186  FOR_EACH_OBSERVER(PluginInstallerObserver, observers_, DownloadCancelled());
187}
188