Home | History | Annotate | Download | only in cros
      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);
     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 
    108 LibCrosServiceLibraryImpl::LibCrosServiceLibraryImpl()
    109     : service_connection_(NULL) {
    110   if (!CrosLibrary::Get()->EnsureLoaded()) {
    111     LOG(ERROR) << "Cros library has not been loaded.";
    112   }
    113 }
    114 
    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.
    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 
    152 LibCrosServiceLibraryImpl::ServicingLibrary::ServicingLibrary(
    153     LibCrosServiceConnection connection)
    154     : service_connection_(connection) {
    155 }
    156 
    157 LibCrosServiceLibraryImpl::ServicingLibrary::~ServicingLibrary() {
    158   ClearServiceConnection();
    159 }
    160 
    161 void LibCrosServiceLibraryImpl::ServicingLibrary::ClearServiceConnection() {
    162   base::AutoLock lock(data_lock_);
    163   service_connection_ = NULL;
    164 }
    165 
    166 //----------- LibCrosServiceLibraryImpl::NetworkProxyLibrary: public -----------
    167 
    168 LibCrosServiceLibraryImpl::NetworkProxyLibrary::NetworkProxyLibrary(
    169     LibCrosServiceConnection connection)
    170     : ServicingLibrary(connection) {
    171   // Register callback for LibCrosService::ResolveNetworkProxy.
    172   SetNetworkProxyResolver(&ResolveProxyHandler, this, service_connection_);
    173 }
    174 
    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.
    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.
    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.
    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 
    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.
    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:
    290   LibCrosServiceLibraryStubImpl() {}
    291   virtual ~LibCrosServiceLibraryStubImpl() {}
    292 
    293   // LibCrosServiceLibrary overrides.
    294   virtual void StartService() {}
    295 
    296   DISALLOW_COPY_AND_ASSIGN(LibCrosServiceLibraryStubImpl);
    297 };
    298 
    299 //--------------------------- LibCrosServiceLibrary ----------------------------
    300 
    301 // Static.
    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