summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/plugin_data_remover.cc8
-rw-r--r--chrome/browser/plugin_data_remover.h17
-rw-r--r--content/browser/plugin_process_host.cc12
-rw-r--r--content/browser/plugin_process_host.h4
-rw-r--r--content/browser/plugin_service.cc22
-rw-r--r--content/browser/plugin_service.h5
-rw-r--r--content/browser/plugin_service_browsertest.cc62
-rw-r--r--content/browser/renderer_host/render_message_filter.cc139
-rw-r--r--content/browser/renderer_host/render_message_filter.h9
9 files changed, 215 insertions, 63 deletions
diff --git a/chrome/browser/plugin_data_remover.cc b/chrome/browser/plugin_data_remover.cc
index 5b06586..e33a00c 100644
--- a/chrome/browser/plugin_data_remover.cc
+++ b/chrome/browser/plugin_data_remover.cc
@@ -24,9 +24,9 @@
namespace {
-const char* kFlashMimeType = "application/x-shockwave-flash";
+const char kFlashMimeType[] = "application/x-shockwave-flash";
// The minimum Flash Player version that implements NPP_ClearSiteData.
-const char* kMinFlashVersion = "10.3";
+const char kMinFlashVersion[] = "10.3";
const int64 kRemovalTimeoutMs = 10000;
const uint64 kClearAllData = 0;
@@ -97,6 +97,10 @@ void PluginDataRemover::SetPluginInfo(
const webkit::WebPluginInfo& info) {
}
+void PluginDataRemover::OnFoundPluginProcessHost(
+ PluginProcessHost* host) {
+}
+
void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) {
ConnectToChannel(handle);
// Balancing the AddRef call in StartRemoving.
diff --git a/chrome/browser/plugin_data_remover.h b/chrome/browser/plugin_data_remover.h
index 9ff4235..c97a191 100644
--- a/chrome/browser/plugin_data_remover.h
+++ b/chrome/browser/plugin_data_remover.h
@@ -47,16 +47,17 @@ class PluginDataRemover : public base::RefCountedThreadSafe<PluginDataRemover>,
void Wait();
// PluginProcessHost::Client methods.
- virtual int ID();
- virtual bool OffTheRecord();
- virtual const content::ResourceContext& GetResourceContext();
- virtual void SetPluginInfo(const webkit::WebPluginInfo& info);
- virtual void OnChannelOpened(const IPC::ChannelHandle& handle);
- virtual void OnError();
+ virtual int ID() OVERRIDE;
+ virtual bool OffTheRecord() OVERRIDE;
+ virtual const content::ResourceContext& GetResourceContext() OVERRIDE;
+ virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE;
+ virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE;
+ virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE;
+ virtual void OnError() OVERRIDE;
// IPC::Channel::Listener methods.
- virtual bool OnMessageReceived(const IPC::Message& message);
- virtual void OnChannelError();
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual void OnChannelError() OVERRIDE;
private:
friend class base::RefCountedThreadSafe<PluginDataRemover>;
diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc
index 23516c7..973be60 100644
--- a/content/browser/plugin_process_host.cc
+++ b/content/browser/plugin_process_host.cc
@@ -364,6 +364,18 @@ void PluginProcessHost::OpenChannelToPlugin(Client* client) {
RequestPluginChannel(client);
}
+void PluginProcessHost::CancelRequest(Client* client) {
+ std::vector<Client*>::iterator it = pending_requests_.begin();
+ while (it != pending_requests_.end()) {
+ if (client == *it) {
+ pending_requests_.erase(it);
+ return;
+ }
+ ++it;
+ }
+ DCHECK(it != pending_requests_.end());
+}
+
void PluginProcessHost::RequestPluginChannel(Client* client) {
// We can't send any sync messages from the browser because it might lead to
// a hang. However this async messages must be answered right away by the
diff --git a/content/browser/plugin_process_host.h b/content/browser/plugin_process_host.h
index fcec36c..202c9a9 100644
--- a/content/browser/plugin_process_host.h
+++ b/content/browser/plugin_process_host.h
@@ -52,6 +52,7 @@ class PluginProcessHost : public BrowserChildProcessHost {
virtual const content::ResourceContext& GetResourceContext() = 0;
virtual bool OffTheRecord() = 0;
virtual void SetPluginInfo(const webkit::WebPluginInfo& info) = 0;
+ virtual void OnFoundPluginProcessHost(PluginProcessHost* host) = 0;
// The client should delete itself when one of these methods is called.
virtual void OnChannelOpened(const IPC::ChannelHandle& handle) = 0;
virtual void OnError() = 0;
@@ -83,6 +84,9 @@ class PluginProcessHost : public BrowserChildProcessHost {
static void CancelPendingRequestsForResourceContext(
const content::ResourceContext* context);
+ // This function is called to cancel requests to open new channels.
+ void CancelRequest(Client* client);
+
// This function is called on the IO thread once we receive a reply from the
// modal HTML dialog (in the form of a JSON string). This function forwards
// that reply back to the plugin that requested the dialog.
diff --git a/content/browser/plugin_service.cc b/content/browser/plugin_service.cc
index 86670db..daa0c62 100644
--- a/content/browser/plugin_service.cc
+++ b/content/browser/plugin_service.cc
@@ -100,6 +100,8 @@ PluginService::~PluginService() {
if (hklm_event_.get())
hklm_event_->Release();
#endif
+ // Make sure no plugin channel requests have been leaked.
+ DCHECK(pending_plugin_clients_.empty());
}
void PluginService::StartWatchingPlugins() {
@@ -285,6 +287,8 @@ void PluginService::OpenChannelToNpapiPlugin(
const GURL& page_url,
const std::string& mime_type,
PluginProcessHost::Client* client) {
+ DCHECK(!ContainsKey(pending_plugin_clients_, client));
+ pending_plugin_clients_.insert(client);
// The PluginList::GetPluginInfo may need to load the plugins. Don't do it on
// the IO thread.
BrowserThread::PostTask(
@@ -316,6 +320,13 @@ void PluginService::OpenChannelToPpapiBroker(
client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle());
}
+void PluginService::CancelOpenChannelToNpapiPlugin(
+ PluginProcessHost::Client* client) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(ContainsKey(pending_plugin_clients_, client));
+ pending_plugin_clients_.erase(client);
+}
+
void PluginService::GetAllowedPluginForOpenChannelToPlugin(
int render_process_id,
int render_view_id,
@@ -347,11 +358,18 @@ void PluginService::FinishOpenChannelToPlugin(
PluginProcessHost::Client* client) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Make sure it hasn't been canceled yet.
+ if (!ContainsKey(pending_plugin_clients_, client))
+ return;
+ pending_plugin_clients_.erase(client);
+
PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
- if (plugin_host)
+ if (plugin_host) {
+ client->OnFoundPluginProcessHost(plugin_host);
plugin_host->OpenChannelToPlugin(client);
- else
+ } else {
client->OnError();
+ }
}
bool PluginService::GetPluginInfo(int render_process_id,
diff --git a/content/browser/plugin_service.h b/content/browser/plugin_service.h
index 8dbef70f..c75f467 100644
--- a/content/browser/plugin_service.h
+++ b/content/browser/plugin_service.h
@@ -98,6 +98,9 @@ class PluginService
void OpenChannelToPpapiBroker(const FilePath& path,
PpapiBrokerProcessHost::Client* client);
+ // Cancels opening a channel to a NPAPI plugin.
+ void CancelOpenChannelToNpapiPlugin(PluginProcessHost::Client* client);
+
// Gets the plugin in the list of plugins that matches the given url and mime
// type. Must be called on the FILE thread if |use_stale| is NULL.
bool GetPluginInfo(int render_process_id,
@@ -192,6 +195,8 @@ class PluginService
// Weak pointer; outlives us.
content::PluginServiceFilter* filter_;
+ std::set<PluginProcessHost::Client*> pending_plugin_clients_;
+
DISALLOW_COPY_AND_ASSIGN(PluginService);
};
diff --git a/content/browser/plugin_service_browsertest.cc b/content/browser/plugin_service_browsertest.cc
index c49a90b..05f4b2f 100644
--- a/content/browser/plugin_service_browsertest.cc
+++ b/content/browser/plugin_service_browsertest.cc
@@ -4,6 +4,7 @@
#include "content/browser/plugin_service.h"
+#include "base/bind.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "chrome/browser/ui/browser.h"
@@ -42,6 +43,8 @@ class MockPluginProcessHostClient : public PluginProcessHost::Client,
virtual const content::ResourceContext& GetResourceContext() OVERRIDE {
return context_;
}
+ virtual void OnFoundPluginProcessHost(PluginProcessHost* host) {
+ }
void OnChannelOpened(const IPC::ChannelHandle& handle) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -76,8 +79,6 @@ class MockPluginProcessHostClient : public PluginProcessHost::Client,
DISALLOW_COPY_AND_ASSIGN(MockPluginProcessHostClient);
};
-} // namespace
-
class PluginServiceTest : public InProcessBrowserTest {
public:
PluginServiceTest() : InProcessBrowserTest() { }
@@ -101,3 +102,60 @@ IN_PROC_BROWSER_TEST_F(PluginServiceTest, OpenChannelToPlugin) {
0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, &mock_client);
ui_test_utils::RunMessageLoop();
}
+
+// A strict mock that fails if any of the methods are called. They shouldn't be
+// called since the request should get canceled before then.
+class MockCanceledPluginProcessHostClient: public PluginProcessHost::Client {
+ public:
+ // Client implementation.
+ MOCK_METHOD1(OnFoundPluginProcessHost, void(PluginProcessHost* host));
+ MOCK_METHOD1(OnChannelOpened, void(const IPC::ChannelHandle& handle));
+ MOCK_METHOD1(SetPluginInfo, void(const webkit::WebPluginInfo& info));
+ MOCK_METHOD0(OnError, void());
+
+ // Listener implementation.
+ MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message& message));
+ MOCK_METHOD1(OnChannelConnected, void(int32 peer_pid));
+ MOCK_METHOD0(OnChannelError, void());
+ MOCK_METHOD0(OnChannelDenied, void());
+ MOCK_METHOD0(OnChannelListenError, void());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCanceledPluginProcessHostClient);
+};
+
+void DoNothing() {}
+
+void QuitUIMessageLoopFromIOThread() {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ new MessageLoop::QuitTask());
+}
+
+void OpenChannelAndThenCancel(PluginProcessHost::Client* client) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Start opening the channel
+ PluginService::GetInstance()->OpenChannelToNpapiPlugin(
+ 0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client);
+ // Immediately cancel it. This is guaranteed to work since PluginService needs
+ // to consult its filter on the FILE thread.
+ PluginService::GetInstance()->CancelOpenChannelToNpapiPlugin(client);
+ // Before we terminate the test, add a roundtrip through the FILE thread to
+ // make sure that it's had a chance to post back to the IO thread. Then signal
+ // the UI thread to stop and exit the test.
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&DoNothing),
+ base::Bind(&QuitUIMessageLoopFromIOThread));
+}
+
+// Should not attempt to open a channel, since it should be canceled early on.
+IN_PROC_BROWSER_TEST_F(PluginServiceTest, CancelOpenChannelToPlugin) {
+ ::testing::StrictMock<MockPluginProcessHostClient> mock_client(
+ browser()->profile()->GetResourceContext());
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(OpenChannelAndThenCancel, &mock_client));
+ ui_test_utils::RunMessageLoop();
+}
+
+} // namespace
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index f6e4547..1135ed8 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -118,51 +118,6 @@ class ClearCacheCompletion : public RenderMessageCompletionCallback,
}
};
-class OpenChannelToNpapiPluginCallback : public RenderMessageCompletionCallback,
- public PluginProcessHost::Client {
- public:
- OpenChannelToNpapiPluginCallback(RenderMessageFilter* filter,
- const content::ResourceContext& context,
- IPC::Message* reply_msg)
- : RenderMessageCompletionCallback(filter, reply_msg),
- context_(context) {
- }
-
- virtual int ID() OVERRIDE {
- return filter()->render_process_id();
- }
-
- virtual const content::ResourceContext& GetResourceContext() OVERRIDE {
- return context_;
- }
-
- virtual bool OffTheRecord() OVERRIDE {
- return filter()->OffTheRecord();
- }
-
- virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
- info_ = info;
- }
-
- virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
- WriteReplyAndDeleteThis(handle);
- }
-
- virtual void OnError() OVERRIDE {
- WriteReplyAndDeleteThis(IPC::ChannelHandle());
- }
-
- private:
- void WriteReplyAndDeleteThis(const IPC::ChannelHandle& handle) {
- ViewHostMsg_OpenChannelToPlugin::WriteReplyParams(reply_msg(),
- handle, info_);
- SendReplyAndDeleteThis();
- }
-
- const content::ResourceContext& context_;
- webkit::WebPluginInfo info_;
-};
-
class OpenChannelToPpapiPluginCallback : public RenderMessageCompletionCallback,
public PpapiPluginProcessHost::Client {
public:
@@ -278,6 +233,68 @@ class DoomEntriesHelper {
} // namespace
+class RenderMessageFilter::OpenChannelToNpapiPluginCallback
+ : public RenderMessageCompletionCallback,
+ public PluginProcessHost::Client {
+ public:
+ OpenChannelToNpapiPluginCallback(RenderMessageFilter* filter,
+ const content::ResourceContext& context,
+ IPC::Message* reply_msg)
+ : RenderMessageCompletionCallback(filter, reply_msg),
+ context_(context),
+ host_(NULL) {
+ }
+
+ virtual int ID() OVERRIDE {
+ return filter()->render_process_id();
+ }
+
+ virtual const content::ResourceContext& GetResourceContext() OVERRIDE {
+ return context_;
+ }
+
+ virtual bool OffTheRecord() OVERRIDE {
+ return filter()->OffTheRecord();
+ }
+
+ virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
+ info_ = info;
+ }
+
+ virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
+ DCHECK(host);
+ host_ = host;
+ }
+
+ virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
+ WriteReplyAndDeleteThis(handle);
+ }
+
+ virtual void OnError() OVERRIDE {
+ WriteReplyAndDeleteThis(IPC::ChannelHandle());
+ }
+
+ PluginProcessHost* host() const {
+ return host_;
+ }
+
+ void Cancel() {
+ delete this;
+ }
+
+ private:
+ void WriteReplyAndDeleteThis(const IPC::ChannelHandle& handle) {
+ ViewHostMsg_OpenChannelToPlugin::WriteReplyParams(reply_msg(),
+ handle, info_);
+ filter()->OnCompletedOpenChannelToNpapiPlugin(this);
+ SendReplyAndDeleteThis();
+ }
+
+ const content::ResourceContext& context_;
+ webkit::WebPluginInfo info_;
+ PluginProcessHost* host_;
+};
+
RenderMessageFilter::RenderMessageFilter(
int render_process_id,
PluginService* plugin_service,
@@ -302,6 +319,22 @@ RenderMessageFilter::RenderMessageFilter(
RenderMessageFilter::~RenderMessageFilter() {
// This function should be called on the IO thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(plugin_host_clients_.empty());
+}
+
+void RenderMessageFilter::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
+ for (std::set<OpenChannelToNpapiPluginCallback*>::iterator it =
+ plugin_host_clients_.begin(); it != plugin_host_clients_.end(); ++it) {
+ OpenChannelToNpapiPluginCallback* client = *it;
+ if (client->host()) {
+ client->host()->CancelRequest(client);
+ } else {
+ plugin_service_->CancelOpenChannelToNpapiPlugin(client);
+ }
+ client->Cancel();
+ }
+ plugin_host_clients_.clear();
}
void RenderMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
@@ -568,12 +601,13 @@ void RenderMessageFilter::OnOpenChannelToPlugin(int routing_id,
const GURL& policy_url,
const std::string& mime_type,
IPC::Message* reply_msg) {
+ OpenChannelToNpapiPluginCallback* client =
+ new OpenChannelToNpapiPluginCallback(this, resource_context_, reply_msg);
+ DCHECK(!ContainsKey(plugin_host_clients_, client));
+ plugin_host_clients_.insert(client);
plugin_service_->OpenChannelToNpapiPlugin(
render_process_id_, routing_id,
- url, policy_url, mime_type,
- new OpenChannelToNpapiPluginCallback(this,
- resource_context_,
- reply_msg));
+ url, policy_url, mime_type, client);
}
void RenderMessageFilter::OnOpenChannelToPepperPlugin(
@@ -916,3 +950,10 @@ void RenderMessageFilter::SendGetRawCookiesResponse(
ViewHostMsg_GetRawCookies::WriteReplyParams(reply_msg, cookies);
Send(reply_msg);
}
+
+void RenderMessageFilter::OnCompletedOpenChannelToNpapiPlugin(
+ OpenChannelToNpapiPluginCallback* client) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(ContainsKey(plugin_host_clients_, client));
+ plugin_host_clients_.erase(client);
+}
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 247571e..5d63975 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -76,6 +76,9 @@ class RenderMessageFilter : public BrowserMessageFilter {
net::URLRequestContextGetter* request_context,
RenderWidgetHelper* render_widget_helper);
+ // IPC::ChannelProxy::MessageFilter methods:
+ virtual void OnChannelClosing() OVERRIDE;
+
// BrowserMessageFilter methods:
virtual void OverrideThreadForMessage(const IPC::Message& message,
BrowserThread::ID* thread);
@@ -99,6 +102,8 @@ class RenderMessageFilter : public BrowserMessageFilter {
friend class BrowserThread;
friend class DeleteTask<RenderMessageFilter>;
+ class OpenChannelToNpapiPluginCallback;
+
virtual ~RenderMessageFilter();
void OnMsgCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
@@ -226,6 +231,8 @@ class RenderMessageFilter : public BrowserMessageFilter {
bool CheckBenchmarkingEnabled() const;
bool CheckPreparsedJsCachingEnabled() const;
+ void OnCompletedOpenChannelToNpapiPlugin(
+ OpenChannelToNpapiPluginCallback* client);
// Cached resource request dispatcher host and plugin service, guaranteed to
// be non-null if Init succeeds. We do not own the objects, they are managed
@@ -255,6 +262,8 @@ class RenderMessageFilter : public BrowserMessageFilter {
int render_process_id_;
+ std::set<OpenChannelToNpapiPluginCallback*> plugin_host_clients_;
+
DISALLOW_COPY_AND_ASSIGN(RenderMessageFilter);
};