| 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 |