diff options
-rw-r--r-- | chrome/browser/plugin_data_remover.cc | 11 | ||||
-rw-r--r-- | chrome/browser/plugin_data_remover.h | 18 | ||||
-rw-r--r-- | content/browser/plugin_process_host.cc | 34 | ||||
-rw-r--r-- | content/browser/plugin_process_host.h | 12 | ||||
-rw-r--r-- | content/browser/plugin_service.cc | 22 | ||||
-rw-r--r-- | content/browser/plugin_service.h | 5 | ||||
-rw-r--r-- | content/browser/plugin_service_browsertest.cc | 216 | ||||
-rw-r--r-- | content/browser/renderer_host/render_message_filter.cc | 153 | ||||
-rw-r--r-- | content/browser/renderer_host/render_message_filter.h | 9 |
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); }; |