Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chromeos / dbus / services / proxy_resolution_service_provider.cc
blob1f5ec44637d8a25c3608904f3c645de5b1c439d6
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"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "dbus/bus.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"
19 namespace chromeos {
21 // The ProxyResolverInterface implementation used in production.
22 class ProxyResolverImpl : public ProxyResolverInterface {
23 public:
24 // Data being used in one proxy resolution.
25 class Request {
26 public:
27 explicit Request(const std::string& source_url) : source_url_(source_url) {
30 virtual ~Request() {}
32 // Callback on IO thread for when net::ProxyService::ResolveProxy
33 // completes, synchronously or asynchronously.
34 void OnCompletion(scoped_refptr<base::SingleThreadTaskRunner> origin_thread,
35 int result) {
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.
48 private:
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_;
65 delete request;
69 // ProxyResolverInterface override.
70 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());
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);
88 // GetRequestContext() must be called on UI thread.
89 scoped_refptr<net::URLRequestContextGetter> getter =
90 delegate_->GetRequestContext();
92 getter->GetNetworkTaskRunner()->PostTask(
93 FROM_HERE,
94 base::Bind(&ProxyResolverImpl::ResolveProxyInternal,
95 request,
96 origin_thread_,
97 getter,
98 exported_object));
101 private:
102 // Helper function for ResolveProxy().
103 static void ResolveProxyInternal(
104 Request* request,
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.
112 if (!getter.get()) {
113 request->error_ = "No URLRequestContextGetter";
114 request->OnCompletion(origin_thread, net::ERR_UNEXPECTED);
115 return;
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);
124 return;
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),
132 origin_thread);
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
143 // thread.
144 void NotifyProxyResolved(
145 const std::string& signal_interface,
146 const std::string& signal_name,
147 scoped_refptr<dbus::ExportedObject> exported_object,
148 Request* request) {
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";
164 } else {
165 all_requests_.erase(iter);
167 delete request;
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,
213 bool success) {
214 if (!success) {
215 LOG(ERROR) << "Failed to export " << interface_name << "."
216 << method_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>());
240 return;
243 resolver_->ResolveProxy(source_url,
244 signal_interface,
245 signal_name,
246 exported_object_);
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));
253 // static
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>());
261 return;
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