Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/dbus/services/proxy_resolution_service_provider.h" | 5 #include "chromeos/dbus/services/proxy_resolution_service_provider.h" |
| 6 | 6 |
| 7 #include <string> | |
| 8 #include <utility> | 7 #include <utility> |
| 9 | 8 |
| 10 #include "base/bind.h" | 9 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 12 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/memory/ptr_util.h" | |
| 13 #include "base/threading/thread_task_runner_handle.h" | 13 #include "base/threading/thread_task_runner_handle.h" |
| 14 #include "dbus/bus.h" | 14 #include "dbus/bus.h" |
| 15 #include "dbus/message.h" | 15 #include "dbus/message.h" |
| 16 #include "net/base/net_errors.h" | 16 #include "net/base/net_errors.h" |
| 17 #include "net/log/net_log_with_source.h" | 17 #include "net/log/net_log_with_source.h" |
| 18 #include "net/proxy/proxy_service.h" | 18 #include "net/proxy/proxy_service.h" |
| 19 #include "net/url_request/url_request_context.h" | 19 #include "net/url_request/url_request_context.h" |
| 20 #include "net/url_request/url_request_context_getter.h" | 20 #include "net/url_request/url_request_context_getter.h" |
| 21 #include "third_party/cros_system_api/dbus/service_constants.h" | 21 #include "third_party/cros_system_api/dbus/service_constants.h" |
| 22 | 22 |
| 23 namespace chromeos { | 23 namespace chromeos { |
| 24 namespace { | |
| 24 | 25 |
| 25 // The ProxyResolverInterface implementation used in production. | 26 // The ProxyResolverInterface implementation used in production. |
| 26 class ProxyResolverImpl : public ProxyResolverInterface { | 27 class ProxyResolverImpl : public ProxyResolverInterface { |
| 27 public: | 28 public: |
| 28 // Data being used in one proxy resolution. | 29 explicit ProxyResolverImpl(std::unique_ptr<ProxyResolverDelegate> delegate); |
| 29 class Request { | 30 ~ProxyResolverImpl() override; |
| 30 public: | |
| 31 explicit Request(const std::string& source_url) : source_url_(source_url) { | |
| 32 } | |
| 33 | |
| 34 virtual ~Request() {} | |
| 35 | |
| 36 // Callback on IO thread for when net::ProxyService::ResolveProxy | |
| 37 // completes, synchronously or asynchronously. | |
| 38 void OnCompletion(scoped_refptr<base::SingleThreadTaskRunner> origin_thread, | |
| 39 int result) { | |
| 40 // Generate the error message if the error message is not yet set, | |
| 41 // and there was an error. | |
| 42 if (error_.empty() && result != net::OK) | |
| 43 error_ = net::ErrorToString(result); | |
| 44 origin_thread->PostTask(FROM_HERE, notify_task_); | |
| 45 } | |
| 46 | |
| 47 std::string source_url_; // URL being resolved. | |
| 48 net::ProxyInfo proxy_info_; // ProxyInfo resolved for source_url_. | |
| 49 std::string error_; // Error from proxy resolution. | |
| 50 base::Closure notify_task_; // Task to notify of resolution result. | |
| 51 | |
| 52 private: | |
| 53 DISALLOW_COPY_AND_ASSIGN(Request); | |
| 54 }; | |
| 55 | |
| 56 explicit ProxyResolverImpl(std::unique_ptr<ProxyResolverDelegate> delegate) | |
| 57 : delegate_(std::move(delegate)), | |
| 58 origin_thread_(base::ThreadTaskRunnerHandle::Get()), | |
| 59 weak_ptr_factory_(this) {} | |
| 60 | |
| 61 ~ProxyResolverImpl() override { | |
| 62 DCHECK(OnOriginThread()); | |
| 63 | |
| 64 for (std::set<Request*>::iterator iter = all_requests_.begin(); | |
| 65 iter != all_requests_.end(); ++iter) { | |
| 66 Request* request = *iter; | |
| 67 LOG(WARNING) << "Pending request for " << request->source_url_; | |
| 68 delete request; | |
| 69 } | |
| 70 } | |
| 71 | 31 |
| 72 // ProxyResolverInterface override. | 32 // ProxyResolverInterface override. |
| 73 void ResolveProxy( | 33 void ResolveProxy( |
| 74 const std::string& source_url, | 34 const std::string& source_url, |
| 75 const std::string& signal_interface, | 35 const std::string& signal_interface, |
| 76 const std::string& signal_name, | 36 const std::string& signal_name, |
| 77 scoped_refptr<dbus::ExportedObject> exported_object) override { | 37 scoped_refptr<dbus::ExportedObject> exported_object) override; |
| 78 DCHECK(OnOriginThread()); | |
| 79 | |
| 80 // Create a request slot for this proxy resolution request. | |
| 81 Request* request = new Request(source_url); | |
| 82 request->notify_task_ = base::Bind( | |
| 83 &ProxyResolverImpl::NotifyProxyResolved, | |
| 84 weak_ptr_factory_.GetWeakPtr(), | |
| 85 signal_interface, | |
| 86 signal_name, | |
| 87 exported_object, | |
| 88 request); | |
| 89 all_requests_.insert(request); | |
| 90 | |
| 91 // GetRequestContext() must be called on UI thread. | |
| 92 scoped_refptr<net::URLRequestContextGetter> getter = | |
| 93 delegate_->GetRequestContext(); | |
| 94 | |
| 95 getter->GetNetworkTaskRunner()->PostTask( | |
| 96 FROM_HERE, | |
| 97 base::Bind(&ProxyResolverImpl::ResolveProxyInternal, | |
| 98 request, | |
| 99 origin_thread_, | |
| 100 getter, | |
| 101 exported_object)); | |
| 102 } | |
| 103 | 38 |
| 104 private: | 39 private: |
| 105 // Helper function for ResolveProxy(). | 40 // Data being used in one proxy resolution. |
| 106 static void ResolveProxyInternal( | 41 struct Request { |
| 107 Request* request, | 42 public: |
| 108 scoped_refptr<base::SingleThreadTaskRunner> origin_thread, | 43 Request(const std::string& source_url, |
| 109 scoped_refptr<net::URLRequestContextGetter> getter, | 44 const std::string& signal_interface, |
| 110 scoped_refptr<dbus::ExportedObject> exported_object) { | 45 const std::string& signal_name, |
| 111 // Make sure we're running on IO thread. | 46 scoped_refptr<dbus::ExportedObject> exported_object, |
| 112 DCHECK(getter->GetNetworkTaskRunner()->BelongsToCurrentThread()); | 47 scoped_refptr<net::URLRequestContextGetter> context_getter) |
| 48 : source_url(source_url), | |
| 49 signal_interface(signal_interface), | |
| 50 signal_name(signal_name), | |
| 51 exported_object(exported_object), | |
| 52 context_getter(context_getter) {} | |
| 53 ~Request() = default; | |
| 113 | 54 |
| 114 // Check if we have the URLRequestContextGetter. | 55 // URL being resolved. |
| 115 if (!getter.get()) { | 56 const std::string source_url; |
| 116 request->error_ = "No URLRequestContextGetter"; | |
| 117 request->OnCompletion(origin_thread, net::ERR_UNEXPECTED); | |
| 118 return; | |
| 119 } | |
| 120 | 57 |
| 121 // Retrieve ProxyService from profile's request context. | 58 // D-Bus interface, name, and object for emitting result signal after |
| 122 net::ProxyService* proxy_service = | 59 // resolution is complete. |
| 123 getter->GetURLRequestContext()->proxy_service(); | 60 const std::string signal_interface; |
| 124 if (!proxy_service) { | 61 const std::string signal_name; |
| 125 request->error_ = "No proxy service in chrome"; | 62 const scoped_refptr<dbus::ExportedObject> exported_object; |
| 126 request->OnCompletion(origin_thread, net::ERR_UNEXPECTED); | |
| 127 return; | |
| 128 } | |
| 129 | 63 |
| 130 VLOG(1) << "Starting network proxy resolution for " | 64 // Used to get the network context associated with the profile used to run |
| 131 << request->source_url_; | 65 // this request. |
| 132 net::CompletionCallback completion_callback = | 66 const scoped_refptr<net::URLRequestContextGetter> context_getter; |
| 133 base::Bind(&Request::OnCompletion, | |
| 134 base::Unretained(request), | |
| 135 origin_thread); | |
| 136 const int result = proxy_service->ResolveProxy( | |
| 137 GURL(request->source_url_), std::string(), &request->proxy_info_, | |
| 138 completion_callback, NULL, NULL, net::NetLogWithSource()); | |
| 139 if (result != net::ERR_IO_PENDING) { | |
| 140 VLOG(1) << "Network proxy resolution completed synchronously."; | |
| 141 completion_callback.Run(result); | |
| 142 } | |
| 143 } | |
| 144 | 67 |
| 145 // Called on UI thread as task posted from Request::OnCompletion on IO | 68 // ProxyInfo resolved for |source_url|. |
| 146 // thread. | 69 net::ProxyInfo proxy_info; |
| 147 void NotifyProxyResolved( | |
| 148 const std::string& signal_interface, | |
| 149 const std::string& signal_name, | |
| 150 scoped_refptr<dbus::ExportedObject> exported_object, | |
| 151 Request* request) { | |
| 152 DCHECK(OnOriginThread()); | |
| 153 | 70 |
| 154 // Send a signal to the client. | 71 // Error from proxy resolution. |
| 155 dbus::Signal signal(signal_interface, signal_name); | 72 std::string error; |
| 156 dbus::MessageWriter writer(&signal); | |
| 157 writer.AppendString(request->source_url_); | |
| 158 writer.AppendString(request->proxy_info_.ToPacString()); | |
| 159 writer.AppendString(request->error_); | |
| 160 exported_object->SendSignal(&signal); | |
| 161 VLOG(1) << "Sending signal: " << signal.ToString(); | |
| 162 | 73 |
| 163 std::set<Request*>::iterator iter = all_requests_.find(request); | 74 private: |
| 164 if (iter == all_requests_.end()) { | 75 DISALLOW_COPY_AND_ASSIGN(Request); |
| 165 LOG(ERROR) << "can't find request slot(" << request->source_url_ | 76 }; |
| 166 << ") in proxy-resolution queue"; | |
| 167 } else { | |
| 168 all_requests_.erase(iter); | |
| 169 } | |
| 170 delete request; | |
| 171 } | |
| 172 | 77 |
| 173 // Returns true if the current thread is on the origin thread. | 78 // Returns true if the current thread is on the origin thread. |
| 174 bool OnOriginThread() { | 79 bool OnOriginThread() { return origin_thread_->BelongsToCurrentThread(); } |
| 175 return origin_thread_->BelongsToCurrentThread(); | 80 |
| 176 } | 81 // Helper method for ResolveProxy() that runs on network thread. |
| 82 void ResolveProxyOnNetworkThread(std::unique_ptr<Request> request); | |
| 83 | |
| 84 // Callback on network thread for when net::ProxyService::ResolveProxy() | |
| 85 // completes, synchronously or asynchronously. | |
| 86 void OnResolutionComplete(std::unique_ptr<Request> request, int result); | |
| 87 | |
| 88 // Called on UI thread from OnResolutionCompletion() to pass the resolved | |
| 89 // proxy information to the client over D-Bus. | |
| 90 void NotifyProxyResolved(std::unique_ptr<Request> request); | |
| 177 | 91 |
| 178 std::unique_ptr<ProxyResolverDelegate> delegate_; | 92 std::unique_ptr<ProxyResolverDelegate> delegate_; |
| 179 scoped_refptr<base::SingleThreadTaskRunner> origin_thread_; | 93 scoped_refptr<base::SingleThreadTaskRunner> origin_thread_; |
| 180 std::set<Request*> all_requests_; | |
| 181 base::WeakPtrFactory<ProxyResolverImpl> weak_ptr_factory_; | 94 base::WeakPtrFactory<ProxyResolverImpl> weak_ptr_factory_; |
| 182 | 95 |
| 183 DISALLOW_COPY_AND_ASSIGN(ProxyResolverImpl); | 96 DISALLOW_COPY_AND_ASSIGN(ProxyResolverImpl); |
| 184 }; | 97 }; |
| 185 | 98 |
| 99 ProxyResolverImpl::ProxyResolverImpl( | |
| 100 std::unique_ptr<ProxyResolverDelegate> delegate) | |
| 101 : delegate_(std::move(delegate)), | |
| 102 origin_thread_(base::ThreadTaskRunnerHandle::Get()), | |
| 103 weak_ptr_factory_(this) {} | |
| 104 | |
| 105 ProxyResolverImpl::~ProxyResolverImpl() { | |
| 106 DCHECK(OnOriginThread()); | |
| 107 } | |
| 108 | |
| 109 void ProxyResolverImpl::ResolveProxy( | |
| 110 const std::string& source_url, | |
| 111 const std::string& signal_interface, | |
| 112 const std::string& signal_name, | |
| 113 scoped_refptr<dbus::ExportedObject> exported_object) { | |
| 114 DCHECK(OnOriginThread()); | |
| 115 | |
| 116 auto request = base::MakeUnique<Request>(source_url, signal_interface, | |
| 117 signal_name, exported_object, | |
| 118 delegate_->GetRequestContext()); | |
| 119 | |
| 120 // This would ideally call PostTaskAndReply() instead of PostTask(), but | |
| 121 // ResolveProxyOnNetworkThread()'s call to net::ProxyService::ResolveProxy() | |
| 122 // can result in an asynchronous lookup, in which case the result won't be | |
| 123 // available immediately. | |
| 124 request->context_getter->GetNetworkTaskRunner()->PostTask( | |
|
Daniel Erat
2017/03/22 21:35:59
whoops, introduced a bug here (dereferencing |requ
| |
| 125 FROM_HERE, base::Bind(&ProxyResolverImpl::ResolveProxyOnNetworkThread, | |
| 126 weak_ptr_factory_.GetWeakPtr(), | |
| 127 base::Passed(std::move(request)))); | |
| 128 } | |
| 129 | |
| 130 void ProxyResolverImpl::ResolveProxyOnNetworkThread( | |
| 131 std::unique_ptr<Request> request) { | |
| 132 DCHECK(request->context_getter->GetNetworkTaskRunner() | |
| 133 ->BelongsToCurrentThread()); | |
| 134 | |
| 135 net::ProxyService* proxy_service = | |
| 136 request->context_getter->GetURLRequestContext()->proxy_service(); | |
| 137 if (!proxy_service) { | |
| 138 request->error = "No proxy service in chrome"; | |
| 139 OnResolutionComplete(std::move(request), net::ERR_UNEXPECTED); | |
| 140 return; | |
| 141 } | |
| 142 | |
| 143 Request* request_ptr = request.get(); | |
| 144 net::CompletionCallback callback = base::Bind( | |
| 145 &ProxyResolverImpl::OnResolutionComplete, weak_ptr_factory_.GetWeakPtr(), | |
| 146 base::Passed(std::move(request))); | |
| 147 | |
| 148 VLOG(1) << "Starting network proxy resolution for " | |
| 149 << request_ptr->source_url; | |
| 150 const int result = proxy_service->ResolveProxy( | |
| 151 GURL(request_ptr->source_url), std::string(), &request_ptr->proxy_info, | |
| 152 callback, nullptr, nullptr, net::NetLogWithSource()); | |
| 153 if (result != net::ERR_IO_PENDING) { | |
| 154 VLOG(1) << "Network proxy resolution completed synchronously."; | |
| 155 callback.Run(result); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 void ProxyResolverImpl::OnResolutionComplete(std::unique_ptr<Request> request, | |
| 160 int result) { | |
| 161 DCHECK(request->context_getter->GetNetworkTaskRunner() | |
| 162 ->BelongsToCurrentThread()); | |
| 163 | |
| 164 if (request->error.empty() && result != net::OK) | |
| 165 request->error = net::ErrorToString(result); | |
| 166 | |
| 167 origin_thread_->PostTask(FROM_HERE, | |
| 168 base::Bind(&ProxyResolverImpl::NotifyProxyResolved, | |
| 169 weak_ptr_factory_.GetWeakPtr(), | |
| 170 base::Passed(std::move(request)))); | |
| 171 } | |
| 172 | |
| 173 void ProxyResolverImpl::NotifyProxyResolved(std::unique_ptr<Request> request) { | |
| 174 DCHECK(OnOriginThread()); | |
| 175 | |
| 176 // Send a signal to the client. | |
| 177 dbus::Signal signal(request->signal_interface, request->signal_name); | |
| 178 dbus::MessageWriter writer(&signal); | |
| 179 writer.AppendString(request->source_url); | |
| 180 writer.AppendString(request->proxy_info.ToPacString()); | |
| 181 writer.AppendString(request->error); | |
| 182 request->exported_object->SendSignal(&signal); | |
| 183 VLOG(1) << "Sending signal: " << signal.ToString(); | |
| 184 } | |
| 185 | |
| 186 } // namespace | |
| 187 | |
| 186 ProxyResolutionServiceProvider::ProxyResolutionServiceProvider( | 188 ProxyResolutionServiceProvider::ProxyResolutionServiceProvider( |
| 187 ProxyResolverInterface* resolver) | 189 ProxyResolverInterface* resolver) |
| 188 : resolver_(resolver), | 190 : resolver_(resolver), |
| 189 origin_thread_(base::ThreadTaskRunnerHandle::Get()), | 191 origin_thread_(base::ThreadTaskRunnerHandle::Get()), |
| 190 weak_ptr_factory_(this) { | 192 weak_ptr_factory_(this) { |
| 191 } | 193 } |
| 192 | 194 |
| 193 ProxyResolutionServiceProvider::~ProxyResolutionServiceProvider() { | 195 ProxyResolutionServiceProvider::~ProxyResolutionServiceProvider() = default; |
| 194 } | |
| 195 | 196 |
| 196 void ProxyResolutionServiceProvider::Start( | 197 void ProxyResolutionServiceProvider::Start( |
| 197 scoped_refptr<dbus::ExportedObject> exported_object) { | 198 scoped_refptr<dbus::ExportedObject> exported_object) { |
| 198 DCHECK(OnOriginThread()); | 199 DCHECK(OnOriginThread()); |
| 199 exported_object_ = exported_object; | 200 exported_object_ = exported_object; |
| 200 VLOG(1) << "ProxyResolutionServiceProvider started"; | 201 VLOG(1) << "ProxyResolutionServiceProvider started"; |
| 201 exported_object_->ExportMethod( | 202 exported_object_->ExportMethod( |
| 202 kLibCrosServiceInterface, | 203 kLibCrosServiceInterface, |
| 203 kResolveNetworkProxy, | 204 kResolveNetworkProxy, |
| 204 // Weak pointers can only bind to methods without return values, | 205 // Weak pointers can only bind to methods without return values, |
| 205 // hence we cannot bind ResolveProxyInternal here. Instead we use a | 206 // hence we cannot bind ResolveProxyInternal here. Instead we use a |
| 206 // static function to solve this problem. | 207 // static function to solve this problem. |
| 207 base::Bind(&ProxyResolutionServiceProvider::CallResolveProxyHandler, | 208 base::Bind(&ProxyResolutionServiceProvider::CallResolveProxyHandler, |
| 208 weak_ptr_factory_.GetWeakPtr()), | 209 weak_ptr_factory_.GetWeakPtr()), |
| 209 base::Bind(&ProxyResolutionServiceProvider::OnExported, | 210 base::Bind(&ProxyResolutionServiceProvider::OnExported, |
| 210 weak_ptr_factory_.GetWeakPtr())); | 211 weak_ptr_factory_.GetWeakPtr())); |
| 211 } | 212 } |
| 212 | 213 |
| 213 void ProxyResolutionServiceProvider::OnExported( | 214 void ProxyResolutionServiceProvider::OnExported( |
| 214 const std::string& interface_name, | 215 const std::string& interface_name, |
| 215 const std::string& method_name, | 216 const std::string& method_name, |
| 216 bool success) { | 217 bool success) { |
| 217 if (!success) { | 218 if (!success) { |
| 218 LOG(ERROR) << "Failed to export " << interface_name << "." | 219 LOG(ERROR) << "Failed to export " << interface_name << "." |
| 219 << method_name; | 220 << method_name; |
| 221 } else { | |
| 222 VLOG(1) << "Method exported: " << interface_name << "." << method_name; | |
| 220 } | 223 } |
| 221 VLOG(1) << "Method exported: " << interface_name << "." << method_name; | |
| 222 } | 224 } |
| 223 | 225 |
| 224 bool ProxyResolutionServiceProvider::OnOriginThread() { | 226 bool ProxyResolutionServiceProvider::OnOriginThread() { |
| 225 return origin_thread_->BelongsToCurrentThread(); | 227 return origin_thread_->BelongsToCurrentThread(); |
| 226 } | 228 } |
| 227 | 229 |
| 228 void ProxyResolutionServiceProvider::ResolveProxyHandler( | 230 void ProxyResolutionServiceProvider::ResolveProxyHandler( |
| 229 dbus::MethodCall* method_call, | 231 dbus::MethodCall* method_call, |
| 230 dbus::ExportedObject::ResponseSender response_sender) { | 232 dbus::ExportedObject::ResponseSender response_sender) { |
| 231 DCHECK(OnOriginThread()); | 233 DCHECK(OnOriginThread()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 } | 267 } |
| 266 provider_weak_ptr->ResolveProxyHandler(method_call, response_sender); | 268 provider_weak_ptr->ResolveProxyHandler(method_call, response_sender); |
| 267 } | 269 } |
| 268 | 270 |
| 269 ProxyResolutionServiceProvider* ProxyResolutionServiceProvider::Create( | 271 ProxyResolutionServiceProvider* ProxyResolutionServiceProvider::Create( |
| 270 std::unique_ptr<ProxyResolverDelegate> delegate) { | 272 std::unique_ptr<ProxyResolverDelegate> delegate) { |
| 271 return new ProxyResolutionServiceProvider( | 273 return new ProxyResolutionServiceProvider( |
| 272 new ProxyResolverImpl(std::move(delegate))); | 274 new ProxyResolverImpl(std::move(delegate))); |
| 273 } | 275 } |
| 274 | 276 |
| 275 ProxyResolverInterface::~ProxyResolverInterface() { | 277 ProxyResolverInterface::~ProxyResolverInterface() = default; |
| 276 } | |
| 277 | 278 |
| 278 } // namespace chromeos | 279 } // namespace chromeos |
| OLD | NEW |