diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-11 19:25:38 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-11 19:25:38 +0000 |
commit | 1de6f2bf3cf4324737eeb5d4d67f3c76bfa1a60a (patch) | |
tree | c5b017af643fa263fc6b97148a78139dee27d0b7 /chrome | |
parent | d3ff52b38ae7096cf95b9cce4308f4081a38a662 (diff) | |
download | chromium_src-1de6f2bf3cf4324737eeb5d4d67f3c76bfa1a60a.zip chromium_src-1de6f2bf3cf4324737eeb5d4d67f3c76bfa1a60a.tar.gz chromium_src-1de6f2bf3cf4324737eeb5d4d67f3c76bfa1a60a.tar.bz2 |
Ensure we don't load plugins on the IO thread
BUG=17938
TEST=added asserts which crash if plugins loaded on IO thread, current UI tests exercise them
Review URL: http://codereview.chromium.org/164305
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23064 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/plugin_service.cc | 12 | ||||
-rw-r--r-- | chrome/browser/plugin_service.h | 6 | ||||
-rw-r--r-- | chrome/browser/renderer_host/buffered_resource_handler.cc | 135 | ||||
-rw-r--r-- | chrome/browser/renderer_host/buffered_resource_handler.h | 17 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_dispatcher_host.cc | 54 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_dispatcher_host.h | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_handler.h | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 18 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 3 |
9 files changed, 176 insertions, 78 deletions
diff --git a/chrome/browser/plugin_service.cc b/chrome/browser/plugin_service.cc index d9d3e65..1360e6f 100644 --- a/chrome/browser/plugin_service.cc +++ b/chrome/browser/plugin_service.cc @@ -75,8 +75,14 @@ PluginService::~PluginService() { #endif } +bool PluginService::PluginsLoaded() { + AutoLock lock(lock_); + return NPAPI::PluginList::PluginsLoaded(); +} + void PluginService::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); AutoLock lock(lock_); NPAPI::PluginList::Singleton()->GetPlugins(refresh, plugins); } @@ -180,6 +186,8 @@ FilePath PluginService::GetPluginPath(const GURL& url, const std::string& clsid, std::string* actual_mime_type) { AutoLock lock(lock_); + DCHECK(NPAPI::PluginList::PluginsLoaded() || + ChromeThread::CurrentlyOn(ChromeThread::FILE)); bool allow_wildcard = true; WebPluginInfo info; if (NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, clsid, @@ -195,12 +203,16 @@ FilePath PluginService::GetPluginPath(const GURL& url, bool PluginService::GetPluginInfoByPath(const FilePath& plugin_path, WebPluginInfo* info) { AutoLock lock(lock_); + DCHECK(NPAPI::PluginList::PluginsLoaded() || + ChromeThread::CurrentlyOn(ChromeThread::FILE)); return NPAPI::PluginList::Singleton()->GetPluginInfoByPath(plugin_path, info); } bool PluginService::HavePluginFor(const std::string& mime_type, bool allow_wildcard) { AutoLock lock(lock_); + DCHECK(NPAPI::PluginList::PluginsLoaded() || + ChromeThread::CurrentlyOn(ChromeThread::FILE)); GURL url; WebPluginInfo info; diff --git a/chrome/browser/plugin_service.h b/chrome/browser/plugin_service.h index 8bcbf7c..c8be00d 100644 --- a/chrome/browser/plugin_service.h +++ b/chrome/browser/plugin_service.h @@ -45,7 +45,11 @@ class PluginService // Returns the PluginService singleton. static PluginService* GetInstance(); - // Gets the list of available plugins. + // Returns true iff the plugin list has been loaded. + bool PluginsLoaded(); + + // Loads the plugin list. Must be called on the file thread only since it may + // have to crawl the disk. void GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins); // Load all the plugins that should be loaded for the lifetime of the browser diff --git a/chrome/browser/renderer_host/buffered_resource_handler.cc b/chrome/browser/renderer_host/buffered_resource_handler.cc index b1007fe..60212e0 100644 --- a/chrome/browser/renderer_host/buffered_resource_handler.cc +++ b/chrome/browser/renderer_host/buffered_resource_handler.cc @@ -9,10 +9,13 @@ #include "base/string_util.h" #include "net/base/mime_sniffer.h" #include "net/base/net_errors.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/plugin_service.h" #include "chrome/browser/renderer_host/download_throttling_resource_handler.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/common/url_constants.h" #include "net/base/mime_sniffer.h" +#include "net/base/mime_util.h" #include "net/base/io_buffer.h" #include "net/http/http_response_headers.h" @@ -49,6 +52,7 @@ BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler, bytes_read_(0), sniff_content_(false), should_buffer_(false), + wait_for_plugins_(false), buffering_(false), finished_(false) { } @@ -118,12 +122,13 @@ bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) { return true; LOG(INFO) << "Finished buffering " << request_->url().spec(); - sniff_content_ = should_buffer_ = false; *bytes_read = bytes_read_; // Done buffering, send the pending ResponseStarted event. if (!CompleteResponseStarted(request_id, true)) return false; + } else if (wait_for_plugins_) { + return true; } // Release the reference that we acquired at OnWillRead. @@ -171,6 +176,12 @@ bool BufferedResourceHandler::DelayResponse() { LOG(INFO) << "To buffer: " << request_->url().spec(); return true; } + + if (ShouldWaitForPlugins()) { + wait_for_plugins_ = true; + return true; + } + return false; } @@ -189,6 +200,12 @@ bool BufferedResourceHandler::ShouldBuffer(const GURL& url, return mime_type == "text/html"; } +bool BufferedResourceHandler::DidBufferEnough(int bytes_read) { + const int kRequiredLength = 256; + + return bytes_read >= kRequiredLength; +} + bool BufferedResourceHandler::KeepBuffering(int bytes_read) { DCHECK(read_buffer_); if (my_buffer_) { @@ -219,17 +236,34 @@ bool BufferedResourceHandler::KeepBuffering(int bytes_read) { response_->response_head.mime_type.assign(new_type); // We just sniffed the mime type, maybe there is a doctype to process. - if (ShouldBuffer(request_->url(), new_type)) + if (ShouldBuffer(request_->url(), new_type)) { should_buffer_ = true; + } else if (ShouldWaitForPlugins()) { + wait_for_plugins_ = true; + } } - if (!finished_ && should_buffer_) { - if (!DidBufferEnough(bytes_read_)) { + if (should_buffer_) { + if (!finished_ && !DidBufferEnough(bytes_read_)) { buffering_ = true; return true; } + + should_buffer_ = false; + if (ShouldWaitForPlugins()) + wait_for_plugins_ = true; } + buffering_ = false; + + if (wait_for_plugins_) { + // We don't want to keep buffering as our buffer will fill up. + ResourceDispatcherHost::ExtraRequestInfo* info = + ResourceDispatcherHost::ExtraInfoForRequest(request_); + host_->PauseRequest(info->process_id, info->request_id, true); + return true; + } + return false; } @@ -238,16 +272,10 @@ bool BufferedResourceHandler::CompleteResponseStarted(int request_id, // Check to see if we should forward the data from this request to the // download thread. // TODO(paulg): Only download if the context from the renderer allows it. - std::string content_disposition; - request_->GetResponseHeaderByName("content-disposition", - &content_disposition); - ResourceDispatcherHost::ExtraRequestInfo* info = ResourceDispatcherHost::ExtraInfoForRequest(request_); - if (info->allow_download && - host_->ShouldDownload(response_->response_head.mime_type, - content_disposition)) { + if (info->allow_download && ShouldDownload(NULL)) { if (response_->response_head.headers && // Can be NULL if FTP. response_->response_head.headers->response_code() / 100 != 2) { // The response code indicates that this is an error page, but we don't @@ -293,8 +321,87 @@ bool BufferedResourceHandler::CompleteResponseStarted(int request_id, return real_handler_->OnResponseStarted(request_id, response_); } -bool BufferedResourceHandler::DidBufferEnough(int bytes_read) { - const int kRequiredLength = 256; +bool BufferedResourceHandler::ShouldWaitForPlugins() { + bool need_plugin_list; + if (!ShouldDownload(&need_plugin_list) || !need_plugin_list) + return false; - return bytes_read >= kRequiredLength; + // Schedule plugin loading on the file thread. + ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE, + NewRunnableMethod(this, &BufferedResourceHandler::LoadPlugins)); + return true; +} + +// This test mirrors the decision that WebKit makes in +// WebFrameLoaderClient::dispatchDecidePolicyForMIMEType. +bool BufferedResourceHandler::ShouldDownload(bool* need_plugin_list) { + if (need_plugin_list) + *need_plugin_list = false; + std::string type = StringToLowerASCII(response_->response_head.mime_type); + std::string disposition; + request_->GetResponseHeaderByName("content-disposition", &disposition); + disposition = StringToLowerASCII(disposition); + + // First, examine content-disposition. + if (!disposition.empty()) { + bool should_download = true; + + // Some broken sites just send ... + // Content-Disposition: ; filename="file" + // ... screen those out here. + if (disposition[0] == ';') + should_download = false; + + if (disposition.compare(0, 6, "inline") == 0) + should_download = false; + + // Some broken sites just send ... + // Content-Disposition: filename="file" + // ... without a disposition token... Screen those out. + if (disposition.compare(0, 8, "filename") == 0) + should_download = false; + + // Also in use is Content-Disposition: name="file" + if (disposition.compare(0, 4, "name") == 0) + should_download = false; + + // We have a content-disposition of "attachment" or unknown. + // RFC 2183, section 2.8 says that an unknown disposition + // value should be treated as "attachment". + if (should_download) + return true; + } + + // MIME type checking. + if (net::IsSupportedMimeType(type)) + return false; + + if (need_plugin_list) { + if (!PluginService::GetInstance()->PluginsLoaded()) { + *need_plugin_list = true; + return true; + } + } else { + DCHECK(PluginService::GetInstance()->PluginsLoaded()); + } + + // Finally, check the plugin service. + bool allow_wildcard = false; + return !PluginService::GetInstance()->HavePluginFor(type, allow_wildcard); +} + +void BufferedResourceHandler::LoadPlugins() { + std::vector<WebPluginInfo> plugins; + PluginService::GetInstance()->GetPlugins(false, &plugins); + ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE, + NewRunnableMethod(this, &BufferedResourceHandler::OnPluginsLoaded)); +} + +void BufferedResourceHandler::OnPluginsLoaded() { + wait_for_plugins_ = false; + ResourceDispatcherHost::ExtraRequestInfo* info = + ResourceDispatcherHost::ExtraInfoForRequest(request_); + host_->PauseRequest(info->process_id, info->request_id, false); + if (!CompleteResponseStarted(info->request_id, false)) + host_->CancelRequest(info->process_id, info->request_id, false); } diff --git a/chrome/browser/renderer_host/buffered_resource_handler.h b/chrome/browser/renderer_host/buffered_resource_handler.h index 3799b99..b36ac9b 100644 --- a/chrome/browser/renderer_host/buffered_resource_handler.h +++ b/chrome/browser/renderer_host/buffered_resource_handler.h @@ -49,6 +49,22 @@ class BufferedResourceHandler : public ResourceHandler { // this is invoked from |OnResponseCompleted|. bool CompleteResponseStarted(int request_id, bool in_complete); + // Returns true if we have to wait until the plugin list is generated. + bool ShouldWaitForPlugins(); + + // A test to determining whether the request should be forwarded to the + // download thread. If need_plugin_list was passed in and was set to true, + // that means that the check couldn't be fully done because the plugins aren't + // loaded. The function should be called again after the plugin list is + // loaded. + bool ShouldDownload(bool* need_plugin_list); + + // Called on the file thread to load the list of plugins. + void LoadPlugins(); + + // Called on the IO thread once the list of plugins has been loaded. + void OnPluginsLoaded(); + scoped_refptr<ResourceHandler> real_handler_; scoped_refptr<ResourceResponse> response_; ResourceDispatcherHost* host_; @@ -59,6 +75,7 @@ class BufferedResourceHandler : public ResourceHandler { int bytes_read_; bool sniff_content_; bool should_buffer_; + bool wait_for_plugins_; bool buffering_; bool finished_; diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc index 05d116d..590a31d 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.cc +++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc @@ -256,7 +256,6 @@ ResourceDispatcherHost::ResourceDispatcherHost(MessageLoop* io_loop) safe_browsing_(new SafeBrowsingService), webkit_thread_(new WebKitThread), request_id_(-1), - plugin_service_(PluginService::GetInstance()), ALLOW_THIS_IN_INITIALIZER_LIST(method_runner_(this)), is_shutdown_(false), max_outstanding_requests_cost_per_process_( @@ -468,7 +467,7 @@ void ResourceDispatcherHost::BeginRequest( // requests. Does nothing if they are already loaded. // TODO(mpcomplete): This takes 200 ms! Investigate parallelizing this by // starting the load earlier in a BG thread. - plugin_service_->LoadChromePlugins(this); + PluginService::GetInstance()->LoadChromePlugins(this); // Construct the event handler. scoped_refptr<ResourceHandler> handler; @@ -668,7 +667,7 @@ void ResourceDispatcherHost::BeginDownload(const GURL& url, // Ensure the Chrome plugins are loaded, as they may intercept network // requests. Does nothing if they are already loaded. - plugin_service_->LoadChromePlugins(this); + PluginService::GetInstance()->LoadChromePlugins(this); URLRequest* request = new URLRequest(url, this); request_id_--; @@ -734,7 +733,7 @@ void ResourceDispatcherHost::BeginSaveFile(const GURL& url, // Ensure the Chrome plugins are loaded, as they may intercept network // requests. Does nothing if they are already loaded. - plugin_service_->LoadChromePlugins(this); + PluginService::GetInstance()->LoadChromePlugins(this); scoped_refptr<ResourceHandler> handler = new SaveFileResourceHandler(process_id, @@ -1260,53 +1259,6 @@ void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request) { } } -// This test mirrors the decision that WebKit makes in -// WebFrameLoaderClient::dispatchDecidePolicyForMIMEType. -// static. -bool ResourceDispatcherHost::ShouldDownload( - const std::string& mime_type, const std::string& content_disposition) { - std::string type = StringToLowerASCII(mime_type); - std::string disposition = StringToLowerASCII(content_disposition); - - // First, examine content-disposition. - if (!disposition.empty()) { - bool should_download = true; - - // Some broken sites just send ... - // Content-Disposition: ; filename="file" - // ... screen those out here. - if (disposition[0] == ';') - should_download = false; - - if (disposition.compare(0, 6, "inline") == 0) - should_download = false; - - // Some broken sites just send ... - // Content-Disposition: filename="file" - // ... without a disposition token... Screen those out. - if (disposition.compare(0, 8, "filename") == 0) - should_download = false; - - // Also in use is Content-Disposition: name="file" - if (disposition.compare(0, 4, "name") == 0) - should_download = false; - - // We have a content-disposition of "attachment" or unknown. - // RFC 2183, section 2.8 says that an unknown disposition - // value should be treated as "attachment". - if (should_download) - return true; - } - - // MIME type checking. - if (net::IsSupportedMimeType(type)) - return false; - - // Finally, check the plugin service. - bool allow_wildcard = false; - return !plugin_service_->HavePluginFor(type, allow_wildcard); -} - bool ResourceDispatcherHost::PauseRequestIfNeeded(ExtraRequestInfo* info) { if (info->pause_count > 0) info->is_paused = true; diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h index 5353562..bcac386 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.h +++ b/chrome/browser/renderer_host/resource_dispatcher_host.h @@ -352,11 +352,6 @@ class ResourceDispatcherHost : public URLRequest::Delegate { // Retrieves a URLRequest. Must be called from the IO thread. URLRequest* GetURLRequest(GlobalRequestID request_id) const; - // A test to determining whether a given request should be forwarded to the - // download thread. - bool ShouldDownload(const std::string& mime_type, - const std::string& content_disposition); - // Notifies our observers that a request has been cancelled. void NotifyResponseCompleted(URLRequest* request, int process_id); @@ -551,8 +546,6 @@ class ResourceDispatcherHost : public URLRequest::Delegate { // List of objects observing resource dispatching. ObserverList<Observer> observer_list_; - PluginService* plugin_service_; - // For running tasks. ScopedRunnableMethodFactory<ResourceDispatcherHost> method_runner_; diff --git a/chrome/browser/renderer_host/resource_handler.h b/chrome/browser/renderer_host/resource_handler.h index 76851b6..fec7db0 100644 --- a/chrome/browser/renderer_host/resource_handler.h +++ b/chrome/browser/renderer_host/resource_handler.h @@ -52,7 +52,7 @@ struct ResourceResponse : public base::RefCounted<ResourceResponse> { // The resource dispatcher host uses this interface to push load events to the // renderer, allowing for differences in the types of IPC messages generated. // See the implementations of this interface defined below. -class ResourceHandler : public base::RefCounted<ResourceHandler> { +class ResourceHandler : public base::RefCountedThreadSafe<ResourceHandler> { public: virtual ~ResourceHandler() {} diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index d817aa7..77e45ce 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -288,7 +288,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { #if defined(OS_WIN) // This hack is Windows-specific. IPC_MESSAGE_HANDLER(ViewHostMsg_LoadFont, OnLoadFont) #endif - IPC_MESSAGE_HANDLER(ViewHostMsg_GetPlugins, OnGetPlugins) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPlugins, OnGetPlugins) IPC_MESSAGE_HANDLER(ViewHostMsg_GetPluginPath, OnGetPluginPath) IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl) IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_ContextMenu, @@ -545,8 +545,20 @@ void ResourceMessageFilter::OnLoadFont(LOGFONT font) { #endif void ResourceMessageFilter::OnGetPlugins(bool refresh, - std::vector<WebPluginInfo>* plugins) { - plugin_service_->GetPlugins(refresh, plugins); + IPC::Message* reply_msg) { + ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE, + NewRunnableMethod(this, &ResourceMessageFilter::OnGetPluginsOnFileThread, + refresh, reply_msg)); +} + +void ResourceMessageFilter::OnGetPluginsOnFileThread(bool refresh, + IPC::Message* reply_msg) { + std::vector<WebPluginInfo> plugins; + PluginService::GetInstance()->GetPlugins(refresh, &plugins); + + ViewHostMsg_GetPlugins::WriteReplyParams(reply_msg, plugins); + ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE, + NewRunnableMethod(this, &ResourceMessageFilter::Send, reply_msg)); } void ResourceMessageFilter::OnGetPluginPath(const GURL& url, diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index e435bac..8cdd660 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -141,7 +141,8 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, // Not handled in the IO thread on Mac. void OnGetScreenInfo(gfx::NativeViewId window, IPC::Message* reply); #endif - void OnGetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins); + void OnGetPlugins(bool refresh, IPC::Message* reply_msg); + void OnGetPluginsOnFileThread(bool refresh, IPC::Message* reply_msg); void OnGetPluginPath(const GURL& url, const GURL& policy_url, const std::string& mime_type, |