• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/cros/libcros_service_library.h"
6 
7 #include "base/synchronization/lock.h"
8 #include "chrome/browser/chromeos/cros/cros_library.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "content/browser/browser_thread.h"
11 #include "cros/chromeos_libcros_service.h"
12 #include "net/base/net_errors.h"
13 #include "net/proxy/proxy_service.h"
14 #include "net/url_request/url_request_context.h"
15 #include "net/url_request/url_request_context_getter.h"
16 
17 namespace chromeos {
18 
19 class LibCrosServiceLibraryImpl : public LibCrosServiceLibrary {
20  public:
21   // Base class for all services of LibCrosService.
22   // Each subclass should declare DISABLE_RUNNABLE_METHOD_REFCOUNT to disable
23   // refcounting, which is okay since the subclass's object will exist as a
24   // scoped_ptr in Singleton LibCrosServiceLibraryImpl, guaranteeing that its
25   // lifetime is longer than that of any message loop.
26   class ServicingLibrary {
27    public:
28     explicit ServicingLibrary(LibCrosServiceConnection service_connection);
29     virtual ~ServicingLibrary();
30 
31     // Clears service_connection_ (which is stored as weak pointer) so that it
32     // can't be used anymore.
33     virtual void ClearServiceConnection();
34 
35    protected:
36     LibCrosServiceConnection service_connection_;  // Weak pointer.
37     // Lock for data members to synchronize access on multiple threads.
38     base::Lock data_lock_;
39 
40    private:
41     DISALLOW_COPY_AND_ASSIGN(ServicingLibrary);
42   };
43 
44   // Library that provides network proxy service for LibCrosService.
45   // For now, it only processes proxy resolution requests for ChromeOS clients.
46   class NetworkProxyLibrary : public ServicingLibrary {
47    public:
48     explicit NetworkProxyLibrary(LibCrosServiceConnection connection);
49     virtual ~NetworkProxyLibrary();
50 
51    private:
52     // Data being used in one proxy resolution.
53     class Request {
54      public:
55       explicit Request(const std::string& source_url);
~Request()56       virtual ~Request() {}
57 
58       // Callback on IO thread for when net::ProxyService::ResolveProxy
59       // completes, synchronously or asynchronously.
60       void OnCompletion(int result);
61       net::CompletionCallbackImpl<Request> completion_callback_;
62 
63       std::string source_url_;  // URL being resolved.
64       int result_;  // Result of proxy resolution.
65       net::ProxyInfo proxy_info_;  // ProxyInfo resolved for source_url_.
66       std::string error_;  // Error from proxy resolution.
67       Task* notify_task_;  // Task to notify of resolution result.
68 
69      private:
70       DISALLOW_COPY_AND_ASSIGN(Request);
71     };
72 
73     // Static callback passed to LibCrosService to be invoked when ChromeOS
74     // clients send network proxy resolution requests to the service running in
75     // chrome executable.  Called on UI thread from dbus request.
76     static void ResolveProxyHandler(void* object, const char* source_url);
77 
78     void ResolveProxy(const std::string& source_url);
79 
80     // Wrapper on UI thread to call LibCrosService::NotifyNetworkProxyResolved.
81     void NotifyProxyResolved(Request* request);
82 
83     std::vector<Request*> all_requests_;
84 
85     DISALLOW_COPY_AND_ASSIGN(NetworkProxyLibrary);
86   };
87 
88   LibCrosServiceLibraryImpl();
89   virtual ~LibCrosServiceLibraryImpl();
90 
91   // LibCrosServiceLibrary implementation.
92 
93   // Starts LibCrosService running on dbus if not already started.
94   virtual void StartService();
95 
96  private:
97   // Connection to LibCrosService.
98   LibCrosServiceConnection service_connection_;
99 
100   // Libraries that form LibCrosService.
101   scoped_ptr<NetworkProxyLibrary> network_proxy_lib_;
102 
103   DISALLOW_COPY_AND_ASSIGN(LibCrosServiceLibraryImpl);
104 };
105 
106 //---------------- LibCrosServiceLibraryImpl: public ---------------------------
107 
LibCrosServiceLibraryImpl()108 LibCrosServiceLibraryImpl::LibCrosServiceLibraryImpl()
109     : service_connection_(NULL) {
110   if (!CrosLibrary::Get()->EnsureLoaded()) {
111     LOG(ERROR) << "Cros library has not been loaded.";
112   }
113 }
114 
~LibCrosServiceLibraryImpl()115 LibCrosServiceLibraryImpl::~LibCrosServiceLibraryImpl() {
116   if (service_connection_) {
117     // Clear service connections in servicing libraries which held the former
118     // as weak pointers.
119     if (network_proxy_lib_.get())
120       network_proxy_lib_->ClearServiceConnection();
121 
122     StopLibCrosService(service_connection_);
123     VLOG(1) << "LibCrosService stopped.";
124     service_connection_ = NULL;
125   }
126 }
127 
128 // Called on UI thread to start service for LibCrosService.
StartService()129 void LibCrosServiceLibraryImpl::StartService() {
130   // Make sure we're running on UI thread.
131   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
132     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
133         NewRunnableMethod(this,
134                           &LibCrosServiceLibraryImpl::StartService));
135     return;
136   }
137   if (service_connection_)  // Service has already been started.
138     return;
139   // Starts LibCrosService; the returned connection is used for future
140   // interactions with the service.
141   service_connection_ = StartLibCrosService();
142   if (!service_connection_) {
143     LOG(WARNING) << "Error starting LibCrosService";
144     return;
145   }
146   network_proxy_lib_.reset(new NetworkProxyLibrary(service_connection_));
147   VLOG(1) << "LibCrosService started.";
148 }
149 
150 //------------- LibCrosServiceLibraryImpl::ServicingLibrary: public ------------
151 
ServicingLibrary(LibCrosServiceConnection connection)152 LibCrosServiceLibraryImpl::ServicingLibrary::ServicingLibrary(
153     LibCrosServiceConnection connection)
154     : service_connection_(connection) {
155 }
156 
~ServicingLibrary()157 LibCrosServiceLibraryImpl::ServicingLibrary::~ServicingLibrary() {
158   ClearServiceConnection();
159 }
160 
ClearServiceConnection()161 void LibCrosServiceLibraryImpl::ServicingLibrary::ClearServiceConnection() {
162   base::AutoLock lock(data_lock_);
163   service_connection_ = NULL;
164 }
165 
166 //----------- LibCrosServiceLibraryImpl::NetworkProxyLibrary: public -----------
167 
NetworkProxyLibrary(LibCrosServiceConnection connection)168 LibCrosServiceLibraryImpl::NetworkProxyLibrary::NetworkProxyLibrary(
169     LibCrosServiceConnection connection)
170     : ServicingLibrary(connection) {
171   // Register callback for LibCrosService::ResolveNetworkProxy.
172   SetNetworkProxyResolver(&ResolveProxyHandler, this, service_connection_);
173 }
174 
~NetworkProxyLibrary()175 LibCrosServiceLibraryImpl::NetworkProxyLibrary::~NetworkProxyLibrary() {
176   base::AutoLock lock(data_lock_);
177   if (!all_requests_.empty()) {
178     for (size_t i = all_requests_.size() - 1;  i >= 0; --i) {
179       LOG(WARNING) << "Pending request for " << all_requests_[i]->source_url_;
180       delete all_requests_[i];
181     }
182     all_requests_.clear();
183   }
184 }
185 
186 //----------- LibCrosServiceLibraryImpl::NetworkProxyLibrary: private ----------
187 
188 // Static, called on UI thread from LibCrosService::ResolveProxy via dbus.
ResolveProxyHandler(void * object,const char * source_url)189 void LibCrosServiceLibraryImpl::NetworkProxyLibrary::ResolveProxyHandler(
190     void* object, const char* source_url) {
191   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192   NetworkProxyLibrary* lib = static_cast<NetworkProxyLibrary*>(object);
193   // source_url will be freed when this function returns, so make a copy of it.
194   std::string url(source_url);
195   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
196       NewRunnableMethod(lib, &NetworkProxyLibrary::ResolveProxy, url));
197 }
198 
199 // Called on IO thread as task posted from ResolveProxyHandler on UI thread.
ResolveProxy(const std::string & source_url)200 void LibCrosServiceLibraryImpl::NetworkProxyLibrary::ResolveProxy(
201     const std::string& source_url) {
202   // Make sure we're running on IO thread.
203   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
204 
205   // Create a request slot for this proxy resolution request.
206   Request* request = new Request(source_url);
207   request->notify_task_ = NewRunnableMethod(this,
208       &NetworkProxyLibrary::NotifyProxyResolved, request);
209 
210   // Retrieve ProxyService from profile's request context.
211   net::URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
212   net::ProxyService* proxy_service = NULL;
213   if (getter)
214     proxy_service = getter->GetURLRequestContext()->proxy_service();
215 
216   // Check that we have valid proxy service and service_connection.
217   if (!proxy_service) {
218      request->error_ = "No proxy service in chrome";
219   } else {
220     base::AutoLock lock(data_lock_);
221     // Queue request slot.
222     all_requests_.push_back(request);
223     if (!service_connection_)
224       request->error_ = "LibCrosService not started";
225   }
226   if (request->error_ != "") {  // Error string was just set.
227     LOG(ERROR) << request->error_;
228     request->result_ = net::OK;  // Set to OK since error string is set.
229   } else {
230     VLOG(1) << "Starting networy proxy resolution for " << request->source_url_;
231     request->result_ = proxy_service->ResolveProxy(
232         GURL(request->source_url_), &request->proxy_info_,
233         &request->completion_callback_, NULL, net::BoundNetLog());
234   }
235   if (request->result_ != net::ERR_IO_PENDING) {
236     VLOG(1) << "Network proxy resolution completed synchronously.";
237     request->OnCompletion(request->result_);
238   }
239 }
240 
241 // Called on UI thread as task posted from Request::OnCompletion on IO thread.
NotifyProxyResolved(Request * request)242 void LibCrosServiceLibraryImpl::NetworkProxyLibrary::NotifyProxyResolved(
243     Request* request) {
244   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
245   base::AutoLock lock(data_lock_);
246   if (service_connection_) {
247     if (!NotifyNetworkProxyResolved(request->source_url_.c_str(),
248                                     request->proxy_info_.ToPacString().c_str(),
249                                     request->error_.c_str(),
250                                     service_connection_)) {
251       LOG(ERROR) << "LibCrosService has error with NotifyNetworkProxyResolved";
252     } else {
253       VLOG(1) << "LibCrosService has notified proxy resoloution for "
254               << request->source_url_;
255     }
256   }
257   std::vector<Request*>::iterator iter =
258       std::find(all_requests_.begin(), all_requests_.end(), request);
259   DCHECK(iter != all_requests_.end());
260   all_requests_.erase(iter);
261   delete request;
262 }
263 
264 //---------- LibCrosServiceLibraryImpl::NetworkProxyLibrary::Request -----------
265 
Request(const std::string & source_url)266 LibCrosServiceLibraryImpl::NetworkProxyLibrary::Request::Request(
267     const std::string& source_url)
268     : ALLOW_THIS_IN_INITIALIZER_LIST(
269           completion_callback_(this, &Request::OnCompletion)),
270       source_url_(source_url),
271       result_(net::ERR_FAILED),
272       notify_task_(NULL) {
273 }
274 
275 // Called on IO thread when net::ProxyService::ResolveProxy has completed.
OnCompletion(int result)276 void LibCrosServiceLibraryImpl::NetworkProxyLibrary::Request::OnCompletion(
277     int result) {
278   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
279   result_ = result;
280   if (result_ != net::OK)
281     error_ = net::ErrorToString(result_);
282   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, notify_task_);
283   notify_task_ = NULL;
284 }
285 
286 //--------------------- LibCrosServiceLibraryStubImpl --------------------------
287 
288 class LibCrosServiceLibraryStubImpl : public LibCrosServiceLibrary {
289  public:
LibCrosServiceLibraryStubImpl()290   LibCrosServiceLibraryStubImpl() {}
~LibCrosServiceLibraryStubImpl()291   virtual ~LibCrosServiceLibraryStubImpl() {}
292 
293   // LibCrosServiceLibrary overrides.
StartService()294   virtual void StartService() {}
295 
296   DISALLOW_COPY_AND_ASSIGN(LibCrosServiceLibraryStubImpl);
297 };
298 
299 //--------------------------- LibCrosServiceLibrary ----------------------------
300 
301 // Static.
GetImpl(bool stub)302 LibCrosServiceLibrary* LibCrosServiceLibrary::GetImpl(bool stub) {
303   if (stub)
304     return new LibCrosServiceLibraryStubImpl();
305   return new LibCrosServiceLibraryImpl();
306 }
307 
308 }  // namespace chromeos
309 
310 // Allows InvokeLater without adding refcounting. This class is a Singleton and
311 // won't be deleted until it's last InvokeLater is run, so are all its
312 // scoped_ptred class members.
313 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::LibCrosServiceLibraryImpl);
314 DISABLE_RUNNABLE_METHOD_REFCOUNT(
315     chromeos::LibCrosServiceLibraryImpl::NetworkProxyLibrary);
316 
317