OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/thread_task_runner_handle.h" | |
10 #include "chrome/browser/profiles/profile_manager.h" | |
11 #include "dbus/bus.h" | |
12 #include "dbus/message.h" | |
13 #include "dbus/exported_object.h" | |
14 #include "net/base/load_flags.h" | |
15 #include "net/base/net_errors.h" | |
16 #include "net/proxy/proxy_service.h" | |
17 #include "net/url_request/url_request_context.h" | |
18 #include "net/url_request/url_request_context_getter.h" | |
19 #include "third_party/cros_system_api/dbus/service_constants.h" | |
20 | |
21 namespace chromeos { | |
22 | |
23 // The ProxyResolverInterface implementation used in production. | |
24 class ProxyResolverImpl : public ProxyResolverInterface { | |
25 public: | |
26 // Data being used in one proxy resolution. | |
27 class Request { | |
28 public: | |
29 explicit Request(const std::string& source_url) : source_url_(source_url) { | |
30 } | |
31 | |
32 virtual ~Request() {} | |
33 | |
34 // Callback on IO thread for when net::ProxyService::ResolveProxy | |
35 // completes, synchronously or asynchronously. | |
36 void OnCompletion(scoped_refptr<base::SingleThreadTaskRunner> origin_thread, | |
37 int result) { | |
38 // Generate the error message if the error message is not yet set, | |
39 // and there was an error. | |
40 if (error_.empty() && result != net::OK) | |
41 error_ = net::ErrorToString(result); | |
42 origin_thread->PostTask(FROM_HERE, notify_task_); | |
43 } | |
44 | |
45 std::string source_url_; // URL being resolved. | |
46 net::ProxyInfo proxy_info_; // ProxyInfo resolved for source_url_. | |
47 std::string error_; // Error from proxy resolution. | |
48 base::Closure notify_task_; // Task to notify of resolution result. | |
49 | |
50 private: | |
51 DISALLOW_COPY_AND_ASSIGN(Request); | |
52 }; | |
53 | |
54 ProxyResolverImpl() : origin_thread_(base::ThreadTaskRunnerHandle::Get()), | |
55 weak_ptr_factory_(this) { | |
56 } | |
57 | |
58 virtual ~ProxyResolverImpl() { | |
59 DCHECK(OnOriginThread()); | |
60 | |
61 for (std::set<Request*>::iterator iter = all_requests_.begin(); | |
62 iter != all_requests_.end(); ++iter) { | |
63 Request* request = *iter; | |
64 LOG(WARNING) << "Pending request for " << request->source_url_; | |
65 delete request; | |
66 } | |
67 } | |
68 | |
69 // ProxyResolverInterface override. | |
70 virtual void ResolveProxy( | |
71 const std::string& source_url, | |
72 const std::string& signal_interface, | |
73 const std::string& signal_name, | |
74 scoped_refptr<dbus::ExportedObject> exported_object) override { | |
75 DCHECK(OnOriginThread()); | |
76 | |
77 // Create a request slot for this proxy resolution request. | |
78 Request* request = new Request(source_url); | |
79 request->notify_task_ = base::Bind( | |
80 &ProxyResolverImpl::NotifyProxyResolved, | |
81 weak_ptr_factory_.GetWeakPtr(), | |
82 signal_interface, | |
83 signal_name, | |
84 exported_object, | |
85 request); | |
86 all_requests_.insert(request); | |
87 | |
88 // GetPrimaryUserProfile() and GetRequestContext() must be called on UI | |
89 // thread. | |
90 Profile* profile = ProfileManager::GetPrimaryUserProfile(); | |
91 scoped_refptr<net::URLRequestContextGetter> getter = | |
92 profile->GetRequestContext(); | |
93 | |
94 getter->GetNetworkTaskRunner()->PostTask( | |
95 FROM_HERE, | |
96 base::Bind(&ProxyResolverImpl::ResolveProxyInternal, | |
97 request, | |
98 origin_thread_, | |
99 getter, | |
100 exported_object)); | |
101 } | |
102 | |
103 private: | |
104 // Helper function for ResolveProxy(). | |
105 static void ResolveProxyInternal( | |
106 Request* request, | |
107 scoped_refptr<base::SingleThreadTaskRunner> origin_thread, | |
108 scoped_refptr<net::URLRequestContextGetter> getter, | |
109 scoped_refptr<dbus::ExportedObject> exported_object) { | |
110 // Make sure we're running on IO thread. | |
111 DCHECK(getter->GetNetworkTaskRunner()->BelongsToCurrentThread()); | |
112 | |
113 // Check if we have the URLRequestContextGetter. | |
114 if (!getter.get()) { | |
115 request->error_ = "No URLRequestContextGetter"; | |
116 request->OnCompletion(origin_thread, net::ERR_UNEXPECTED); | |
117 return; | |
118 } | |
119 | |
120 // Retrieve ProxyService from profile's request context. | |
121 net::ProxyService* proxy_service = | |
122 getter->GetURLRequestContext()->proxy_service(); | |
123 if (!proxy_service) { | |
124 request->error_ = "No proxy service in chrome"; | |
125 request->OnCompletion(origin_thread, net::ERR_UNEXPECTED); | |
126 return; | |
127 } | |
128 | |
129 VLOG(1) << "Starting network proxy resolution for " | |
130 << request->source_url_; | |
131 net::CompletionCallback completion_callback = | |
132 base::Bind(&Request::OnCompletion, | |
133 base::Unretained(request), | |
134 origin_thread); | |
135 const int result = proxy_service->ResolveProxy( | |
136 GURL(request->source_url_), net::LOAD_NORMAL, &request->proxy_info_, | |
137 completion_callback, NULL, NULL, net::BoundNetLog()); | |
138 if (result != net::ERR_IO_PENDING) { | |
139 VLOG(1) << "Network proxy resolution completed synchronously."; | |
140 completion_callback.Run(result); | |
141 } | |
142 } | |
143 | |
144 // Called on UI thread as task posted from Request::OnCompletion on IO | |
145 // thread. | |
146 void NotifyProxyResolved( | |
147 const std::string& signal_interface, | |
148 const std::string& signal_name, | |
149 scoped_refptr<dbus::ExportedObject> exported_object, | |
150 Request* request) { | |
151 DCHECK(OnOriginThread()); | |
152 | |
153 // Send a signal to the client. | |
154 dbus::Signal signal(signal_interface, signal_name); | |
155 dbus::MessageWriter writer(&signal); | |
156 writer.AppendString(request->source_url_); | |
157 writer.AppendString(request->proxy_info_.ToPacString()); | |
158 writer.AppendString(request->error_); | |
159 exported_object->SendSignal(&signal); | |
160 VLOG(1) << "Sending signal: " << signal.ToString(); | |
161 | |
162 std::set<Request*>::iterator iter = all_requests_.find(request); | |
163 if (iter == all_requests_.end()) { | |
164 LOG(ERROR) << "can't find request slot(" << request->source_url_ | |
165 << ") in proxy-resolution queue"; | |
166 } else { | |
167 all_requests_.erase(iter); | |
168 } | |
169 delete request; | |
170 } | |
171 | |
172 // Returns true if the current thread is on the origin thread. | |
173 bool OnOriginThread() { | |
174 return origin_thread_->BelongsToCurrentThread(); | |
175 } | |
176 | |
177 scoped_refptr<base::SingleThreadTaskRunner> origin_thread_; | |
178 std::set<Request*> all_requests_; | |
179 base::WeakPtrFactory<ProxyResolverImpl> weak_ptr_factory_; | |
180 | |
181 DISALLOW_COPY_AND_ASSIGN(ProxyResolverImpl); | |
182 }; | |
183 | |
184 ProxyResolutionServiceProvider::ProxyResolutionServiceProvider( | |
185 ProxyResolverInterface* resolver) | |
186 : resolver_(resolver), | |
187 origin_thread_(base::ThreadTaskRunnerHandle::Get()), | |
188 weak_ptr_factory_(this) { | |
189 } | |
190 | |
191 ProxyResolutionServiceProvider::~ProxyResolutionServiceProvider() { | |
192 } | |
193 | |
194 void ProxyResolutionServiceProvider::Start( | |
195 scoped_refptr<dbus::ExportedObject> exported_object) { | |
196 DCHECK(OnOriginThread()); | |
197 exported_object_ = exported_object; | |
198 VLOG(1) << "ProxyResolutionServiceProvider started"; | |
199 exported_object_->ExportMethod( | |
200 kLibCrosServiceInterface, | |
201 kResolveNetworkProxy, | |
202 // Weak pointers can only bind to methods without return values, | |
203 // hence we cannot bind ResolveProxyInternal here. Instead we use a | |
204 // static function to solve this problem. | |
205 base::Bind(&ProxyResolutionServiceProvider::CallResolveProxyHandler, | |
206 weak_ptr_factory_.GetWeakPtr()), | |
207 base::Bind(&ProxyResolutionServiceProvider::OnExported, | |
208 weak_ptr_factory_.GetWeakPtr())); | |
209 } | |
210 | |
211 void ProxyResolutionServiceProvider::OnExported( | |
212 const std::string& interface_name, | |
213 const std::string& method_name, | |
214 bool success) { | |
215 if (!success) { | |
216 LOG(ERROR) << "Failed to export " << interface_name << "." | |
217 << method_name; | |
218 } | |
219 VLOG(1) << "Method exported: " << interface_name << "." << method_name; | |
220 } | |
221 | |
222 bool ProxyResolutionServiceProvider::OnOriginThread() { | |
223 return origin_thread_->BelongsToCurrentThread(); | |
224 } | |
225 | |
226 void ProxyResolutionServiceProvider::ResolveProxyHandler( | |
227 dbus::MethodCall* method_call, | |
228 dbus::ExportedObject::ResponseSender response_sender) { | |
229 DCHECK(OnOriginThread()); | |
230 VLOG(1) << "Handing method call: " << method_call->ToString(); | |
231 // The method call should contain the three string parameters. | |
232 dbus::MessageReader reader(method_call); | |
233 std::string source_url; | |
234 std::string signal_interface; | |
235 std::string signal_name; | |
236 if (!reader.PopString(&source_url) || | |
237 !reader.PopString(&signal_interface) || | |
238 !reader.PopString(&signal_name)) { | |
239 LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); | |
240 response_sender.Run(scoped_ptr<dbus::Response>()); | |
241 return; | |
242 } | |
243 | |
244 resolver_->ResolveProxy(source_url, | |
245 signal_interface, | |
246 signal_name, | |
247 exported_object_); | |
248 | |
249 // Send an empty response for now. We'll send a signal once the network proxy | |
250 // resolution is completed. | |
251 response_sender.Run(dbus::Response::FromMethodCall(method_call)); | |
252 } | |
253 | |
254 // static | |
255 void ProxyResolutionServiceProvider::CallResolveProxyHandler( | |
256 base::WeakPtr<ProxyResolutionServiceProvider> provider_weak_ptr, | |
257 dbus::MethodCall* method_call, | |
258 dbus::ExportedObject::ResponseSender response_sender) { | |
259 if (!provider_weak_ptr) { | |
260 LOG(WARNING) << "Called after the object is deleted"; | |
261 response_sender.Run(scoped_ptr<dbus::Response>()); | |
262 return; | |
263 } | |
264 provider_weak_ptr->ResolveProxyHandler(method_call, response_sender); | |
265 } | |
266 | |
267 ProxyResolutionServiceProvider* ProxyResolutionServiceProvider::Create() { | |
268 return new ProxyResolutionServiceProvider(new ProxyResolverImpl); | |
269 } | |
270 | |
271 ProxyResolutionServiceProvider* | |
272 ProxyResolutionServiceProvider::CreateForTesting( | |
273 ProxyResolverInterface* resolver) { | |
274 return new ProxyResolutionServiceProvider(resolver); | |
275 } | |
276 | |
277 ProxyResolverInterface::~ProxyResolverInterface() { | |
278 } | |
279 | |
280 } // namespace chromeos | |
OLD | NEW |