diff options
author | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-31 01:34:20 +0000 |
---|---|---|
committer | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-31 01:34:20 +0000 |
commit | 41b2780f0135d23196958816d3adcfd606b80f1e (patch) | |
tree | 306a00be7404dfc6d3ff9ef667d35827f87281a2 /chrome/browser | |
parent | 18a12354e6c3e1edf2f85e11cd7359127d2d3ce2 (diff) | |
download | chromium_src-41b2780f0135d23196958816d3adcfd606b80f1e.zip chromium_src-41b2780f0135d23196958816d3adcfd606b80f1e.tar.gz chromium_src-41b2780f0135d23196958816d3adcfd606b80f1e.tar.bz2 |
Move proxy resolve requests out of plugin/renderer process, and into the browser.
Review URL: http://codereview.chromium.org/14142
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9006 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.scons | 3 | ||||
-rw-r--r-- | chrome/browser/browser.vcproj | 8 | ||||
-rw-r--r-- | chrome/browser/net/resolve_proxy_msg_helper.cc | 89 | ||||
-rw-r--r-- | chrome/browser/net/resolve_proxy_msg_helper.h | 104 | ||||
-rw-r--r-- | chrome/browser/net/resolve_proxy_msg_helper_unittest.cc | 349 | ||||
-rw-r--r-- | chrome/browser/plugin_process_host.cc | 67 | ||||
-rw-r--r-- | chrome/browser/plugin_process_host.h | 16 | ||||
-rw-r--r-- | chrome/browser/resource_message_filter.cc | 17 | ||||
-rw-r--r-- | chrome/browser/resource_message_filter.h | 15 |
9 files changed, 603 insertions, 65 deletions
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons index 5a56ec1..09ab7e5 100644 --- a/chrome/browser/browser.scons +++ b/chrome/browser/browser.scons @@ -432,6 +432,8 @@ input_files = ChromeFileList([ 'net/dns_slave.h', 'net/referrer.cc', 'net/referrer.h', + 'net/resolve_proxy_msg_helper.cc', + 'net/resolve_proxy_msg_helper.h', 'net/sdch_dictionary_fetcher.cc', 'net/sdch_dictionary_fetcher.h', 'net/url_fetcher.cc', @@ -746,6 +748,7 @@ if not env.Bit('windows'): 'net/dns_global.cc', 'net/dns_master.cc', 'net/dns_slave.cc', + 'net/resolve_proxy_msg_helper.cc', 'google_update.cc', 'password_manager/encryptor.cc', 'password_manager/ie7_password.cc', diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index b76a16f..253a164 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -1650,6 +1650,14 @@ > </File> <File + RelativePath=".\net\resolve_proxy_msg_helper.cc" + > + </File> + <File + RelativePath=".\net\resolve_proxy_msg_helper.h" + > + </File> + <File RelativePath=".\net\sdch_dictionary_fetcher.cc" > </File> diff --git a/chrome/browser/net/resolve_proxy_msg_helper.cc b/chrome/browser/net/resolve_proxy_msg_helper.cc new file mode 100644 index 0000000..dca5ad6 --- /dev/null +++ b/chrome/browser/net/resolve_proxy_msg_helper.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/net/resolve_proxy_msg_helper.h" + +#include "base/compiler_specific.h" +#include "chrome/browser/profile.h" +#include "net/base/net_errors.h" +#include "net/url_request/url_request_context.h" + +ResolveProxyMsgHelper::ResolveProxyMsgHelper(Delegate* delegate, + net::ProxyService* proxy_service) + : proxy_service_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST(callback_( + this, &ResolveProxyMsgHelper::OnResolveProxyCompleted)), + delegate_(delegate), + proxy_service_override_(proxy_service) { +} + +void ResolveProxyMsgHelper::Start(const GURL& url, IPC::Message* reply_msg) { + // Enqueue the pending request. + pending_requests_.push_back(PendingRequest(url, reply_msg)); + + // If nothing is in progress, start. + if (pending_requests_.size() == 1) + StartPendingRequest(); +} + +void ResolveProxyMsgHelper::OnResolveProxyCompleted(int result) { + CHECK(!pending_requests_.empty()); + + // Notify the delegate of completion. + const PendingRequest& completed_req = pending_requests_.front(); + delegate_->OnResolveProxyCompleted(completed_req.reply_msg, + result, + proxy_info_.GetAnnotatedProxyList()); + + // Clear the current (completed) request. + pending_requests_.pop_front(); + proxy_service_ = NULL; + + // Start the next request. + if (!pending_requests_.empty()) + StartPendingRequest(); +} + +void ResolveProxyMsgHelper::StartPendingRequest() { + PendingRequest& req = pending_requests_.front(); + + // Verify the request wasn't started yet. + DCHECK(NULL == req.pac_req); + DCHECK(NULL == proxy_service_); + + // Start the request. + proxy_service_ = GetProxyService(); + int result = proxy_service_->ResolveProxy( + req.url, &proxy_info_, &callback_, &req.pac_req); + + // Completed synchronously. + if (result != net::ERR_IO_PENDING) + OnResolveProxyCompleted(result); +} + +net::ProxyService* ResolveProxyMsgHelper::GetProxyService() const { + // Unit-tests specify their own proxy service to use. + if (proxy_service_override_) + return proxy_service_override_; + + // Otherwise use the browser's global proxy service. + return Profile::GetDefaultRequestContext()->proxy_service(); +} + +ResolveProxyMsgHelper::~ResolveProxyMsgHelper() { + // Clear all pending requests. + if (!pending_requests_.empty()) { + PendingRequest req = pending_requests_.front(); + proxy_service_->CancelPacRequest(req.pac_req); + } + + for (PendingRequestList::iterator it = pending_requests_.begin(); + it != pending_requests_.end(); + ++it) { + delete it->reply_msg; + } + + proxy_service_ = NULL; + pending_requests_.clear(); +} diff --git a/chrome/browser/net/resolve_proxy_msg_helper.h b/chrome/browser/net/resolve_proxy_msg_helper.h new file mode 100644 index 0000000..bf4c2f8 --- /dev/null +++ b/chrome/browser/net/resolve_proxy_msg_helper.h @@ -0,0 +1,104 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NET_RESOLVE_PROXY_MSG_HELPER_ +#define CHROME_BROWSER_NET_RESOLVE_PROXY_MSG_HELPER_ + +#include <deque> +#include <string> + +#include "chrome/common/ipc_message.h" +#include "net/base/completion_callback.h" +#include "googleurl/src/gurl.h" +#include "net/proxy/proxy_service.h" + +// This class holds the common logic used to respond to the messages: +// {PluginProcessHostMsg_ResolveProxy, ViewHostMsg_ResolveProxy}. +// +// This involves kicking off a ProxyResolve request on the IO thread using +// the specified proxy service. +// +// When the request completes, it calls the delegate's OnProxyResolveCompleted() +// method, passing it the result (error code + proxy list), as well as the +// IPC::Message pointer that had been stored. +// +// When an instance of ResolveProxyMsgHelper is destroyed, it cancels any +// outstanding proxy resolve requests with the proxy service. It also deletes +// the stored IPC::Message pointers for pending requests. +// +// This object is expected to live on the IO thread. +class ResolveProxyMsgHelper { + public: + class Delegate { + public: + // Callback for when the proxy resolve request has completed. + // |reply_msg| -- The same pointer that the request was started with. + // |result| -- The network error code from ProxyService. + // |proxy_list| -- The PAC string result from ProxyService. + virtual void OnResolveProxyCompleted(IPC::Message* reply_msg, + int result, + const std::string& proxy_list) = 0; + virtual ~Delegate() {} + }; + + // Construct a ResolveProxyMsgHelper instance that notifies request + // completion to |delegate|. Note that |delegate| must be live throughout + // our lifespan. If |proxy_service| is NULL, then the current profile's + // proxy service will be used. + explicit ResolveProxyMsgHelper(Delegate* delegate, + net::ProxyService* proxy_service); + + // Resolve proxies for |url|. Completion is notified through the delegate. + // If multiple requests are started at the same time, they will run in + // FIFO order, with only 1 being outstanding at a time. + void Start(const GURL& url, IPC::Message* reply_msg); + + // Destruction cancels the current outstanding request, and clears the + // pending queue. + ~ResolveProxyMsgHelper(); + + private: + // Callback for the ProxyService (bound to |callback_|). + void OnResolveProxyCompleted(int result); + + // Start the first pending request. + void StartPendingRequest(); + + // Get the proxy service instance to use. + net::ProxyService* GetProxyService() const; + + // A PendingRequest is a resolve request that is in progress, or queued. + struct PendingRequest { + public: + PendingRequest(const GURL& url, IPC::Message* reply_msg) : + url(url), reply_msg(reply_msg), pac_req(NULL) { } + + // The URL of the request. + GURL url; + + // Data to pass back to the delegate on completion (we own it until then). + IPC::Message* reply_msg; + + // Handle for cancelling the current request if it has started (else NULL). + net::ProxyService::PacRequest* pac_req; + }; + + // Members for the current outstanding proxy request. + net::ProxyService* proxy_service_; + net::CompletionCallbackImpl<ResolveProxyMsgHelper> callback_; + net::ProxyInfo proxy_info_; + + // FIFO queue of pending requests. The first entry is always the current one. + typedef std::deque<PendingRequest> PendingRequestList; + PendingRequestList pending_requests_; + + Delegate* delegate_; + + // Specified by unit-tests, to use this proxy service in place of the + // global one. + net::ProxyService* proxy_service_override_; +}; + +#endif // CHROME_BROWSER_NET_RESOLVE_PROXY_MSG_HELPER_ + diff --git a/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc b/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc new file mode 100644 index 0000000..dd70713 --- /dev/null +++ b/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc @@ -0,0 +1,349 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/net/resolve_proxy_msg_helper.h" + +#include "base/waitable_event.h" +#include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" + +// This ProxyConfigService always returns "http://pac" as the PAC url to use. +class MockProxyConfigService: public net::ProxyConfigService { + public: + virtual int GetProxyConfig(net::ProxyConfig* results) { + results->pac_url = GURL("http://pac"); + return net::OK; + } +}; + +// This PAC resolver always returns the hostname of the query URL as the +// proxy to use. The Block() method will make GetProxyForURL() hang until +// Unblock() is called. +class MockProxyResolver : public net::ProxyResolver { + public: + explicit MockProxyResolver() : event_(false, false), is_blocked_(false) { + } + + virtual int GetProxyForURL(const GURL& query_url, + const GURL& /*pac_url*/, + net::ProxyInfo* results) { + if (is_blocked_) + event_.Wait(); + results->UseNamedProxy(query_url.host()); + return net::OK; + } + + void Block() { + is_blocked_ = true; + event_.Reset(); + } + + void Unblock() { + is_blocked_ = false; + event_.Signal(); + } + + private: + base::WaitableEvent event_; + bool is_blocked_; +}; + +// This struct holds the values that were passed to +// Delegate::OnResolveProxyCompleted(). The caller should use WaitUntilDone() +// to block until the result has been populated. +struct ResultFuture { + public: + ResultFuture() + : reply_msg(NULL), + error_code(0), + started_(false, false), + completed_(false, false) { + } + + // Wait until the request has completed. In other words we have invoked: + // ResolveProxyMsgHelper::Delegate::OnResolveProxyCompleted. + void WaitUntilDone() { + completed_.Wait(); + } + + // Wait until the request has been sent to ResolveProxyMsgHelper. + void WaitUntilStarted() { + started_.Wait(); + } + + bool TimedWaitUntilDone(const base::TimeDelta& max_time) { + return completed_.TimedWait(max_time); + } + + // These fields are only valid after returning from WaitUntilDone(). + IPC::Message* reply_msg; + int error_code; + std::string proxy_list; + + private: + friend class AsyncRequestRunner; + base::WaitableEvent started_; + base::WaitableEvent completed_; +}; + +// This class lives on the io thread. It starts async requests using the +// class under test (ResolveProxyMsgHelper), and signals the result future on +// completion. +class AsyncRequestRunner : public ResolveProxyMsgHelper::Delegate { + public: + AsyncRequestRunner(net::ProxyService* proxy_service) { + resolve_proxy_msg_helper_.reset( + new ResolveProxyMsgHelper(this, proxy_service)); + } + + void Start(ResultFuture* future, const GURL& url, IPC::Message* reply_msg) { + futures_.push_back(future); + resolve_proxy_msg_helper_->Start(url, reply_msg); + + // Notify of request start. + future->started_.Signal(); + } + + virtual void OnResolveProxyCompleted(IPC::Message* reply_msg, + int error_code, + const std::string& proxy_list) { + // Update the result future for this request (top of queue), and signal it. + ResultFuture* future = futures_.front(); + futures_.pop_front(); + + future->reply_msg = reply_msg; + future->error_code = error_code; + future->proxy_list = proxy_list; + + // Notify of request completion. + future->completed_.Signal(); + } + + private: + std::deque<ResultFuture*> futures_; + scoped_ptr<ResolveProxyMsgHelper> resolve_proxy_msg_helper_; +}; + +// Helper class to start async requests on an io thread, and return a +// result future. The caller then uses ResultFuture::WaitUntilDone() to +// get at the results. It "bridges" the originating thread with the helper +// io thread. +class RunnerBridge { + public: + RunnerBridge() : io_thread_("io_thread"), done_(true, false) { + // Start an io thread where we will run the async requests. + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + io_thread_.StartWithOptions(options); + + // Construct the state that lives on io thread. + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RunnerBridge::DoConstruct)); + done_.Wait(); + } + + // Start an async request on the io thread. + ResultFuture* Start(const GURL& url, IPC::Message* reply_msg) { + ResultFuture* future = new ResultFuture(); + + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + async_runner_, &AsyncRequestRunner::Start, future, url, reply_msg)); + + return future; + } + + void DestroyAsyncRunner() { + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RunnerBridge::DoDestroyAsyncRunner)); + done_.Wait(); + } + + ~RunnerBridge() { + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RunnerBridge::DoDestroy)); + done_.Wait(); + } + + MockProxyResolver* proxy_resolver() { + return proxy_resolver_; + } + + // Called from io thread. + void DoConstruct() { + proxy_resolver_ = new MockProxyResolver(); + proxy_service_ = new net::ProxyService(new MockProxyConfigService(), + proxy_resolver_); + async_runner_ = new AsyncRequestRunner(proxy_service_); + done_.Signal(); + } + + // Called from io thread. + void DoDestroy() { + delete async_runner_; + delete proxy_service_; + done_.Signal(); + } + + // Called from io thread. + void DoDestroyAsyncRunner() { + delete async_runner_; + async_runner_ = NULL; + done_.Signal(); + } + + private: + base::Thread io_thread_; + base::WaitableEvent done_; + + net::ProxyService* proxy_service_; + MockProxyResolver* proxy_resolver_; // Owned by proxy_service_. + + AsyncRequestRunner* async_runner_; +}; + +// Avoid the need to have an AddRef / Release +template<> +void RunnableMethodTraits<RunnerBridge>::RetainCallee(RunnerBridge*) {} +template<> +void RunnableMethodTraits<RunnerBridge>::ReleaseCallee(RunnerBridge*) {} + +template<> +void RunnableMethodTraits<AsyncRequestRunner>::RetainCallee(AsyncRequestRunner*) {} +template<> +void RunnableMethodTraits<AsyncRequestRunner>::ReleaseCallee(AsyncRequestRunner*) {} + + +// Issue three sequential requests -- each should succeed. +TEST(ResolveProxyMsgHelperTest, Sequential) { + RunnerBridge runner; + + GURL url1("http://www.google1.com/"); + GURL url2("http://www.google2.com/"); + GURL url3("http://www.google3.com/"); + + scoped_ptr<IPC::Message> msg1(new IPC::Message()); + scoped_ptr<IPC::Message> msg2(new IPC::Message()); + scoped_ptr<IPC::Message> msg3(new IPC::Message()); + + // Execute each request sequentially (so there are never 2 requests + // outstanding at the same time). + + scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get())); + result1->WaitUntilDone(); + + scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get())); + result2->WaitUntilDone(); + + scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get())); + result3->WaitUntilDone(); + + // Check that each request gave the expected result. + + EXPECT_EQ(msg1.get(), result1->reply_msg); + EXPECT_EQ(net::OK, result1->error_code); + EXPECT_EQ("PROXY www.google1.com", result1->proxy_list); + + EXPECT_EQ(msg2.get(), result2->reply_msg); + EXPECT_EQ(net::OK, result2->error_code); + EXPECT_EQ("PROXY www.google2.com", result2->proxy_list); + + EXPECT_EQ(msg3.get(), result3->reply_msg); + EXPECT_EQ(net::OK, result3->error_code); + EXPECT_EQ("PROXY www.google3.com", result3->proxy_list); +} + +// Issue a request while one is already in progress -- should be queued. +TEST(ResolveProxyMsgHelperTest, QueueRequests) { + RunnerBridge runner; + + GURL url1("http://www.google1.com/"); + GURL url2("http://www.google2.com/"); + GURL url3("http://www.google3.com/"); + + scoped_ptr<IPC::Message> msg1(new IPC::Message()); + scoped_ptr<IPC::Message> msg2(new IPC::Message()); + scoped_ptr<IPC::Message> msg3(new IPC::Message()); + + // Make the proxy resolver hang on the next request. + runner.proxy_resolver()->Block(); + + // Start three requests. Since the proxy resolver is hung, the second two + // will be pending. + + scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get())); + scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get())); + scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get())); + + // Wait for the final request to have been scheduled. Otherwise we may rush + // to calling Unblock() without actually having blocked anything. + result3->WaitUntilStarted(); + + // Unblock the proxy service so requests 1-3 can complete. + runner.proxy_resolver()->Unblock(); + + // Wait for all the requests to finish (they run in FIFO order). + result3->WaitUntilDone(); + + // Check that each call invoked the callback with the right parameters. + + EXPECT_EQ(msg1.get(), result1->reply_msg); + EXPECT_EQ(net::OK, result1->error_code); + EXPECT_EQ("PROXY www.google1.com", result1->proxy_list); + + EXPECT_EQ(msg2.get(), result2->reply_msg); + EXPECT_EQ(net::OK, result2->error_code); + EXPECT_EQ("PROXY www.google2.com", result2->proxy_list); + + EXPECT_EQ(msg3.get(), result3->reply_msg); + EXPECT_EQ(net::OK, result3->error_code); + EXPECT_EQ("PROXY www.google3.com", result3->proxy_list); +} + +// Delete the helper while a request is in progress, and others are pending. +TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) { + RunnerBridge runner; + + GURL url1("http://www.google1.com/"); + GURL url2("http://www.google2.com/"); + GURL url3("http://www.google3.com/"); + + // NOTE: these are not scoped ptr, since they will be deleted by the + // request's cancellation. + IPC::Message* msg1 = new IPC::Message(); + IPC::Message* msg2 = new IPC::Message(); + IPC::Message* msg3 = new IPC::Message(); + + // Make the next request block. + runner.proxy_resolver()->Block(); + + // Start three requests; since the first one blocked, the other two should + // be pending. + + scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1)); + scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2)); + scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3)); + + result3->WaitUntilStarted(); + + // Delete the underlying ResolveProxyMsgHelper -- this should cancel all + // the requests which are outstanding. + runner.DestroyAsyncRunner(); + + // Unblocking the proxy resolver means the three requests can complete -- + // however they should not try to notify the delegate since we have already + // deleted the helper. + runner.proxy_resolver()->Unblock(); + + // Check that none of the requests were sent to the delegate. + EXPECT_FALSE( + result1->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); + EXPECT_FALSE( + result2->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); + EXPECT_FALSE( + result3->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); + + // It should also be the case that msg1, msg2, msg3 were deleted by the + // cancellation. (Else will show up as a leak in Purify). +} + diff --git a/chrome/browser/plugin_process_host.cc b/chrome/browser/plugin_process_host.cc index 0229d95..f071a7a 100644 --- a/chrome/browser/plugin_process_host.cc +++ b/chrome/browser/plugin_process_host.cc @@ -37,7 +37,6 @@ #include "chrome/common/win_util.h" #include "net/base/cookie_monster.h" #include "net/base/io_buffer.h" -#include "net/proxy/proxy_service.h" #include "net/url_request/url_request.h" #include "sandbox/src/sandbox.h" #include "webkit/glue/plugins/plugin_constants_win.h" @@ -300,57 +299,6 @@ void PluginDownloadUrlHelper::DownloadCompletedHelper(bool success) { delete this; } -// The following class is a helper to handle ProxyResolve IPC requests. -// It is responsible for initiating an asynchronous proxy resolve request, -// and will send out the IPC response on completion then delete itself. -// Should the PluginProcessHost be destroyed while a proxy resolve request -// is in progress, the request will not be canceled. However once it completes -// it will see that it has been revoked and delete itself. -// TODO(eroman): This could leak if ProxyService is deleted while request is -// outstanding. -class PluginResolveProxyHelper : RevocableStore::Revocable { - public: - // Create a helper that writes its response through |plugin_host|. - PluginResolveProxyHelper(PluginProcessHost* plugin_host) - : RevocableStore::Revocable(&plugin_host->revocable_store_), - plugin_host_(plugin_host), - reply_msg_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(callback_( - this, &PluginResolveProxyHelper::OnProxyResolveCompleted)) { - } - - // Completion callback for ProxyService. - void OnProxyResolveCompleted(int result) { - if (!revoked()) { - PluginProcessHostMsg_ResolveProxy::WriteReplyParams( - reply_msg_, result, proxy_info_.GetAnnotatedProxyList()); - plugin_host_->Send(reply_msg_); - } - - delete this; - }; - - // Resolve the proxy for |url| using |proxy_service|. Write the response - // to |reply_msg|. - void Start(net::ProxyService* proxy_service, - const GURL& url, - IPC::Message* reply_msg) { - reply_msg_ = reply_msg; - int rv = proxy_service->ResolveProxy( - url, &proxy_info_, &callback_, NULL); - if (rv != net::ERR_IO_PENDING) - OnProxyResolveCompleted(rv); - } - - private: - // |plugin_host_| is only valid if !this->revoked(). - PluginProcessHost* plugin_host_; - IPC::Message* reply_msg_; - net::CompletionCallbackImpl<PluginResolveProxyHelper> callback_; - net::ProxyInfo proxy_info_; -}; - - // Sends the reply to the create window message on the IO thread. class SendReplyTask : public Task { public: @@ -435,6 +383,7 @@ PluginProcessHost::PluginProcessHost(PluginService* plugin_service) : process_(NULL), opening_channel_(false), resource_dispatcher_host_(plugin_service->resource_dispatcher_host()), + ALLOW_THIS_IN_INITIALIZER_LIST(resolve_proxy_msg_helper_(this, NULL)), plugin_service_(plugin_service) { DCHECK(resource_dispatcher_host_); } @@ -814,13 +763,15 @@ void PluginProcessHost::OnGetCookies(uint32 request_context, void PluginProcessHost::OnResolveProxy(const GURL& url, IPC::Message* reply_msg) { - // Use the default profile's proxy service. - net::ProxyService* proxy_service = - Profile::GetDefaultRequestContext()->proxy_service(); + resolve_proxy_msg_helper_.Start(url, reply_msg); +} - // Kick off a proxy resolve request; writes the response to |reply_msg| - // on completion. The helper's storage will be deleted on completion. - (new PluginResolveProxyHelper(this))->Start(proxy_service, url, reply_msg); +void PluginProcessHost::OnResolveProxyCompleted(IPC::Message* reply_msg, + int result, + const std::string& proxy_list) { + PluginProcessHostMsg_ResolveProxy::WriteReplyParams( + reply_msg, result, proxy_list); + Send(reply_msg); } void PluginProcessHost::ReplyToRenderer( diff --git a/chrome/browser/plugin_process_host.h b/chrome/browser/plugin_process_host.h index a4e390c..21adb90 100644 --- a/chrome/browser/plugin_process_host.h +++ b/chrome/browser/plugin_process_host.h @@ -15,6 +15,7 @@ #include "base/task.h" #include "chrome/browser/resource_message_filter.h" #include "chrome/common/ipc_channel_proxy.h" +#include "chrome/browser/net/resolve_proxy_msg_helper.h" #include "chrome/browser/resource_message_filter.h" class PluginService; @@ -34,7 +35,8 @@ class GURL; // the renderer and plugin processes. class PluginProcessHost : public IPC::Channel::Listener, public IPC::Message::Sender, - public base::ObjectWatcher::Delegate { + public base::ObjectWatcher::Delegate, + public ResolveProxyMsgHelper::Delegate { public: PluginProcessHost(PluginService* plugin_service); ~PluginProcessHost(); @@ -58,6 +60,11 @@ class PluginProcessHost : public IPC::Channel::Listener, virtual void OnChannelConnected(int32 peer_pid); virtual void OnChannelError(); + // ResolveProxyMsgHelper::Delegate implementation: + virtual void OnResolveProxyCompleted(IPC::Message* reply_msg, + int result, + const std::string& proxy_list); + // Getter to the process, may return NULL if there is no connection. HANDLE process() { return process_.handle(); } @@ -157,10 +164,9 @@ class PluginProcessHost : public IPC::Channel::Listener, ResourceDispatcherHost* resource_dispatcher_host_; - // This RevocableStore prevents ResolveProxy completion callbacks from - // accessing a deleted PluginProcessHost (since we do not cancel the - // in-progress resolve requests during destruction). - RevocableStore revocable_store_; + // Helper class for handling PluginProcessHost_ResolveProxy messages (manages + // the requests to the proxy service). + ResolveProxyMsgHelper resolve_proxy_msg_helper_; DISALLOW_EVIL_CONSTRUCTORS(PluginProcessHost); }; diff --git a/chrome/browser/resource_message_filter.cc b/chrome/browser/resource_message_filter.cc index dd0dd5a..d1d9370 100644 --- a/chrome/browser/resource_message_filter.cc +++ b/chrome/browser/resource_message_filter.cc @@ -100,7 +100,8 @@ ResourceMessageFilter::ResourceMessageFilter( request_context_(profile->GetRequestContext()), profile_(profile), render_widget_helper_(render_widget_helper), - spellchecker_(spellchecker) { + spellchecker_(spellchecker), + ALLOW_THIS_IN_INITIALIZER_LIST(resolve_proxy_msg_helper_(this, NULL)) { DCHECK(request_context_.get()); DCHECK(request_context_->cookie_store()); @@ -207,6 +208,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { OnGetCPBrowsingContext) IPC_MESSAGE_HANDLER(ViewHostMsg_DuplicateSection, OnDuplicateSection) IPC_MESSAGE_HANDLER(ViewHostMsg_ResourceTypeStats, OnResourceTypeStats) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ResolveProxy, OnResolveProxy) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDefaultPrintSettings, OnGetDefaultPrintSettings) #if defined(OS_WIN) @@ -572,6 +574,19 @@ void ResourceMessageFilter::OnResourceTypeStats( static_cast<int>(stats.fonts.size / 1024)); } +void ResourceMessageFilter::OnResolveProxy(const GURL& url, + IPC::Message* reply_msg) { + resolve_proxy_msg_helper_.Start(url, reply_msg); +} + +void ResourceMessageFilter::OnResolveProxyCompleted( + IPC::Message* reply_msg, + int result, + const std::string& proxy_list) { + ViewHostMsg_ResolveProxy::WriteReplyParams(reply_msg, result, proxy_list); + Send(reply_msg); +} + void ResourceMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { scoped_refptr<printing::PrinterQuery> printer_query; print_job_manager_->PopPrinterQuery(0, &printer_query); diff --git a/chrome/browser/resource_message_filter.h b/chrome/browser/resource_message_filter.h index 026c232..48b4fb8 100644 --- a/chrome/browser/resource_message_filter.h +++ b/chrome/browser/resource_message_filter.h @@ -11,6 +11,7 @@ #include "base/gfx/native_widget_types.h" #include "base/ref_counted.h" #include "build/build_config.h" +#include "chrome/browser/net/resolve_proxy_msg_helper.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/common/ipc_channel_proxy.h" #include "chrome/common/notification_service.h" @@ -43,7 +44,8 @@ struct ScreenInfo; class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, public ResourceDispatcherHost::Receiver, - public NotificationObserver { + public NotificationObserver, + public ResolveProxyMsgHelper::Delegate { public: // Create the filter. // Note: because the lifecycle of the ResourceMessageFilter is not @@ -157,6 +159,13 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, base::SharedMemoryHandle* browser_handle); void OnResourceTypeStats(const CacheManager::ResourceTypeStats& stats); + void OnResolveProxy(const GURL& url, IPC::Message* reply_msg); + + // ResolveProxyMsgHelper::Delegate implementation: + virtual void OnResolveProxyCompleted(IPC::Message* reply_msg, + int result, + const std::string& proxy_list); + // A javascript code requested to print the current page. This is done in two // steps and this is the first step. Get the print setting right here // synchronously. It will hang the I/O completely. @@ -204,6 +213,10 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, // Our spellchecker object. scoped_refptr<SpellChecker> spellchecker_; + // Helper class for handling PluginProcessHost_ResolveProxy messages (manages + // the requests to the proxy service). + ResolveProxyMsgHelper resolve_proxy_msg_helper_; + // Process handle of the renderer process. base::ProcessHandle render_handle_; |