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 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::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 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 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 151void 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 165void 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 176void 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 182void PluginInstaller::DownloadCancelled() { 183 DCHECK_EQ(INSTALLER_STATE_DOWNLOADING, state_); 184 state_ = INSTALLER_STATE_IDLE; 185 FOR_EACH_OBSERVER(PluginInstallerObserver, observers_, DownloadCancelled()); 186} 187