| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/proxy/sync_host_resolver_bridge.h" | 5 #include "net/proxy/sync_host_resolver_bridge.h" |
| 6 | 6 |
| 7 #include "base/thread.h" | 7 #include "base/thread.h" |
| 8 #include "base/waitable_event.h" | 8 #include "base/waitable_event.h" |
| 9 #include "net/base/address_list.h" | 9 #include "net/base/address_list.h" |
| 10 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
| 11 #include "net/base/net_log.h" | 11 #include "net/base/net_log.h" |
| 12 #include "net/proxy/multi_threaded_proxy_resolver.h" |
| 12 #include "net/base/test_completion_callback.h" | 13 #include "net/base/test_completion_callback.h" |
| 13 #include "net/proxy/proxy_info.h" | 14 #include "net/proxy/proxy_info.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 15 | 16 |
| 17 // TODO(eroman): This test should be moved into |
| 18 // multi_threaded_proxy_resolver_unittest.cc. |
| 19 |
| 16 namespace net { | 20 namespace net { |
| 17 | 21 |
| 18 namespace { | 22 namespace { |
| 19 | 23 |
| 20 // This implementation of HostResolver allows blocking until a resolve request | 24 // This implementation of HostResolver allows blocking until a resolve request |
| 21 // has been received. The resolve requests it receives will never be completed. | 25 // has been received. The resolve requests it receives will never be completed. |
| 22 class BlockableHostResolver : public HostResolver { | 26 class BlockableHostResolver : public HostResolver { |
| 23 public: | 27 public: |
| 24 BlockableHostResolver() | 28 BlockableHostResolver() |
| 25 : event_(true, false), | 29 : event_(true, false), |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 private: | 72 private: |
| 69 // Event to notify when a resolve request was received. | 73 // Event to notify when a resolve request was received. |
| 70 base::WaitableEvent event_; | 74 base::WaitableEvent event_; |
| 71 bool was_request_cancelled_; | 75 bool was_request_cancelled_; |
| 72 }; | 76 }; |
| 73 | 77 |
| 74 // This implementation of ProxyResolver simply does a synchronous resolve | 78 // This implementation of ProxyResolver simply does a synchronous resolve |
| 75 // on |host_resolver| in response to GetProxyForURL(). | 79 // on |host_resolver| in response to GetProxyForURL(). |
| 76 class SyncProxyResolver : public ProxyResolver { | 80 class SyncProxyResolver : public ProxyResolver { |
| 77 public: | 81 public: |
| 78 explicit SyncProxyResolver(HostResolver* host_resolver) | 82 explicit SyncProxyResolver(SyncHostResolverBridge* host_resolver) |
| 79 : ProxyResolver(false), host_resolver_(host_resolver) {} | 83 : ProxyResolver(false), host_resolver_(host_resolver) {} |
| 80 | 84 |
| 81 virtual int GetProxyForURL(const GURL& url, | 85 virtual int GetProxyForURL(const GURL& url, |
| 82 ProxyInfo* results, | 86 ProxyInfo* results, |
| 83 CompletionCallback* callback, | 87 CompletionCallback* callback, |
| 84 RequestHandle* request, | 88 RequestHandle* request, |
| 85 const BoundNetLog& net_log) { | 89 const BoundNetLog& net_log) { |
| 86 EXPECT_FALSE(callback); | 90 EXPECT_FALSE(callback); |
| 87 EXPECT_FALSE(request); | 91 EXPECT_FALSE(request); |
| 88 | 92 |
| 89 // Do a synchronous host resolve. | 93 // Do a synchronous host resolve. |
| 90 HostResolver::RequestInfo info(url.host(), 80); | 94 HostResolver::RequestInfo info(url.host(), 80); |
| 91 AddressList addresses; | 95 AddressList addresses; |
| 92 int rv = | 96 int rv = |
| 93 host_resolver_->Resolve(info, &addresses, NULL, NULL, BoundNetLog()); | 97 host_resolver_->Resolve(info, &addresses, NULL, NULL, BoundNetLog()); |
| 94 | 98 |
| 95 EXPECT_EQ(ERR_ABORTED, rv); | 99 EXPECT_EQ(ERR_ABORTED, rv); |
| 96 | 100 |
| 97 return rv; | 101 return rv; |
| 98 } | 102 } |
| 99 | 103 |
| 100 virtual void CancelRequest(RequestHandle request) { | 104 virtual void CancelRequest(RequestHandle request) { |
| 101 NOTREACHED(); | 105 NOTREACHED(); |
| 102 } | 106 } |
| 103 | 107 |
| 108 virtual void Shutdown() { |
| 109 host_resolver_->Shutdown(); |
| 110 } |
| 111 |
| 104 private: | 112 private: |
| 105 virtual int SetPacScript(const GURL& pac_url, | 113 virtual int SetPacScript(const GURL& pac_url, |
| 106 const string16& pac_script, | 114 const string16& pac_script, |
| 107 CompletionCallback* callback) { | 115 CompletionCallback* callback) { |
| 108 NOTREACHED(); | |
| 109 return OK; | 116 return OK; |
| 110 } | 117 } |
| 111 | 118 |
| 112 scoped_refptr<HostResolver> host_resolver_; | 119 scoped_refptr<SyncHostResolverBridge> host_resolver_; |
| 120 }; |
| 121 |
| 122 class SyncProxyResolverFactory : public ProxyResolverFactory { |
| 123 public: |
| 124 explicit SyncProxyResolverFactory(SyncHostResolverBridge* sync_host_resolver) |
| 125 : ProxyResolverFactory(false), |
| 126 sync_host_resolver_(sync_host_resolver) { |
| 127 } |
| 128 |
| 129 virtual ProxyResolver* CreateProxyResolver() { |
| 130 return new SyncProxyResolver(sync_host_resolver_); |
| 131 } |
| 132 |
| 133 private: |
| 134 scoped_refptr<SyncHostResolverBridge> sync_host_resolver_; |
| 113 }; | 135 }; |
| 114 | 136 |
| 115 // This helper thread is used to create the circumstances for the deadlock. | 137 // This helper thread is used to create the circumstances for the deadlock. |
| 116 // It is analagous to the "IO thread" which would be main thread running the | 138 // It is analagous to the "IO thread" which would be main thread running the |
| 117 // network stack. | 139 // network stack. |
| 118 class IOThread : public base::Thread { | 140 class IOThread : public base::Thread { |
| 119 public: | 141 public: |
| 120 IOThread() : base::Thread("IO-thread") {} | 142 IOThread() : base::Thread("IO-thread") {} |
| 121 | 143 |
| 122 virtual ~IOThread() { | 144 virtual ~IOThread() { |
| 123 Stop(); | 145 Stop(); |
| 124 } | 146 } |
| 125 | 147 |
| 126 const scoped_refptr<BlockableHostResolver>& async_resolver() { | 148 const scoped_refptr<BlockableHostResolver>& async_resolver() { |
| 127 return async_resolver_; | 149 return async_resolver_; |
| 128 } | 150 } |
| 129 | 151 |
| 130 protected: | 152 protected: |
| 131 virtual void Init() { | 153 virtual void Init() { |
| 132 async_resolver_ = new BlockableHostResolver(); | 154 async_resolver_ = new BlockableHostResolver(); |
| 133 | 155 |
| 134 // Create a synchronous host resolver that operates the async host | 156 // Create a synchronous host resolver that operates the async host |
| 135 // resolver on THIS thread. | 157 // resolver on THIS thread. |
| 136 scoped_refptr<SyncHostResolverBridge> sync_resolver = | 158 scoped_refptr<SyncHostResolverBridge> sync_resolver = |
| 137 new SyncHostResolverBridge(async_resolver_, message_loop()); | 159 new SyncHostResolverBridge(async_resolver_, message_loop()); |
| 138 | 160 |
| 139 proxy_resolver_.reset( | 161 proxy_resolver_.reset( |
| 140 new SingleThreadedProxyResolverUsingBridgedHostResolver( | 162 new MultiThreadedProxyResolver( |
| 141 new SyncProxyResolver(sync_resolver), | 163 new SyncProxyResolverFactory(sync_resolver), |
| 142 sync_resolver)); | 164 1u)); |
| 165 |
| 166 // Initialize the resolver. |
| 167 TestCompletionCallback callback; |
| 168 proxy_resolver_->SetPacScriptByUrl(GURL(), &callback); |
| 169 EXPECT_EQ(OK, callback.WaitForResult()); |
| 143 | 170 |
| 144 // Start an asynchronous request to the proxy resolver | 171 // Start an asynchronous request to the proxy resolver |
| 145 // (note that it will never complete). | 172 // (note that it will never complete). |
| 146 proxy_resolver_->GetProxyForURL(GURL("http://test/"), &results_, | 173 proxy_resolver_->GetProxyForURL(GURL("http://test/"), &results_, |
| 147 &callback_, &request_, BoundNetLog()); | 174 &callback_, &request_, BoundNetLog()); |
| 148 } | 175 } |
| 149 | 176 |
| 150 virtual void CleanUp() { | 177 virtual void CleanUp() { |
| 151 // Cancel the outstanding request (note however that this will not | 178 // Cancel the outstanding request (note however that this will not |
| 152 // unblock the PAC thread though). | 179 // unblock the PAC thread though). |
| 153 proxy_resolver_->CancelRequest(request_); | 180 proxy_resolver_->CancelRequest(request_); |
| 154 | 181 |
| 155 // Delete the single threaded proxy resolver. | 182 // Delete the single threaded proxy resolver. |
| 156 proxy_resolver_.reset(); | 183 proxy_resolver_.reset(); |
| 157 | 184 |
| 185 // (There may have been a completion posted back to origin thread, avoid |
| 186 // leaking it by running). |
| 187 MessageLoop::current()->RunAllPending(); |
| 188 |
| 158 // During the teardown sequence of the single threaded proxy resolver, | 189 // During the teardown sequence of the single threaded proxy resolver, |
| 159 // the outstanding host resolve should have been cancelled. | 190 // the outstanding host resolve should have been cancelled. |
| 160 EXPECT_TRUE(async_resolver_->was_request_cancelled()); | 191 EXPECT_TRUE(async_resolver_->was_request_cancelled()); |
| 161 | 192 |
| 162 async_resolver_ = NULL; | 193 async_resolver_ = NULL; |
| 163 } | 194 } |
| 164 | 195 |
| 165 private: | 196 private: |
| 166 // This (async) host resolver will outlive the thread that is operating it | 197 // This (async) host resolver will outlive the thread that is operating it |
| 167 // synchronously. | 198 // synchronously. |
| 168 scoped_refptr<BlockableHostResolver> async_resolver_; | 199 scoped_refptr<BlockableHostResolver> async_resolver_; |
| 169 | 200 |
| 170 scoped_ptr<ProxyResolver> proxy_resolver_; | 201 scoped_ptr<ProxyResolver> proxy_resolver_; |
| 171 | 202 |
| 172 // Data for the outstanding request to the single threaded proxy resolver. | 203 // Data for the outstanding request to the single threaded proxy resolver. |
| 173 TestCompletionCallback callback_; | 204 TestCompletionCallback callback_; |
| 174 ProxyInfo results_; | 205 ProxyInfo results_; |
| 175 ProxyResolver::RequestHandle request_; | 206 ProxyResolver::RequestHandle request_; |
| 176 }; | 207 }; |
| 177 | 208 |
| 178 // Test that a deadlock does not happen during shutdown when a host resolve | 209 // Test that a deadlock does not happen during shutdown when a host resolve |
| 179 // is outstanding on the SyncHostResolverBridge. | 210 // is outstanding on the SyncHostResolverBridge. |
| 180 // This is a regression test for http://crbug.com/41244. | 211 // This is a regression test for http://crbug.com/41244. |
| 181 TEST(SingleThreadedProxyResolverWithBridgedHostResolverTest, ShutdownDeadlock) { | 212 TEST(MultiThreadedProxyResolverTest, ShutdownIsCalledBeforeThreadJoin) { |
| 182 IOThread io_thread; | 213 IOThread io_thread; |
| 183 base::Thread::Options options; | 214 base::Thread::Options options; |
| 184 options.message_loop_type = MessageLoop::TYPE_IO; | 215 options.message_loop_type = MessageLoop::TYPE_IO; |
| 185 ASSERT_TRUE(io_thread.StartWithOptions(options)); | 216 ASSERT_TRUE(io_thread.StartWithOptions(options)); |
| 186 | 217 |
| 187 io_thread.async_resolver()->WaitUntilRequestIsReceived(); | 218 io_thread.async_resolver()->WaitUntilRequestIsReceived(); |
| 188 | 219 |
| 189 // Now upon exitting this scope, the IOThread is destroyed -- this will | 220 // Now upon exitting this scope, the IOThread is destroyed -- this will |
| 190 // stop the IOThread, which will in turn delete the | 221 // stop the IOThread, which will in turn delete the |
| 191 // SingleThreadedProxyResolver, which in turn will stop its internal | 222 // SingleThreadedProxyResolver, which in turn will stop its internal |
| 192 // PAC thread (which is currently blocked waiting on the host resolve which | 223 // PAC thread (which is currently blocked waiting on the host resolve which |
| 193 // is running on IOThread). The IOThread::Cleanup() will verify that after | 224 // is running on IOThread). The IOThread::Cleanup() will verify that after |
| 194 // the PAC thread is stopped, it cancels the request on the HostResolver. | 225 // the PAC thread is stopped, it cancels the request on the HostResolver. |
| 195 } | 226 } |
| 196 | 227 |
| 197 } // namespace | 228 } // namespace |
| 198 | 229 |
| 199 } // namespace net | 230 } // namespace net |
| OLD | NEW |