OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/single_threaded_proxy_resolver.h" | 5 #include "net/proxy/single_threaded_proxy_resolver.h" |
6 | 6 |
7 #include "base/thread.h" | 7 #include "base/thread.h" |
8 #include "net/base/net_errors.h" | 8 #include "net/base/net_errors.h" |
9 #include "net/proxy/proxy_info.h" | 9 #include "net/proxy/proxy_info.h" |
10 | 10 |
11 namespace net { | 11 namespace net { |
12 | 12 |
13 // Runs on the worker thread to call ProxyResolver::SetPacScriptByUrl or | 13 // SingleThreadedProxyResolver::SetPacScriptTask ------------------------------ |
14 // ProxyResolver::SetPacScriptByData. | 14 |
15 // TODO(eroman): the lifetime of this task is ill-defined; |resolver_| must | 15 // Runs on the worker thread to call ProxyResolver::SetPacScript. |
16 // be valid when the task eventually is run. Make this task cancellable. | 16 class SingleThreadedProxyResolver::SetPacScriptTask |
17 class SetPacScriptTask : public Task { | 17 : public base::RefCountedThreadSafe< |
| 18 SingleThreadedProxyResolver::SetPacScriptTask> { |
18 public: | 19 public: |
19 SetPacScriptTask(ProxyResolver* resolver, | 20 SetPacScriptTask(SingleThreadedProxyResolver* coordinator, |
20 const GURL& pac_url, | 21 const GURL& pac_url, |
21 const std::string& bytes) | 22 const std::string& pac_bytes, |
22 : resolver_(resolver), pac_url_(pac_url), bytes_(bytes) {} | 23 CompletionCallback* callback) |
23 | 24 : coordinator_(coordinator), |
24 virtual void Run() { | 25 callback_(callback), |
25 if (resolver_->expects_pac_bytes()) | 26 pac_bytes_(pac_bytes), |
26 resolver_->SetPacScriptByData(bytes_); | 27 pac_url_(pac_url), |
27 else | 28 origin_loop_(MessageLoop::current()) { |
28 resolver_->SetPacScriptByUrl(pac_url_); | 29 DCHECK(callback); |
29 } | 30 } |
30 | 31 |
| 32 // Start the SetPacScript request on the worker thread. |
| 33 void Start() { |
| 34 // TODO(eroman): Are these manual AddRef / Release necessary? |
| 35 AddRef(); // balanced in RequestComplete |
| 36 |
| 37 coordinator_->thread()->message_loop()->PostTask( |
| 38 FROM_HERE, NewRunnableMethod(this, &SetPacScriptTask::DoRequest, |
| 39 coordinator_->resolver_.get())); |
| 40 } |
| 41 |
| 42 void Cancel() { |
| 43 // Clear these to inform RequestComplete that it should not try to |
| 44 // access them. |
| 45 coordinator_ = NULL; |
| 46 callback_ = NULL; |
| 47 } |
| 48 |
| 49 // Returns true if Cancel() has been called. |
| 50 bool was_cancelled() const { return callback_ == NULL; } |
| 51 |
31 private: | 52 private: |
32 ProxyResolver* resolver_; | 53 // Runs on the worker thread. |
| 54 void DoRequest(ProxyResolver* resolver) { |
| 55 int rv = resolver->expects_pac_bytes() ? |
| 56 resolver->SetPacScriptByData(pac_bytes_, NULL) : |
| 57 resolver->SetPacScriptByUrl(pac_url_, NULL); |
| 58 |
| 59 DCHECK_NE(rv, ERR_IO_PENDING); |
| 60 origin_loop_->PostTask(FROM_HERE, |
| 61 NewRunnableMethod(this, &SetPacScriptTask::RequestComplete, rv)); |
| 62 } |
| 63 |
| 64 // Runs the completion callback on the origin thread. |
| 65 void RequestComplete(int result_code) { |
| 66 // The task may have been cancelled after it was started. |
| 67 if (!was_cancelled()) { |
| 68 CompletionCallback* callback = callback_; |
| 69 coordinator_->RemoveOutstandingSetPacScriptTask(this); |
| 70 callback->Run(result_code); |
| 71 } |
| 72 |
| 73 Release(); // Balances the AddRef in Start. |
| 74 } |
| 75 |
| 76 // Must only be used on the "origin" thread. |
| 77 SingleThreadedProxyResolver* coordinator_; |
| 78 CompletionCallback* callback_; |
| 79 std::string pac_bytes_; |
33 GURL pac_url_; | 80 GURL pac_url_; |
34 std::string bytes_; | 81 |
| 82 // Usable from within DoQuery on the worker thread. |
| 83 MessageLoop* origin_loop_; |
35 }; | 84 }; |
36 | 85 |
37 // SingleThreadedProxyResolver::Job ------------------------------------------- | 86 // SingleThreadedProxyResolver::Job ------------------------------------------- |
38 | 87 |
39 class SingleThreadedProxyResolver::Job | 88 class SingleThreadedProxyResolver::Job |
40 : public base::RefCountedThreadSafe<SingleThreadedProxyResolver::Job> { | 89 : public base::RefCountedThreadSafe<SingleThreadedProxyResolver::Job> { |
41 public: | 90 public: |
42 // |coordinator| -- the SingleThreadedProxyResolver that owns this job. | 91 // |coordinator| -- the SingleThreadedProxyResolver that owns this job. |
43 // |url| -- the URL of the query. | 92 // |url| -- the URL of the query. |
44 // |results| -- the structure to fill with proxy resolve results. | 93 // |results| -- the structure to fill with proxy resolve results. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 results_->Use(results_buf_); | 144 results_->Use(results_buf_); |
96 } | 145 } |
97 callback_->Run(result_code); | 146 callback_->Run(result_code); |
98 | 147 |
99 // We check for cancellation once again, in case the callback deleted | 148 // We check for cancellation once again, in case the callback deleted |
100 // the owning ProxyService (whose destructor will in turn cancel us). | 149 // the owning ProxyService (whose destructor will in turn cancel us). |
101 if (!was_cancelled()) | 150 if (!was_cancelled()) |
102 coordinator_->RemoveFrontOfJobsQueueAndStartNext(this); | 151 coordinator_->RemoveFrontOfJobsQueueAndStartNext(this); |
103 } | 152 } |
104 | 153 |
105 Release(); // balances the AddRef in Query. we may get deleted after | 154 Release(); // Balances the AddRef in Start. We may get deleted after |
106 // we return. | 155 // we return. |
107 } | 156 } |
108 | 157 |
109 // Must only be used on the "origin" thread. | 158 // Must only be used on the "origin" thread. |
110 SingleThreadedProxyResolver* coordinator_; | 159 SingleThreadedProxyResolver* coordinator_; |
111 CompletionCallback* callback_; | 160 CompletionCallback* callback_; |
112 ProxyInfo* results_; | 161 ProxyInfo* results_; |
113 GURL url_; | 162 GURL url_; |
114 bool is_started_; | 163 bool is_started_; |
115 | 164 |
(...skipping 11 matching lines...) Expand all Loading... |
127 } | 176 } |
128 | 177 |
129 SingleThreadedProxyResolver::~SingleThreadedProxyResolver() { | 178 SingleThreadedProxyResolver::~SingleThreadedProxyResolver() { |
130 // Cancel the inprogress job (if any), and free the rest. | 179 // Cancel the inprogress job (if any), and free the rest. |
131 for (PendingJobsQueue::iterator it = pending_jobs_.begin(); | 180 for (PendingJobsQueue::iterator it = pending_jobs_.begin(); |
132 it != pending_jobs_.end(); | 181 it != pending_jobs_.end(); |
133 ++it) { | 182 ++it) { |
134 (*it)->Cancel(); | 183 (*it)->Cancel(); |
135 } | 184 } |
136 | 185 |
| 186 if (outstanding_set_pac_script_task_) |
| 187 outstanding_set_pac_script_task_->Cancel(); |
| 188 |
137 // Note that |thread_| is destroyed before |resolver_|. This is important | 189 // Note that |thread_| is destroyed before |resolver_|. This is important |
138 // since |resolver_| could be running on |thread_|. | 190 // since |resolver_| could be running on |thread_|. |
139 } | 191 } |
140 | 192 |
141 int SingleThreadedProxyResolver::GetProxyForURL(const GURL& url, | 193 int SingleThreadedProxyResolver::GetProxyForURL(const GURL& url, |
142 ProxyInfo* results, | 194 ProxyInfo* results, |
143 CompletionCallback* callback, | 195 CompletionCallback* callback, |
144 RequestHandle* request) { | 196 RequestHandle* request) { |
145 DCHECK(callback); | 197 DCHECK(callback); |
146 | 198 |
(...skipping 28 matching lines...) Expand all Loading... |
175 return; | 227 return; |
176 } | 228 } |
177 | 229 |
178 // Otherwise just delete the job from the queue. | 230 // Otherwise just delete the job from the queue. |
179 PendingJobsQueue::iterator it = std::find( | 231 PendingJobsQueue::iterator it = std::find( |
180 pending_jobs_.begin(), pending_jobs_.end(), job); | 232 pending_jobs_.begin(), pending_jobs_.end(), job); |
181 DCHECK(it != pending_jobs_.end()); | 233 DCHECK(it != pending_jobs_.end()); |
182 pending_jobs_.erase(it); | 234 pending_jobs_.erase(it); |
183 } | 235 } |
184 | 236 |
185 void SingleThreadedProxyResolver::SetPacScriptByUrlInternal( | 237 void SingleThreadedProxyResolver::CancelSetPacScript() { |
186 const GURL& pac_url) { | 238 DCHECK(outstanding_set_pac_script_task_); |
187 SetPacScriptHelper(pac_url, std::string()); | 239 outstanding_set_pac_script_task_->Cancel(); |
| 240 outstanding_set_pac_script_task_ = NULL; |
188 } | 241 } |
189 | 242 |
190 void SingleThreadedProxyResolver::SetPacScriptByDataInternal( | 243 int SingleThreadedProxyResolver::SetPacScript( |
191 const std::string& bytes) { | 244 const GURL& pac_url, |
192 SetPacScriptHelper(GURL(), bytes); | 245 const std::string& pac_bytes, |
193 } | 246 CompletionCallback* callback) { |
| 247 EnsureThreadStarted(); |
| 248 DCHECK(!outstanding_set_pac_script_task_); |
194 | 249 |
195 void SingleThreadedProxyResolver::SetPacScriptHelper(const GURL& pac_url, | 250 SetPacScriptTask* task = new SetPacScriptTask( |
196 const std::string& bytes) { | 251 this, pac_url, pac_bytes, callback); |
197 EnsureThreadStarted(); | 252 outstanding_set_pac_script_task_ = task; |
198 thread()->message_loop()->PostTask( | 253 task->Start(); |
199 FROM_HERE, new SetPacScriptTask(resolver(), pac_url, bytes)); | 254 return ERR_IO_PENDING; |
200 } | 255 } |
201 | 256 |
202 void SingleThreadedProxyResolver::EnsureThreadStarted() { | 257 void SingleThreadedProxyResolver::EnsureThreadStarted() { |
203 if (!thread_.get()) { | 258 if (!thread_.get()) { |
204 thread_.reset(new base::Thread("pac-thread")); | 259 thread_.reset(new base::Thread("pac-thread")); |
205 thread_->Start(); | 260 thread_->Start(); |
206 } | 261 } |
207 } | 262 } |
208 | 263 |
209 void SingleThreadedProxyResolver::ProcessPendingJobs() { | 264 void SingleThreadedProxyResolver::ProcessPendingJobs() { |
(...skipping 11 matching lines...) Expand all Loading... |
221 | 276 |
222 void SingleThreadedProxyResolver::RemoveFrontOfJobsQueueAndStartNext( | 277 void SingleThreadedProxyResolver::RemoveFrontOfJobsQueueAndStartNext( |
223 Job* expected_job) { | 278 Job* expected_job) { |
224 DCHECK_EQ(expected_job, pending_jobs_.front().get()); | 279 DCHECK_EQ(expected_job, pending_jobs_.front().get()); |
225 pending_jobs_.pop_front(); | 280 pending_jobs_.pop_front(); |
226 | 281 |
227 // Start next work item. | 282 // Start next work item. |
228 ProcessPendingJobs(); | 283 ProcessPendingJobs(); |
229 } | 284 } |
230 | 285 |
| 286 void SingleThreadedProxyResolver::RemoveOutstandingSetPacScriptTask( |
| 287 SetPacScriptTask* task) { |
| 288 DCHECK_EQ(outstanding_set_pac_script_task_.get(), task); |
| 289 outstanding_set_pac_script_task_ = NULL; |
| 290 } |
| 291 |
231 } // namespace net | 292 } // namespace net |
OLD | NEW |