[ServiceWorker] Implement WebServiceWorkerContextClient::openWindow().
[chromium-blink-merge.git] / chromeos / dbus / services / proxy_resolution_service_provider.cc
blobfcdcf9767ee0632a6a405f582fc991dc79b6b1a9
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/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"
20 namespace chromeos {
22 // The ProxyResolverInterface implementation used in production.
23 class ProxyResolverImpl : public ProxyResolverInterface {
24 public:
25 // Data being used in one proxy resolution.
26 class Request {
27 public:
28 explicit Request(const std::string& source_url) : source_url_(source_url) {
31 virtual ~Request() {}
33 // Callback on IO thread for when net::ProxyService::ResolveProxy
34 // completes, synchronously or asynchronously.
35 void OnCompletion(scoped_refptr<base::SingleThreadTaskRunner> origin_thread,
36 int result) {
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.
49 private:
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_;
66 delete request;
70 // ProxyResolverInterface override.
71 void ResolveProxy(
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(),
83 signal_interface,
84 signal_name,
85 exported_object,
86 request);
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(
94 FROM_HERE,
95 base::Bind(&ProxyResolverImpl::ResolveProxyInternal,
96 request,
97 origin_thread_,
98 getter,
99 exported_object));
102 private:
103 // Helper function for ResolveProxy().
104 static void ResolveProxyInternal(
105 Request* request,
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.
113 if (!getter.get()) {
114 request->error_ = "No URLRequestContextGetter";
115 request->OnCompletion(origin_thread, net::ERR_UNEXPECTED);
116 return;
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);
125 return;
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),
133 origin_thread);
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
144 // thread.
145 void NotifyProxyResolved(
146 const std::string& signal_interface,
147 const std::string& signal_name,
148 scoped_refptr<dbus::ExportedObject> exported_object,
149 Request* request) {
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";
165 } else {
166 all_requests_.erase(iter);
168 delete request;
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,
214 bool success) {
215 if (!success) {
216 LOG(ERROR) << "Failed to export " << interface_name << "."
217 << method_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>());
241 return;
244 resolver_->ResolveProxy(source_url,
245 signal_interface,
246 signal_name,
247 exported_object_);
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));
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;
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