summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/plugin_data_remover.cc11
-rw-r--r--chrome/browser/plugin_data_remover.h18
-rw-r--r--content/browser/plugin_process_host.cc34
-rw-r--r--content/browser/plugin_process_host.h12
-rw-r--r--content/browser/plugin_service.cc22
-rw-r--r--content/browser/plugin_service.h5
-rw-r--r--content/browser/plugin_service_browsertest.cc216
-rw-r--r--content/browser/renderer_host/render_message_filter.cc153
-rw-r--r--content/browser/renderer_host/render_message_filter.h9
9 files changed, 408 insertions, 72 deletions
diff --git a/chrome/browser/plugin_data_remover.cc b/chrome/browser/plugin_data_remover.cc
index 5b06586..debac0b 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,13 @@ void PluginDataRemover::SetPluginInfo(
const webkit::WebPluginInfo& info) {
}
+void PluginDataRemover::OnFoundPluginProcessHost(
+ PluginProcessHost* host) {
+}
+
+void PluginDataRemover::OnSentPluginChannelRequest() {
+}
+
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..2b15e08 100644
--- a/chrome/browser/plugin_data_remover.h
+++ b/chrome/browser/plugin_data_remover.h
@@ -47,16 +47,18 @@ 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 OnSentPluginChannelRequest() 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..f9b4e10 100644
--- a/content/browser/plugin_process_host.cc
+++ b/content/browser/plugin_process_host.cc
@@ -328,7 +328,7 @@ void PluginProcessHost::CancelRequests() {
while (!sent_requests_.empty()) {
sent_requests_.front()->OnError();
- sent_requests_.pop();
+ sent_requests_.pop_front();
}
}
@@ -364,6 +364,30 @@ void PluginProcessHost::OpenChannelToPlugin(Client* client) {
RequestPluginChannel(client);
}
+void PluginProcessHost::CancelPendingRequest(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::CancelSentRequest(Client* client) {
+ std::list<Client*>::iterator it = sent_requests_.begin();
+ while (it != sent_requests_.end()) {
+ if (client == *it) {
+ *it = NULL;
+ return;
+ }
+ ++it;
+ }
+ DCHECK(it != sent_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
@@ -376,7 +400,8 @@ void PluginProcessHost::RequestPluginChannel(Client* client) {
client->OffTheRecord());
msg->set_unblock(true);
if (Send(msg)) {
- sent_requests_.push(client);
+ sent_requests_.push_back(client);
+ client->OnSentPluginChannelRequest();
} else {
client->OnError();
}
@@ -386,6 +411,7 @@ void PluginProcessHost::OnChannelCreated(
const IPC::ChannelHandle& channel_handle) {
Client* client = sent_requests_.front();
- client->OnChannelOpened(channel_handle);
- sent_requests_.pop();
+ if (client)
+ client->OnChannelOpened(channel_handle);
+ sent_requests_.pop_front();
}
diff --git a/content/browser/plugin_process_host.h b/content/browser/plugin_process_host.h
index fcec36c..8cfc249 100644
--- a/content/browser/plugin_process_host.h
+++ b/content/browser/plugin_process_host.h
@@ -8,7 +8,7 @@
#include "build/build_config.h"
-#include <queue>
+#include <list>
#include <set>
#include <string>
#include <vector>
@@ -52,6 +52,8 @@ 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;
+ virtual void OnSentPluginChannelRequest() = 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 +85,12 @@ class PluginProcessHost : public BrowserChildProcessHost {
static void CancelPendingRequestsForResourceContext(
const content::ResourceContext* context);
+ // This function is called to cancel pending requests to open new channels.
+ void CancelPendingRequest(Client* client);
+
+ // This function is called to cancel sent requests to open new channels.
+ void CancelSentRequest(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.
@@ -138,7 +146,7 @@ class PluginProcessHost : public BrowserChildProcessHost {
// These are the channel requests that we have already sent to
// the plugin process, but haven't heard back about yet.
- std::queue<Client*> sent_requests_;
+ std::list<Client*> sent_requests_;
// Information about the plugin.
webkit::WebPluginInfo info_;
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 f7cb6f3..23ef03b 100644
--- a/content/browser/plugin_service.h
+++ b/content/browser/plugin_service.h
@@ -99,6 +99,9 @@ class CONTENT_EXPORT 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,
@@ -193,6 +196,8 @@ class CONTENT_EXPORT 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..6228a9c 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"
@@ -18,7 +19,7 @@
namespace {
-const char* kNPAPITestPluginMimeType = "application/vnd.npapi-test";
+const char kNPAPITestPluginMimeType[] = "application/vnd.npapi-test";
// Mock up of the Client and the Listener classes that would supply the
// communication channel with the plugin.
@@ -42,8 +43,10 @@ class MockPluginProcessHostClient : public PluginProcessHost::Client,
virtual const content::ResourceContext& GetResourceContext() OVERRIDE {
return context_;
}
+ virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {}
+ virtual void OnSentPluginChannelRequest() OVERRIDE {}
- void OnChannelOpened(const IPC::ChannelHandle& handle) {
+ virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
ASSERT_TRUE(set_plugin_info_called_);
ASSERT_TRUE(!channel_);
@@ -51,7 +54,7 @@ class MockPluginProcessHostClient : public PluginProcessHost::Client,
ASSERT_TRUE(channel_->Connect());
}
- void SetPluginInfo(const webkit::WebPluginInfo& info) {
+ void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
ASSERT_TRUE(info.mime_types.size());
ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
set_plugin_info_called_ = true;
@@ -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,208 @@ 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 MockCanceledPluginServiceClient : public PluginProcessHost::Client {
+ public:
+ MockCanceledPluginServiceClient(const content::ResourceContext& context)
+ : context_(context),
+ get_resource_context_called_(false) {
+ }
+
+ virtual ~MockCanceledPluginServiceClient() {}
+
+ // Client implementation.
+ MOCK_METHOD0(ID, int());
+ virtual const content::ResourceContext& GetResourceContext() OVERRIDE {
+ get_resource_context_called_ = true;
+ return context_;
+ }
+ MOCK_METHOD0(OffTheRecord, bool());
+ MOCK_METHOD1(OnFoundPluginProcessHost, void(PluginProcessHost* host));
+ MOCK_METHOD0(OnSentPluginChannelRequest, void());
+ MOCK_METHOD1(OnChannelOpened, void(const IPC::ChannelHandle& handle));
+ MOCK_METHOD1(SetPluginInfo, void(const webkit::WebPluginInfo& info));
+ MOCK_METHOD0(OnError, void());
+
+ bool get_resource_context_called() const {
+ return get_resource_context_called_;
+ }
+
+ private:
+ const content::ResourceContext& context_;
+ bool get_resource_context_called_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCanceledPluginServiceClient);
+};
+
+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, CancelOpenChannelToPluginService) {
+ ::testing::StrictMock<MockCanceledPluginServiceClient> mock_client(
+ browser()->profile()->GetResourceContext());
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(OpenChannelAndThenCancel, &mock_client));
+ ui_test_utils::RunMessageLoop();
+ EXPECT_TRUE(mock_client.get_resource_context_called());
+}
+
+class MockCanceledBeforeSentPluginProcessHostClient
+ : public MockCanceledPluginServiceClient {
+ public:
+ MockCanceledBeforeSentPluginProcessHostClient(
+ const content::ResourceContext& context)
+ : MockCanceledPluginServiceClient(context),
+ set_plugin_info_called_(false),
+ on_found_plugin_process_host_called_(false),
+ host_(NULL) {}
+
+ virtual ~MockCanceledBeforeSentPluginProcessHostClient() {}
+
+ // Client implementation.
+ virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ASSERT_TRUE(info.mime_types.size());
+ ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
+ set_plugin_info_called_ = true;
+ }
+ virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ set_on_found_plugin_process_host_called();
+ set_host(host);
+ // This gets called right before we request the plugin<=>renderer channel,
+ // so we have to post a task to cancel it.
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&PluginProcessHost::CancelPendingRequest,
+ base::Unretained(host), this));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&QuitUIMessageLoopFromIOThread));
+ }
+
+ bool set_plugin_info_called() const {
+ return set_plugin_info_called_;
+ }
+
+ bool on_found_plugin_process_host_called() const {
+ return on_found_plugin_process_host_called_;
+ }
+
+ protected:
+ void set_on_found_plugin_process_host_called() {
+ on_found_plugin_process_host_called_ = true;
+ }
+ void set_host(PluginProcessHost* host) {
+ host_ = host;
+ }
+
+ PluginProcessHost* host() const { return host_; }
+
+ private:
+ bool set_plugin_info_called_;
+ bool on_found_plugin_process_host_called_;
+ PluginProcessHost* host_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCanceledBeforeSentPluginProcessHostClient);
+};
+
+void OpenChannel(PluginProcessHost::Client* client) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Start opening the channel
+ PluginService::GetInstance()->OpenChannelToNpapiPlugin(
+ 0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client);
+}
+
+IN_PROC_BROWSER_TEST_F(
+ PluginServiceTest, CancelBeforeSentOpenChannelToPluginProcessHost) {
+ ::testing::StrictMock<MockCanceledBeforeSentPluginProcessHostClient>
+ mock_client(browser()->profile()->GetResourceContext());
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(OpenChannel, &mock_client));
+ ui_test_utils::RunMessageLoop();
+ EXPECT_TRUE(mock_client.get_resource_context_called());
+ EXPECT_TRUE(mock_client.set_plugin_info_called());
+ EXPECT_TRUE(mock_client.on_found_plugin_process_host_called());
+}
+
+class MockCanceledAfterSentPluginProcessHostClient
+ : public MockCanceledBeforeSentPluginProcessHostClient {
+ public:
+ MockCanceledAfterSentPluginProcessHostClient(
+ const content::ResourceContext& context)
+ : MockCanceledBeforeSentPluginProcessHostClient(context),
+ on_sent_plugin_channel_request_called_(false) {}
+ virtual ~MockCanceledAfterSentPluginProcessHostClient() {}
+
+ // Client implementation.
+
+ virtual int ID() OVERRIDE { return 42; }
+ virtual bool OffTheRecord() OVERRIDE { return false; }
+
+ // We override this guy again since we don't want to cancel yet.
+ virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ set_on_found_plugin_process_host_called();
+ set_host(host);
+ }
+
+ virtual void OnSentPluginChannelRequest() OVERRIDE {
+ on_sent_plugin_channel_request_called_ = true;
+ host()->CancelSentRequest(this);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ new MessageLoop::QuitTask());
+ }
+
+ bool on_sent_plugin_channel_request_called() const {
+ return on_sent_plugin_channel_request_called_;
+ }
+
+ private:
+ bool on_sent_plugin_channel_request_called_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCanceledAfterSentPluginProcessHostClient);
+};
+
+// Should not attempt to open a channel, since it should be canceled early on.
+IN_PROC_BROWSER_TEST_F(
+ PluginServiceTest, CancelAfterSentOpenChannelToPluginProcessHost) {
+ ::testing::StrictMock<MockCanceledAfterSentPluginProcessHostClient>
+ mock_client(browser()->profile()->GetResourceContext());
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(OpenChannel, &mock_client));
+ ui_test_utils::RunMessageLoop();
+ EXPECT_TRUE(mock_client.get_resource_context_called());
+ EXPECT_TRUE(mock_client.set_plugin_info_called());
+ EXPECT_TRUE(mock_client.on_found_plugin_process_host_called());
+ EXPECT_TRUE(mock_client.on_sent_plugin_channel_request_called());
+}
+
+} // namespace
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 3e8fbd5..5037a66 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,78 @@ 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),
+ sent_plugin_channel_request_(false) {
+ }
+
+ 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 OnSentPluginChannelRequest() OVERRIDE {
+ sent_plugin_channel_request_ = true;
+ }
+
+ virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
+ WriteReplyAndDeleteThis(handle);
+ }
+
+ virtual void OnError() OVERRIDE {
+ WriteReplyAndDeleteThis(IPC::ChannelHandle());
+ }
+
+ PluginProcessHost* host() const {
+ return host_;
+ }
+
+ bool sent_plugin_channel_request() const {
+ return sent_plugin_channel_request_;
+ }
+
+ 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_;
+ bool sent_plugin_channel_request_;
+};
+
RenderMessageFilter::RenderMessageFilter(
int render_process_id,
PluginService* plugin_service,
@@ -302,6 +329,26 @@ 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()) {
+ if (client->sent_plugin_channel_request()) {
+ client->host()->CancelSentRequest(client);
+ } else {
+ client->host()->CancelPendingRequest(client);
+ }
+ } else {
+ plugin_service_->CancelOpenChannelToNpapiPlugin(client);
+ }
+ client->Cancel();
+ }
+ plugin_host_clients_.clear();
}
void RenderMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
@@ -568,12 +615,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(
@@ -917,3 +965,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);
};