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/exported_object.h"
12 #include "dbus/message.h"
13 #include "net/base/load_flags.h"
14 #include "net/base/net_errors.h"
15 #include "net/proxy/proxy_service.h"
16 #include "net/url_request/url_request_context.h"
17 #include "net/url_request/url_request_context_getter.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
22 // The ProxyResolverInterface implementation used in production.
23 class ProxyResolverImpl
: public ProxyResolverInterface
{
25 // Data being used in one proxy resolution.
28 explicit Request(const std::string
& source_url
) : source_url_(source_url
) {
33 // Callback on IO thread for when net::ProxyService::ResolveProxy
34 // completes, synchronously or asynchronously.
35 void OnCompletion(scoped_refptr
<base::SingleThreadTaskRunner
> origin_thread
,
37 // Generate the error message if the error message is not yet set,
38 // and there was an error.
39 if (error_
.empty() && result
!= net::OK
)
40 error_
= net::ErrorToString(result
);
41 origin_thread
->PostTask(FROM_HERE
, notify_task_
);
44 std::string source_url_
; // URL being resolved.
45 net::ProxyInfo proxy_info_
; // ProxyInfo resolved for source_url_.
46 std::string error_
; // Error from proxy resolution.
47 base::Closure notify_task_
; // Task to notify of resolution result.
50 DISALLOW_COPY_AND_ASSIGN(Request
);
53 explicit ProxyResolverImpl(scoped_ptr
<ProxyResolverDelegate
> delegate
)
54 : delegate_(delegate
.Pass()),
55 origin_thread_(base::ThreadTaskRunnerHandle::Get()),
56 weak_ptr_factory_(this) {
59 ~ProxyResolverImpl() override
{
60 DCHECK(OnOriginThread());
62 for (std::set
<Request
*>::iterator iter
= all_requests_
.begin();
63 iter
!= all_requests_
.end(); ++iter
) {
64 Request
* request
= *iter
;
65 LOG(WARNING
) << "Pending request for " << request
->source_url_
;
70 // ProxyResolverInterface override.
72 const std::string
& source_url
,
73 const std::string
& signal_interface
,
74 const std::string
& signal_name
,
75 scoped_refptr
<dbus::ExportedObject
> exported_object
) override
{
76 DCHECK(OnOriginThread());
78 // Create a request slot for this proxy resolution request.
79 Request
* request
= new Request(source_url
);
80 request
->notify_task_
= base::Bind(
81 &ProxyResolverImpl::NotifyProxyResolved
,
82 weak_ptr_factory_
.GetWeakPtr(),
87 all_requests_
.insert(request
);
89 // GetRequestContext() must be called on UI thread.
90 scoped_refptr
<net::URLRequestContextGetter
> getter
=
91 delegate_
->GetRequestContext();
93 getter
->GetNetworkTaskRunner()->PostTask(
95 base::Bind(&ProxyResolverImpl::ResolveProxyInternal
,
103 // Helper function for ResolveProxy().
104 static void ResolveProxyInternal(
106 scoped_refptr
<base::SingleThreadTaskRunner
> origin_thread
,
107 scoped_refptr
<net::URLRequestContextGetter
> getter
,
108 scoped_refptr
<dbus::ExportedObject
> exported_object
) {
109 // Make sure we're running on IO thread.
110 DCHECK(getter
->GetNetworkTaskRunner()->BelongsToCurrentThread());
112 // Check if we have the URLRequestContextGetter.
114 request
->error_
= "No URLRequestContextGetter";
115 request
->OnCompletion(origin_thread
, net::ERR_UNEXPECTED
);
119 // Retrieve ProxyService from profile's request context.
120 net::ProxyService
* proxy_service
=
121 getter
->GetURLRequestContext()->proxy_service();
122 if (!proxy_service
) {
123 request
->error_
= "No proxy service in chrome";
124 request
->OnCompletion(origin_thread
, net::ERR_UNEXPECTED
);
128 VLOG(1) << "Starting network proxy resolution for "
129 << request
->source_url_
;
130 net::CompletionCallback completion_callback
=
131 base::Bind(&Request::OnCompletion
,
132 base::Unretained(request
),
134 const int result
= proxy_service
->ResolveProxy(
135 GURL(request
->source_url_
), net::LOAD_NORMAL
, &request
->proxy_info_
,
136 completion_callback
, NULL
, NULL
, net::BoundNetLog());
137 if (result
!= net::ERR_IO_PENDING
) {
138 VLOG(1) << "Network proxy resolution completed synchronously.";
139 completion_callback
.Run(result
);
143 // Called on UI thread as task posted from Request::OnCompletion on IO
145 void NotifyProxyResolved(
146 const std::string
& signal_interface
,
147 const std::string
& signal_name
,
148 scoped_refptr
<dbus::ExportedObject
> exported_object
,
150 DCHECK(OnOriginThread());
152 // Send a signal to the client.
153 dbus::Signal
signal(signal_interface
, signal_name
);
154 dbus::MessageWriter
writer(&signal
);
155 writer
.AppendString(request
->source_url_
);
156 writer
.AppendString(request
->proxy_info_
.ToPacString());
157 writer
.AppendString(request
->error_
);
158 exported_object
->SendSignal(&signal
);
159 VLOG(1) << "Sending signal: " << signal
.ToString();
161 std::set
<Request
*>::iterator iter
= all_requests_
.find(request
);
162 if (iter
== all_requests_
.end()) {
163 LOG(ERROR
) << "can't find request slot(" << request
->source_url_
164 << ") in proxy-resolution queue";
166 all_requests_
.erase(iter
);
171 // Returns true if the current thread is on the origin thread.
172 bool OnOriginThread() {
173 return origin_thread_
->BelongsToCurrentThread();
176 scoped_ptr
<ProxyResolverDelegate
> delegate_
;
177 scoped_refptr
<base::SingleThreadTaskRunner
> origin_thread_
;
178 std::set
<Request
*> all_requests_
;
179 base::WeakPtrFactory
<ProxyResolverImpl
> weak_ptr_factory_
;
181 DISALLOW_COPY_AND_ASSIGN(ProxyResolverImpl
);
184 ProxyResolutionServiceProvider::ProxyResolutionServiceProvider(
185 ProxyResolverInterface
* resolver
)
186 : resolver_(resolver
),
187 origin_thread_(base::ThreadTaskRunnerHandle::Get()),
188 weak_ptr_factory_(this) {
191 ProxyResolutionServiceProvider::~ProxyResolutionServiceProvider() {
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()));
211 void ProxyResolutionServiceProvider::OnExported(
212 const std::string
& interface_name
,
213 const std::string
& method_name
,
216 LOG(ERROR
) << "Failed to export " << interface_name
<< "."
219 VLOG(1) << "Method exported: " << interface_name
<< "." << method_name
;
222 bool ProxyResolutionServiceProvider::OnOriginThread() {
223 return origin_thread_
->BelongsToCurrentThread();
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
>());
244 resolver_
->ResolveProxy(source_url
,
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
));
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
>());
264 provider_weak_ptr
->ResolveProxyHandler(method_call
, response_sender
);
267 ProxyResolutionServiceProvider
* ProxyResolutionServiceProvider::Create(
268 scoped_ptr
<ProxyResolverDelegate
> delegate
) {
269 return new ProxyResolutionServiceProvider(
270 new ProxyResolverImpl(delegate
.Pass()));
273 ProxyResolverInterface::~ProxyResolverInterface() {
276 } // namespace chromeos