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