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> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.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 | 24 |
| 25 // The ProxyResolverInterface implementation used in production. | 25 // The ProxyResolverInterface implementation used in production. |
| 26 class ProxyResolverImpl : public ProxyResolverInterface { | 26 class ProxyResolverImpl : public ProxyResolverInterface { |
| 27 public: | 27 public: |
| 28 // Data being used in one proxy resolution. | 28 // Data being used in one proxy resolution. |
| 29 class Request { | 29 // This would ideally be bound to callbacks as a std::unique_ptr<Request> and |
| 30 // passed around as long as it's needed instead of being ref-counted, but we | |
| 31 // don't know whether the callback will be run or not when calling | |
| 32 // net::ProxyService::ResolveProxy(): if the proxy can be resolved | |
| 33 // synchronously, it won't be, and we don't want to lose ownership of the | |
|
satorux1
2017/03/22 04:04:02
I'm confused. Even if it's completed synchronously
Daniel Erat
2017/03/22 05:07:23
sorry if the comment is unclear. i meant that net:
| |
| 34 // Request object in that case. | |
|
Daniel Erat
2017/03/22 00:54:00
i initially considered binding base::WeakPtr<Reque
| |
| 35 // TODO(derat): Why is this class public? Make it private. | |
| 36 class Request : public base::RefCountedThreadSafe<Request> { | |
| 30 public: | 37 public: |
| 31 explicit Request(const std::string& source_url) : source_url_(source_url) { | 38 Request(const std::string& source_url, |
| 32 } | 39 const std::string& signal_interface, |
| 33 | 40 const std::string& signal_name, |
| 34 virtual ~Request() {} | 41 scoped_refptr<dbus::ExportedObject> exported_object, |
| 42 scoped_refptr<net::URLRequestContextGetter> context_getter, | |
| 43 base::Callback<void(scoped_refptr<Request>)> notify_task, | |
| 44 scoped_refptr<base::SingleThreadTaskRunner> notify_thread) | |
| 45 : source_url_(source_url), | |
| 46 signal_interface_(signal_interface), | |
| 47 signal_name_(signal_name), | |
| 48 exported_object_(exported_object), | |
| 49 context_getter_(context_getter), | |
| 50 notify_task_(notify_task), | |
|
Daniel Erat
2017/03/22 00:54:00
note that members like this one should be unnecess
| |
| 51 notify_thread_(notify_thread) {} | |
| 35 | 52 |
| 36 // Callback on IO thread for when net::ProxyService::ResolveProxy | 53 // Callback on IO thread for when net::ProxyService::ResolveProxy |
| 37 // completes, synchronously or asynchronously. | 54 // completes, synchronously or asynchronously. |
| 38 void OnCompletion(scoped_refptr<base::SingleThreadTaskRunner> origin_thread, | 55 void OnCompletion(int result) { |
| 39 int result) { | |
| 40 // Generate the error message if the error message is not yet set, | 56 // Generate the error message if the error message is not yet set, |
| 41 // and there was an error. | 57 // and there was an error. |
| 42 if (error_.empty() && result != net::OK) | 58 if (error_.empty() && result != net::OK) |
| 43 error_ = net::ErrorToString(result); | 59 error_ = net::ErrorToString(result); |
| 44 origin_thread->PostTask(FROM_HERE, notify_task_); | 60 notify_thread_->PostTask( |
| 61 FROM_HERE, base::Bind(notify_task_, scoped_refptr<Request>(this))); | |
| 45 } | 62 } |
| 46 | 63 |
| 47 std::string source_url_; // URL being resolved. | 64 // URL being resolved. |
| 48 net::ProxyInfo proxy_info_; // ProxyInfo resolved for source_url_. | 65 const std::string source_url_; |
| 49 std::string error_; // Error from proxy resolution. | 66 |
| 50 base::Closure notify_task_; // Task to notify of resolution result. | 67 // D-Bus interface, name, and object for emitting result signal after |
| 68 // resolution is complete. | |
| 69 const std::string signal_interface_; | |
| 70 const std::string signal_name_; | |
| 71 const scoped_refptr<dbus::ExportedObject> exported_object_; | |
| 72 | |
| 73 // Used to get network context. | |
| 74 const scoped_refptr<net::URLRequestContextGetter> context_getter_; | |
| 75 | |
| 76 // Task to notify of resolution result and task runner to post it to. | |
| 77 const base::Callback<void(scoped_refptr<Request>)> notify_task_; | |
| 78 const scoped_refptr<base::SingleThreadTaskRunner> notify_thread_; | |
| 79 | |
| 80 // ProxyInfo resolved for |source_url_|. | |
| 81 net::ProxyInfo proxy_info_; | |
| 82 | |
| 83 // Error from proxy resolution. | |
| 84 std::string error_; | |
| 51 | 85 |
| 52 private: | 86 private: |
| 87 friend class base::RefCountedThreadSafe<Request>; | |
| 88 virtual ~Request() = default; | |
| 89 | |
| 53 DISALLOW_COPY_AND_ASSIGN(Request); | 90 DISALLOW_COPY_AND_ASSIGN(Request); |
| 54 }; | 91 }; |
| 55 | 92 |
| 93 // TODO(derat): Consider moving all of this class's implementation apart from | |
| 94 // ResolveProxy() into the Request class. | |
| 56 explicit ProxyResolverImpl(std::unique_ptr<ProxyResolverDelegate> delegate) | 95 explicit ProxyResolverImpl(std::unique_ptr<ProxyResolverDelegate> delegate) |
| 57 : delegate_(std::move(delegate)), | 96 : delegate_(std::move(delegate)), |
| 58 origin_thread_(base::ThreadTaskRunnerHandle::Get()), | 97 origin_thread_(base::ThreadTaskRunnerHandle::Get()), |
| 59 weak_ptr_factory_(this) {} | 98 weak_ptr_factory_(this) {} |
| 60 | 99 |
| 61 ~ProxyResolverImpl() override { | 100 ~ProxyResolverImpl() override { |
| 62 DCHECK(OnOriginThread()); | 101 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 } | 102 } |
| 71 | 103 |
| 72 // ProxyResolverInterface override. | 104 // ProxyResolverInterface override. |
| 73 void ResolveProxy( | 105 void ResolveProxy( |
| 74 const std::string& source_url, | 106 const std::string& source_url, |
| 75 const std::string& signal_interface, | 107 const std::string& signal_interface, |
| 76 const std::string& signal_name, | 108 const std::string& signal_name, |
| 77 scoped_refptr<dbus::ExportedObject> exported_object) override { | 109 scoped_refptr<dbus::ExportedObject> exported_object) override { |
| 78 DCHECK(OnOriginThread()); | 110 DCHECK(OnOriginThread()); |
| 79 | 111 |
| 80 // Create a request slot for this proxy resolution request. | 112 // Create a request slot for this proxy resolution request. |
| 81 Request* request = new Request(source_url); | 113 // GetRequestContext() must be called on UI thread. |
| 82 request->notify_task_ = base::Bind( | 114 scoped_refptr<Request> request = |
| 83 &ProxyResolverImpl::NotifyProxyResolved, | 115 new Request(source_url, signal_interface, signal_name, exported_object, |
| 84 weak_ptr_factory_.GetWeakPtr(), | 116 delegate_->GetRequestContext(), |
| 85 signal_interface, | 117 base::Bind(&ProxyResolverImpl::NotifyProxyResolved, |
| 86 signal_name, | 118 weak_ptr_factory_.GetWeakPtr()), |
| 87 exported_object, | 119 origin_thread_); |
| 88 request); | |
| 89 all_requests_.insert(request); | |
| 90 | 120 |
| 91 // GetRequestContext() must be called on UI thread. | 121 // This would ideally call PostTaskAndReply() instead of PostTask(), but |
| 92 scoped_refptr<net::URLRequestContextGetter> getter = | 122 // ResolveProxyInternal()'s call to net::ProxyService::ResolveProxy() can |
| 93 delegate_->GetRequestContext(); | 123 // result in an asynchronous lookup, in which case the result won't be |
| 94 | 124 // available immediately. |
| 95 getter->GetNetworkTaskRunner()->PostTask( | 125 request->context_getter_->GetNetworkTaskRunner()->PostTask( |
| 96 FROM_HERE, | 126 FROM_HERE, |
| 97 base::Bind(&ProxyResolverImpl::ResolveProxyInternal, | 127 base::Bind(&ProxyResolverImpl::ResolveProxyInternal, request)); |
| 98 request, | |
| 99 origin_thread_, | |
| 100 getter, | |
| 101 exported_object)); | |
| 102 } | 128 } |
| 103 | 129 |
| 104 private: | 130 private: |
| 105 // Helper function for ResolveProxy(). | 131 // Helper function for ResolveProxy(). |
| 106 static void ResolveProxyInternal( | 132 static void ResolveProxyInternal(scoped_refptr<Request> request) { |
| 107 Request* request, | 133 DCHECK(request->context_getter_->GetNetworkTaskRunner() |
| 108 scoped_refptr<base::SingleThreadTaskRunner> origin_thread, | 134 ->BelongsToCurrentThread()); |
| 109 scoped_refptr<net::URLRequestContextGetter> getter, | |
| 110 scoped_refptr<dbus::ExportedObject> exported_object) { | |
| 111 // Make sure we're running on IO thread. | |
| 112 DCHECK(getter->GetNetworkTaskRunner()->BelongsToCurrentThread()); | |
| 113 | 135 |
| 114 // Check if we have the URLRequestContextGetter. | 136 if (!request->context_getter_.get()) { |
| 115 if (!getter.get()) { | |
| 116 request->error_ = "No URLRequestContextGetter"; | 137 request->error_ = "No URLRequestContextGetter"; |
|
Daniel Erat
2017/03/22 00:54:00
i suspect that the old code is susceptible to use-
| |
| 117 request->OnCompletion(origin_thread, net::ERR_UNEXPECTED); | 138 request->OnCompletion(net::ERR_UNEXPECTED); |
| 118 return; | 139 return; |
| 119 } | 140 } |
| 120 | 141 |
| 121 // Retrieve ProxyService from profile's request context. | |
| 122 net::ProxyService* proxy_service = | 142 net::ProxyService* proxy_service = |
| 123 getter->GetURLRequestContext()->proxy_service(); | 143 request->context_getter_->GetURLRequestContext()->proxy_service(); |
| 124 if (!proxy_service) { | 144 if (!proxy_service) { |
| 125 request->error_ = "No proxy service in chrome"; | 145 request->error_ = "No proxy service in chrome"; |
| 126 request->OnCompletion(origin_thread, net::ERR_UNEXPECTED); | 146 request->OnCompletion(net::ERR_UNEXPECTED); |
| 127 return; | 147 return; |
| 128 } | 148 } |
| 129 | 149 |
| 130 VLOG(1) << "Starting network proxy resolution for " | 150 VLOG(1) << "Starting network proxy resolution for " |
| 131 << request->source_url_; | 151 << request->source_url_; |
| 132 net::CompletionCallback completion_callback = | 152 net::CompletionCallback completion_callback = |
| 133 base::Bind(&Request::OnCompletion, | 153 base::Bind(&Request::OnCompletion, request); |
| 134 base::Unretained(request), | |
| 135 origin_thread); | |
| 136 const int result = proxy_service->ResolveProxy( | 154 const int result = proxy_service->ResolveProxy( |
| 137 GURL(request->source_url_), std::string(), &request->proxy_info_, | 155 GURL(request->source_url_), std::string(), &request->proxy_info_, |
| 138 completion_callback, NULL, NULL, net::NetLogWithSource()); | 156 completion_callback, nullptr, nullptr, net::NetLogWithSource()); |
| 139 if (result != net::ERR_IO_PENDING) { | 157 if (result != net::ERR_IO_PENDING) { |
| 140 VLOG(1) << "Network proxy resolution completed synchronously."; | 158 VLOG(1) << "Network proxy resolution completed synchronously."; |
| 141 completion_callback.Run(result); | 159 completion_callback.Run(result); |
| 142 } | 160 } |
| 143 } | 161 } |
| 144 | 162 |
| 145 // Called on UI thread as task posted from Request::OnCompletion on IO | 163 // Called on UI thread as task posted from Request::OnCompletion on network |
| 146 // thread. | 164 // thread. |
| 147 void NotifyProxyResolved( | 165 void NotifyProxyResolved(scoped_refptr<Request> request) { |
| 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()); | 166 DCHECK(OnOriginThread()); |
| 153 | 167 |
| 154 // Send a signal to the client. | 168 // Send a signal to the client. |
| 155 dbus::Signal signal(signal_interface, signal_name); | 169 dbus::Signal signal(request->signal_interface_, request->signal_name_); |
|
Daniel Erat
2017/03/22 00:54:00
moving the implementation into Request will also a
| |
| 156 dbus::MessageWriter writer(&signal); | 170 dbus::MessageWriter writer(&signal); |
| 157 writer.AppendString(request->source_url_); | 171 writer.AppendString(request->source_url_); |
| 158 writer.AppendString(request->proxy_info_.ToPacString()); | 172 writer.AppendString(request->proxy_info_.ToPacString()); |
| 159 writer.AppendString(request->error_); | 173 writer.AppendString(request->error_); |
| 160 exported_object->SendSignal(&signal); | 174 request->exported_object_->SendSignal(&signal); |
| 161 VLOG(1) << "Sending signal: " << signal.ToString(); | 175 VLOG(1) << "Sending signal: " << signal.ToString(); |
| 162 | |
| 163 std::set<Request*>::iterator iter = all_requests_.find(request); | |
| 164 if (iter == all_requests_.end()) { | |
| 165 LOG(ERROR) << "can't find request slot(" << request->source_url_ | |
| 166 << ") in proxy-resolution queue"; | |
| 167 } else { | |
| 168 all_requests_.erase(iter); | |
| 169 } | |
| 170 delete request; | |
| 171 } | 176 } |
| 172 | 177 |
| 173 // Returns true if the current thread is on the origin thread. | 178 // Returns true if the current thread is on the origin thread. |
| 174 bool OnOriginThread() { | 179 bool OnOriginThread() { |
| 175 return origin_thread_->BelongsToCurrentThread(); | 180 return origin_thread_->BelongsToCurrentThread(); |
| 176 } | 181 } |
| 177 | 182 |
| 178 std::unique_ptr<ProxyResolverDelegate> delegate_; | 183 std::unique_ptr<ProxyResolverDelegate> delegate_; |
| 179 scoped_refptr<base::SingleThreadTaskRunner> origin_thread_; | 184 scoped_refptr<base::SingleThreadTaskRunner> origin_thread_; |
| 180 std::set<Request*> all_requests_; | |
| 181 base::WeakPtrFactory<ProxyResolverImpl> weak_ptr_factory_; | 185 base::WeakPtrFactory<ProxyResolverImpl> weak_ptr_factory_; |
| 182 | 186 |
| 183 DISALLOW_COPY_AND_ASSIGN(ProxyResolverImpl); | 187 DISALLOW_COPY_AND_ASSIGN(ProxyResolverImpl); |
| 184 }; | 188 }; |
| 185 | 189 |
| 186 ProxyResolutionServiceProvider::ProxyResolutionServiceProvider( | 190 ProxyResolutionServiceProvider::ProxyResolutionServiceProvider( |
| 187 ProxyResolverInterface* resolver) | 191 ProxyResolverInterface* resolver) |
| 188 : resolver_(resolver), | 192 : resolver_(resolver), |
| 189 origin_thread_(base::ThreadTaskRunnerHandle::Get()), | 193 origin_thread_(base::ThreadTaskRunnerHandle::Get()), |
| 190 weak_ptr_factory_(this) { | 194 weak_ptr_factory_(this) { |
| 191 } | 195 } |
| 192 | 196 |
| 193 ProxyResolutionServiceProvider::~ProxyResolutionServiceProvider() { | 197 ProxyResolutionServiceProvider::~ProxyResolutionServiceProvider() = default; |
| 194 } | |
| 195 | 198 |
| 196 void ProxyResolutionServiceProvider::Start( | 199 void ProxyResolutionServiceProvider::Start( |
| 197 scoped_refptr<dbus::ExportedObject> exported_object) { | 200 scoped_refptr<dbus::ExportedObject> exported_object) { |
| 198 DCHECK(OnOriginThread()); | 201 DCHECK(OnOriginThread()); |
| 199 exported_object_ = exported_object; | 202 exported_object_ = exported_object; |
| 200 VLOG(1) << "ProxyResolutionServiceProvider started"; | 203 VLOG(1) << "ProxyResolutionServiceProvider started"; |
| 201 exported_object_->ExportMethod( | 204 exported_object_->ExportMethod( |
| 202 kLibCrosServiceInterface, | 205 kLibCrosServiceInterface, |
| 203 kResolveNetworkProxy, | 206 kResolveNetworkProxy, |
| 204 // Weak pointers can only bind to methods without return values, | 207 // Weak pointers can only bind to methods without return values, |
| 205 // hence we cannot bind ResolveProxyInternal here. Instead we use a | 208 // hence we cannot bind ResolveProxyInternal here. Instead we use a |
| 206 // static function to solve this problem. | 209 // static function to solve this problem. |
| 207 base::Bind(&ProxyResolutionServiceProvider::CallResolveProxyHandler, | 210 base::Bind(&ProxyResolutionServiceProvider::CallResolveProxyHandler, |
| 208 weak_ptr_factory_.GetWeakPtr()), | 211 weak_ptr_factory_.GetWeakPtr()), |
| 209 base::Bind(&ProxyResolutionServiceProvider::OnExported, | 212 base::Bind(&ProxyResolutionServiceProvider::OnExported, |
| 210 weak_ptr_factory_.GetWeakPtr())); | 213 weak_ptr_factory_.GetWeakPtr())); |
| 211 } | 214 } |
| 212 | 215 |
| 213 void ProxyResolutionServiceProvider::OnExported( | 216 void ProxyResolutionServiceProvider::OnExported( |
| 214 const std::string& interface_name, | 217 const std::string& interface_name, |
| 215 const std::string& method_name, | 218 const std::string& method_name, |
| 216 bool success) { | 219 bool success) { |
| 217 if (!success) { | 220 if (!success) { |
| 218 LOG(ERROR) << "Failed to export " << interface_name << "." | 221 LOG(ERROR) << "Failed to export " << interface_name << "." |
| 219 << method_name; | 222 << method_name; |
| 223 } else { | |
| 224 VLOG(1) << "Method exported: " << interface_name << "." << method_name; | |
| 220 } | 225 } |
| 221 VLOG(1) << "Method exported: " << interface_name << "." << method_name; | |
| 222 } | 226 } |
| 223 | 227 |
| 224 bool ProxyResolutionServiceProvider::OnOriginThread() { | 228 bool ProxyResolutionServiceProvider::OnOriginThread() { |
| 225 return origin_thread_->BelongsToCurrentThread(); | 229 return origin_thread_->BelongsToCurrentThread(); |
| 226 } | 230 } |
| 227 | 231 |
| 228 void ProxyResolutionServiceProvider::ResolveProxyHandler( | 232 void ProxyResolutionServiceProvider::ResolveProxyHandler( |
| 229 dbus::MethodCall* method_call, | 233 dbus::MethodCall* method_call, |
| 230 dbus::ExportedObject::ResponseSender response_sender) { | 234 dbus::ExportedObject::ResponseSender response_sender) { |
| 231 DCHECK(OnOriginThread()); | 235 DCHECK(OnOriginThread()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 } | 269 } |
| 266 provider_weak_ptr->ResolveProxyHandler(method_call, response_sender); | 270 provider_weak_ptr->ResolveProxyHandler(method_call, response_sender); |
| 267 } | 271 } |
| 268 | 272 |
| 269 ProxyResolutionServiceProvider* ProxyResolutionServiceProvider::Create( | 273 ProxyResolutionServiceProvider* ProxyResolutionServiceProvider::Create( |
| 270 std::unique_ptr<ProxyResolverDelegate> delegate) { | 274 std::unique_ptr<ProxyResolverDelegate> delegate) { |
| 271 return new ProxyResolutionServiceProvider( | 275 return new ProxyResolutionServiceProvider( |
| 272 new ProxyResolverImpl(std::move(delegate))); | 276 new ProxyResolverImpl(std::move(delegate))); |
| 273 } | 277 } |
| 274 | 278 |
| 275 ProxyResolverInterface::~ProxyResolverInterface() { | 279 ProxyResolverInterface::~ProxyResolverInterface() = default; |
| 276 } | |
| 277 | 280 |
| 278 } // namespace chromeos | 281 } // namespace chromeos |
| OLD | NEW |