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.
5 #include "chromeos/dbus/services/proxy_resolution_service_provider.h"
8 #include "base/bind_helpers.h"
9 #include "base/thread_task_runner_handle.h"
11 #include "dbus/message.h"
12 #include "net/base/load_flags.h"
13 #include "net/base/net_errors.h"
14 #include "net/proxy/proxy_service.h"
15 #include "net/url_request/url_request_context.h"
16 #include "net/url_request/url_request_context_getter.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
21 // The ProxyResolverInterface implementation used in production.
22 class ProxyResolverImpl
: public ProxyResolverInterface
{
24 // Data being used in one proxy resolution.
27 explicit Request(const std::string
& source_url
) : source_url_(source_url
) {
32 // Callback on IO thread for when net::ProxyService::ResolveProxy
33 // completes, synchronously or asynchronously.
34 void OnCompletion(scoped_refptr
<base::SingleThreadTaskRunner
> origin_thread
,
36 // Generate the error message if the error message is not yet set,
37 // and there was an error.
38 if (error_
.empty() && result
!= net::OK
)
39 error_
= net::ErrorToString(result
);
40 origin_thread
->PostTask(FROM_HERE
, notify_task_
);
43 std::string source_url_
; // URL being resolved.
44 net::ProxyInfo proxy_info_
; // ProxyInfo resolved for source_url_.
45 std::string error_
; // Error from proxy resolution.
46 base::Closure notify_task_
; // Task to notify of resolution result.
49 DISALLOW_COPY_AND_ASSIGN(Request
);
52 explicit ProxyResolverImpl(scoped_ptr
<ProxyResolverDelegate
> delegate
)
53 : delegate_(delegate
.Pass()),
54 origin_thread_(base::ThreadTaskRunnerHandle::Get()),
55 weak_ptr_factory_(this) {
58 ~ProxyResolverImpl() override
{
59 DCHECK(OnOriginThread());
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_
;
69 // ProxyResolverInterface override.
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());
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(),
86 all_requests_
.insert(request
);
88 // GetRequestContext() must be called on UI thread.
89 scoped_refptr
<net::URLRequestContextGetter
> getter
=
90 delegate_
->GetRequestContext();
92 getter
->GetNetworkTaskRunner()->PostTask(
94 base::Bind(&ProxyResolverImpl::ResolveProxyInternal
,
102 // Helper function for ResolveProxy().
103 static void ResolveProxyInternal(
105 scoped_refptr
<base::SingleThreadTaskRunner
> origin_thread
,
106 scoped_refptr
<net::URLRequestContextGetter
> getter
,
107 scoped_refptr
<dbus::ExportedObject
> exported_object
) {
108 // Make sure we're running on IO thread.
109 DCHECK(getter
->GetNetworkTaskRunner()->BelongsToCurrentThread());
111 // Check if we have the URLRequestContextGetter.
113 request
->error_
= "No URLRequestContextGetter";
114 request
->OnCompletion(origin_thread
, net::ERR_UNEXPECTED
);
118 // Retrieve ProxyService from profile's request context.
119 net::ProxyService
* proxy_service
=
120 getter
->GetURLRequestContext()->proxy_service();
121 if (!proxy_service
) {
122 request
->error_
= "No proxy service in chrome";
123 request
->OnCompletion(origin_thread
, net::ERR_UNEXPECTED
);
127 VLOG(1) << "Starting network proxy resolution for "
128 << request
->source_url_
;
129 net::CompletionCallback completion_callback
=
130 base::Bind(&Request::OnCompletion
,
131 base::Unretained(request
),
133 const int result
= proxy_service
->ResolveProxy(
134 GURL(request
->source_url_
), net::LOAD_NORMAL
, &request
->proxy_info_
,
135 completion_callback
, NULL
, NULL
, net::BoundNetLog());
136 if (result
!= net::ERR_IO_PENDING
) {
137 VLOG(1) << "Network proxy resolution completed synchronously.";
138 completion_callback
.Run(result
);
142 // Called on UI thread as task posted from Request::OnCompletion on IO
144 void NotifyProxyResolved(
145 const std::string
& signal_interface
,
146 const std::string
& signal_name
,
147 scoped_refptr
<dbus::ExportedObject
> exported_object
,
149 DCHECK(OnOriginThread());
151 // Send a signal to the client.
152 dbus::Signal
signal(signal_interface
, signal_name
);
153 dbus::MessageWriter
writer(&signal
);
154 writer
.AppendString(request
->source_url_
);
155 writer
.AppendString(request
->proxy_info_
.ToPacString());
156 writer
.AppendString(request
->error_
);
157 exported_object
->SendSignal(&signal
);
158 VLOG(1) << "Sending signal: " << signal
.ToString();
160 std::set
<Request
*>::iterator iter
= all_requests_
.find(request
);
161 if (iter
== all_requests_
.end()) {
162 LOG(ERROR
) << "can't find request slot(" << request
->source_url_
163 << ") in proxy-resolution queue";
165 all_requests_
.erase(iter
);
170 // Returns true if the current thread is on the origin thread.
171 bool OnOriginThread() {
172 return origin_thread_
->BelongsToCurrentThread();
175 scoped_ptr
<ProxyResolverDelegate
> delegate_
;
176 scoped_refptr
<base::SingleThreadTaskRunner
> origin_thread_
;
177 std::set
<Request
*> all_requests_
;
178 base::WeakPtrFactory
<ProxyResolverImpl
> weak_ptr_factory_
;
180 DISALLOW_COPY_AND_ASSIGN(ProxyResolverImpl
);
183 ProxyResolutionServiceProvider::ProxyResolutionServiceProvider(
184 ProxyResolverInterface
* resolver
)
185 : resolver_(resolver
),
186 origin_thread_(base::ThreadTaskRunnerHandle::Get()),
187 weak_ptr_factory_(this) {
190 ProxyResolutionServiceProvider::~ProxyResolutionServiceProvider() {
193 void ProxyResolutionServiceProvider::Start(
194 scoped_refptr
<dbus::ExportedObject
> exported_object
) {
195 DCHECK(OnOriginThread());
196 exported_object_
= exported_object
;
197 VLOG(1) << "ProxyResolutionServiceProvider started";
198 exported_object_
->ExportMethod(
199 kLibCrosServiceInterface
,
200 kResolveNetworkProxy
,
201 // Weak pointers can only bind to methods without return values,
202 // hence we cannot bind ResolveProxyInternal here. Instead we use a
203 // static function to solve this problem.
204 base::Bind(&ProxyResolutionServiceProvider::CallResolveProxyHandler
,
205 weak_ptr_factory_
.GetWeakPtr()),
206 base::Bind(&ProxyResolutionServiceProvider::OnExported
,
207 weak_ptr_factory_
.GetWeakPtr()));
210 void ProxyResolutionServiceProvider::OnExported(
211 const std::string
& interface_name
,
212 const std::string
& method_name
,
215 LOG(ERROR
) << "Failed to export " << interface_name
<< "."
218 VLOG(1) << "Method exported: " << interface_name
<< "." << method_name
;
221 bool ProxyResolutionServiceProvider::OnOriginThread() {
222 return origin_thread_
->BelongsToCurrentThread();
225 void ProxyResolutionServiceProvider::ResolveProxyHandler(
226 dbus::MethodCall
* method_call
,
227 dbus::ExportedObject::ResponseSender response_sender
) {
228 DCHECK(OnOriginThread());
229 VLOG(1) << "Handing method call: " << method_call
->ToString();
230 // The method call should contain the three string parameters.
231 dbus::MessageReader
reader(method_call
);
232 std::string source_url
;
233 std::string signal_interface
;
234 std::string signal_name
;
235 if (!reader
.PopString(&source_url
) ||
236 !reader
.PopString(&signal_interface
) ||
237 !reader
.PopString(&signal_name
)) {
238 LOG(ERROR
) << "Unexpected method call: " << method_call
->ToString();
239 response_sender
.Run(scoped_ptr
<dbus::Response
>());
243 resolver_
->ResolveProxy(source_url
,
248 // Send an empty response for now. We'll send a signal once the network proxy
249 // resolution is completed.
250 response_sender
.Run(dbus::Response::FromMethodCall(method_call
));
254 void ProxyResolutionServiceProvider::CallResolveProxyHandler(
255 base::WeakPtr
<ProxyResolutionServiceProvider
> provider_weak_ptr
,
256 dbus::MethodCall
* method_call
,
257 dbus::ExportedObject::ResponseSender response_sender
) {
258 if (!provider_weak_ptr
) {
259 LOG(WARNING
) << "Called after the object is deleted";
260 response_sender
.Run(scoped_ptr
<dbus::Response
>());
263 provider_weak_ptr
->ResolveProxyHandler(method_call
, response_sender
);
266 ProxyResolutionServiceProvider
* ProxyResolutionServiceProvider::Create(
267 scoped_ptr
<ProxyResolverDelegate
> delegate
) {
268 return new ProxyResolutionServiceProvider(
269 new ProxyResolverImpl(delegate
.Pass()));
272 ProxyResolverInterface::~ProxyResolverInterface() {
275 } // namespace chromeos