1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/proxy/sync_host_resolver_bridge.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/waitable_event.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/address_list.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_errors.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_log.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/proxy/multi_threaded_proxy_resolver.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/test_completion_callback.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/proxy/proxy_info.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/gtest/include/gtest/gtest.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(eroman): This test should be moved into
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//               multi_threaded_proxy_resolver_unittest.cc.
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net {
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This implementation of HostResolver allows blocking until a resolve request
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// has been received. The resolve requests it receives will never be completed.
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BlockableHostResolver : public HostResolver {
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BlockableHostResolver()
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : event_(true, false),
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        was_request_cancelled_(false) {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual int Resolve(const RequestInfo& info,
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      AddressList* addresses,
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      CompletionCallback* callback,
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      RequestHandle* out_req,
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      const BoundNetLog& net_log) {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(callback);
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(out_req);
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *out_req = reinterpret_cast<RequestHandle*>(1);  // Magic value.
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Indicate to the caller that a request was received.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    event_.Signal();
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We return ERR_IO_PENDING, as this request will NEVER be completed.
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Expectation is for the caller to later cancel the request.
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_IO_PENDING;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void CancelRequest(RequestHandle req) {
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req);
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    was_request_cancelled_ = true;
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void AddObserver(Observer* observer) {
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void RemoveObserver(Observer* observer) {
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Waits until Resolve() has been called.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void WaitUntilRequestIsReceived() {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    event_.Wait();
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool was_request_cancelled() const {
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return was_request_cancelled_;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Event to notify when a resolve request was received.
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::WaitableEvent event_;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool was_request_cancelled_;
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This implementation of ProxyResolver simply does a synchronous resolve
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// on |host_resolver| in response to GetProxyForURL().
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SyncProxyResolver : public ProxyResolver {
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit SyncProxyResolver(SyncHostResolverBridge* host_resolver)
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : ProxyResolver(false), host_resolver_(host_resolver) {}
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual int GetProxyForURL(const GURL& url,
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             ProxyInfo* results,
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             CompletionCallback* callback,
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             RequestHandle* request,
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const BoundNetLog& net_log) {
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_FALSE(callback);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_FALSE(request);
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Do a synchronous host resolve.
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    HostResolver::RequestInfo info(HostPortPair::FromURL(url));
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddressList addresses;
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int rv =
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        host_resolver_->Resolve(info, &addresses, NULL, NULL, BoundNetLog());
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_EQ(ERR_ABORTED, rv);
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return rv;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void CancelRequest(RequestHandle request) {
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Shutdown() {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    host_resolver_->Shutdown();
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  virtual void CancelSetPacScript() {
11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    NOTREACHED();
11421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual int SetPacScript(
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const scoped_refptr<ProxyResolverScriptData>& script_data,
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CompletionCallback* callback) {
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SyncHostResolverBridge* const host_resolver_;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SyncProxyResolverFactory : public ProxyResolverFactory {
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Takes ownership of |sync_host_resolver|.
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit SyncProxyResolverFactory(SyncHostResolverBridge* sync_host_resolver)
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : ProxyResolverFactory(false),
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        sync_host_resolver_(sync_host_resolver) {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual ProxyResolver* CreateProxyResolver() {
135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return new SyncProxyResolver(sync_host_resolver_.get());
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const scoped_ptr<SyncHostResolverBridge> sync_host_resolver_;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This helper thread is used to create the circumstances for the deadlock.
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// It is analagous to the "IO thread" which would be main thread running the
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// network stack.
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass IOThread : public base::Thread {
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  IOThread() : base::Thread("IO-thread") {}
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual ~IOThread() {
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Stop();
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BlockableHostResolver* async_resolver() {
154731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return async_resolver_.get();
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected:
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Init() {
159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    async_resolver_.reset(new BlockableHostResolver());
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Create a synchronous host resolver that operates the async host
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // resolver on THIS thread.
163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    SyncHostResolverBridge* sync_resolver =
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        new SyncHostResolverBridge(async_resolver_.get(), message_loop());
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    proxy_resolver_.reset(
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new MultiThreadedProxyResolver(
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            new SyncProxyResolverFactory(sync_resolver),
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            1u));
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Initialize the resolver.
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TestCompletionCallback callback;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    proxy_resolver_->SetPacScript(ProxyResolverScriptData::FromURL(GURL()),
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  &callback);
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_EQ(OK, callback.WaitForResult());
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Start an asynchronous request to the proxy resolver
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (note that it will never complete).
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    proxy_resolver_->GetProxyForURL(GURL("http://test/"), &results_,
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    &callback_, &request_, BoundNetLog());
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void CleanUp() {
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Cancel the outstanding request (note however that this will not
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // unblock the PAC thread though).
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    proxy_resolver_->CancelRequest(request_);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delete the single threaded proxy resolver.
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    proxy_resolver_.reset();
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (There may have been a completion posted back to origin thread, avoid
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // leaking it by running).
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->RunAllPending();
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // During the teardown sequence of the single threaded proxy resolver,
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the outstanding host resolve should have been cancelled.
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(async_resolver_->was_request_cancelled());
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This (async) host resolver will outlive the thread that is operating it
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // synchronously.
203731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  scoped_ptr<BlockableHostResolver> async_resolver_;
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<ProxyResolver> proxy_resolver_;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Data for the outstanding request to the single threaded proxy resolver.
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TestCompletionCallback callback_;
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProxyInfo results_;
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProxyResolver::RequestHandle request_;
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Test that a deadlock does not happen during shutdown when a host resolve
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is outstanding on the SyncHostResolverBridge.
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This is a regression test for http://crbug.com/41244.
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST(MultiThreadedProxyResolverTest, ShutdownIsCalledBeforeThreadJoin) {
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  IOThread io_thread;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::Thread::Options options;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  options.message_loop_type = MessageLoop::TYPE_IO;
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(io_thread.StartWithOptions(options));
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  io_thread.async_resolver()->WaitUntilRequestIsReceived();
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now upon exitting this scope, the IOThread is destroyed -- this will
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // stop the IOThread, which will in turn delete the
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // SingleThreadedProxyResolver, which in turn will stop its internal
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // PAC thread (which is currently blocked waiting on the host resolve which
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is running on IOThread).  The IOThread::Cleanup() will verify that after
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the PAC thread is stopped, it cancels the request on the HostResolver.
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
235