Home | History | Annotate | Download | only in net
      1 // Copyright 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 #ifndef SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
      6 #define SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
      7 
      8 #include <iosfwd>
      9 #include <string>
     10 
     11 #include "base/atomicops.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/observer_list.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/synchronization/lock.h"
     16 #include "base/threading/non_thread_safe.h"
     17 #include "base/threading/thread_checker.h"
     18 #include "sync/base/sync_export.h"
     19 #include "sync/syncable/syncable_id.h"
     20 
     21 namespace sync_pb {
     22 class ClientToServerMessage;
     23 }
     24 
     25 namespace syncer {
     26 
     27 namespace syncable {
     28 class Directory;
     29 }
     30 
     31 static const int32 kUnsetResponseCode = -1;
     32 static const int32 kUnsetContentLength = -1;
     33 static const int32 kUnsetPayloadLength = -1;
     34 
     35 // HttpResponse gathers the relevant output properties of an HTTP request.
     36 // Depending on the value of the server_status code, response_code, and
     37 // content_length may not be valid.
     38 struct SYNC_EXPORT_PRIVATE HttpResponse {
     39   enum ServerConnectionCode {
     40     // For uninitialized state.
     41     NONE,
     42 
     43     // CONNECTION_UNAVAILABLE is returned when InternetConnect() fails.
     44     CONNECTION_UNAVAILABLE,
     45 
     46     // IO_ERROR is returned when reading/writing to a buffer has failed.
     47     IO_ERROR,
     48 
     49     // SYNC_SERVER_ERROR is returned when the HTTP status code indicates that
     50     // a non-auth error has occured.
     51     SYNC_SERVER_ERROR,
     52 
     53     // SYNC_AUTH_ERROR is returned when the HTTP status code indicates that an
     54     // auth error has occured (i.e. a 401 or sync-specific AUTH_INVALID
     55     // response)
     56     // TODO(tim): Caring about AUTH_INVALID is a layering violation. But
     57     // this app-specific logic is being added as a stable branch hotfix so
     58     // minimal changes prevail for the moment.  Fix this! Bug 35060.
     59     SYNC_AUTH_ERROR,
     60 
     61     // SERVER_CONNECTION_OK is returned when request was handled correctly.
     62     SERVER_CONNECTION_OK,
     63 
     64     // RETRY is returned when a Commit request fails with a RETRY response from
     65     // the server.
     66     //
     67     // TODO(idana): the server no longer returns RETRY so we should remove this
     68     // value.
     69     RETRY,
     70   };
     71 
     72   // The HTTP Status code.
     73   int64 response_code;
     74 
     75   // The value of the Content-length header.
     76   int64 content_length;
     77 
     78   // The size of a download request's payload.
     79   int64 payload_length;
     80 
     81   // Value of the Update-Client-Auth header.
     82   std::string update_client_auth_header;
     83 
     84   // Identifies the type of failure, if any.
     85   ServerConnectionCode server_status;
     86 
     87   HttpResponse();
     88 
     89   static const char* GetServerConnectionCodeString(
     90       ServerConnectionCode code);
     91 
     92   static ServerConnectionCode ServerConnectionCodeFromNetError(
     93       int error_code);
     94 };
     95 
     96 struct ServerConnectionEvent {
     97   HttpResponse::ServerConnectionCode connection_code;
     98   explicit ServerConnectionEvent(HttpResponse::ServerConnectionCode code) :
     99       connection_code(code) {}
    100 };
    101 
    102 class SYNC_EXPORT_PRIVATE ServerConnectionEventListener {
    103  public:
    104   virtual void OnServerConnectionEvent(const ServerConnectionEvent& event) = 0;
    105  protected:
    106   virtual ~ServerConnectionEventListener() {}
    107 };
    108 
    109 class ServerConnectionManager;
    110 // A helper class that automatically notifies when the status changes.
    111 // TODO(tim): This class shouldn't be exposed outside of the implementation,
    112 // bug 35060.
    113 class SYNC_EXPORT_PRIVATE ScopedServerStatusWatcher
    114     : public base::NonThreadSafe {
    115  public:
    116   ScopedServerStatusWatcher(ServerConnectionManager* conn_mgr,
    117                             HttpResponse* response);
    118   virtual ~ScopedServerStatusWatcher();
    119  private:
    120   ServerConnectionManager* const conn_mgr_;
    121   HttpResponse* const response_;
    122   DISALLOW_COPY_AND_ASSIGN(ScopedServerStatusWatcher);
    123 };
    124 
    125 // Use this class to interact with the sync server.
    126 // The ServerConnectionManager currently supports POSTing protocol buffers.
    127 //
    128 class SYNC_EXPORT_PRIVATE ServerConnectionManager {
    129  public:
    130   // buffer_in - will be POSTed
    131   // buffer_out - string will be overwritten with response
    132   struct PostBufferParams {
    133     std::string buffer_in;
    134     std::string buffer_out;
    135     HttpResponse response;
    136   };
    137 
    138   // Abstract class providing network-layer functionality to the
    139   // ServerConnectionManager. Subclasses implement this using an HTTP stack of
    140   // their choice.
    141   class Connection {
    142    public:
    143     explicit Connection(ServerConnectionManager* scm);
    144     virtual ~Connection();
    145 
    146     // Called to initialize and perform an HTTP POST.
    147     virtual bool Init(const char* path,
    148                       const std::string& auth_token,
    149                       const std::string& payload,
    150                       HttpResponse* response) = 0;
    151 
    152     // Immediately abandons a pending HTTP POST request and unblocks caller
    153     // in Init.
    154     virtual void Abort() = 0;
    155 
    156     bool ReadBufferResponse(std::string* buffer_out, HttpResponse* response,
    157                             bool require_response);
    158     bool ReadDownloadResponse(HttpResponse* response, std::string* buffer_out);
    159 
    160    protected:
    161     std::string MakeConnectionURL(const std::string& sync_server,
    162                                   const std::string& path,
    163                                   bool use_ssl) const;
    164 
    165     void GetServerParams(std::string* server,
    166                          int* server_port,
    167                          bool* use_ssl,
    168                          bool* use_oauth2_token) const {
    169       server->assign(scm_->sync_server_);
    170       *server_port = scm_->sync_server_port_;
    171       *use_ssl = scm_->use_ssl_;
    172       *use_oauth2_token = scm_->use_oauth2_token_;
    173     }
    174 
    175     std::string buffer_;
    176     ServerConnectionManager* scm_;
    177 
    178    private:
    179     int ReadResponse(void* buffer, int length);
    180     int ReadResponse(std::string* buffer, int length);
    181   };
    182 
    183   ServerConnectionManager(const std::string& server,
    184                           int port,
    185                           bool use_ssl,
    186                           bool use_oauth2_token);
    187 
    188   virtual ~ServerConnectionManager();
    189 
    190   // POSTS buffer_in and reads a response into buffer_out. Uses our currently
    191   // set auth token in our headers.
    192   //
    193   // Returns true if executed successfully.
    194   virtual bool PostBufferWithCachedAuth(PostBufferParams* params,
    195                                         ScopedServerStatusWatcher* watcher);
    196 
    197   void AddListener(ServerConnectionEventListener* listener);
    198   void RemoveListener(ServerConnectionEventListener* listener);
    199 
    200   inline HttpResponse::ServerConnectionCode server_status() const {
    201     DCHECK(thread_checker_.CalledOnValidThread());
    202     return server_status_;
    203   }
    204 
    205   const std::string client_id() const { return client_id_; }
    206 
    207   // Returns the current server parameters in server_url, port and use_ssl.
    208   void GetServerParameters(std::string* server_url,
    209                            int* port,
    210                            bool* use_ssl) const;
    211 
    212   std::string GetServerHost() const;
    213 
    214   // Factory method to create an Connection object we can use for
    215   // communication with the server.
    216   virtual Connection* MakeConnection();
    217 
    218   // Aborts any active HTTP POST request.
    219   // We expect this to get called on a different thread than the valid
    220   // ThreadChecker thread, as we want to kill any pending http traffic without
    221   // having to wait for the request to complete.
    222   void TerminateAllIO();
    223 
    224   void set_client_id(const std::string& client_id) {
    225     DCHECK(thread_checker_.CalledOnValidThread());
    226     DCHECK(client_id_.empty());
    227     client_id_.assign(client_id);
    228   }
    229 
    230   // Sets a new auth token and time.
    231   bool SetAuthToken(const std::string& auth_token);
    232 
    233   // Our out-of-band invalidations channel can encounter auth errors,
    234   // and when it does so it tells us via this method to prevent making more
    235   // requests with known-bad tokens. This will put the
    236   // ServerConnectionManager in an auth error state as if it received an
    237   // HTTP 401 from sync servers.
    238   void OnInvalidationCredentialsRejected();
    239 
    240   bool HasInvalidAuthToken() {
    241     return auth_token_.empty();
    242   }
    243 
    244   const std::string auth_token() const {
    245     DCHECK(thread_checker_.CalledOnValidThread());
    246     return auth_token_;
    247   }
    248 
    249  protected:
    250   inline std::string proto_sync_path() const {
    251     return proto_sync_path_;
    252   }
    253 
    254   // Updates server_status_ and notifies listeners if server_status_ changed
    255   void SetServerStatus(HttpResponse::ServerConnectionCode server_status);
    256 
    257   // NOTE: Tests rely on this protected function being virtual.
    258   //
    259   // Internal PostBuffer base function.
    260   virtual bool PostBufferToPath(PostBufferParams*,
    261                                 const std::string& path,
    262                                 const std::string& auth_token,
    263                                 ScopedServerStatusWatcher* watcher);
    264 
    265   // An internal helper to clear our auth_token_ and cache the old version
    266   // in |previously_invalidated_token_| to shelter us from retrying with a
    267   // known bad token.
    268   void InvalidateAndClearAuthToken();
    269 
    270   // Helper to check terminated flags and build a Connection object, installing
    271   // it as the |active_connection_|.  If this ServerConnectionManager has been
    272   // terminated, this will return NULL.
    273   Connection* MakeActiveConnection();
    274 
    275   // Called by Connection objects as they are destroyed to allow the
    276   // ServerConnectionManager to cleanup active connections.
    277   void OnConnectionDestroyed(Connection* connection);
    278 
    279   // The sync_server_ is the server that requests will be made to.
    280   std::string sync_server_;
    281 
    282   // The sync_server_port_ is the port that HTTP requests will be made on.
    283   int sync_server_port_;
    284 
    285   // The unique id of the user's client.
    286   std::string client_id_;
    287 
    288   // Indicates whether or not requests should be made using HTTPS.
    289   bool use_ssl_;
    290 
    291   // Indicates if token should be handled as OAuth2 token. Connection should set
    292   // auth header appropriately.
    293   // TODO(pavely): Remove once sync on android switches to oauth2 tokens.
    294   bool use_oauth2_token_;
    295 
    296   // The paths we post to.
    297   std::string proto_sync_path_;
    298 
    299   // The auth token to use in authenticated requests.
    300   std::string auth_token_;
    301 
    302   // The previous auth token that is invalid now.
    303   std::string previously_invalidated_token;
    304 
    305   ObserverList<ServerConnectionEventListener> listeners_;
    306 
    307   HttpResponse::ServerConnectionCode server_status_;
    308 
    309   base::ThreadChecker thread_checker_;
    310 
    311   // Protects all variables below to allow bailing out of active connections.
    312   base::Lock terminate_connection_lock_;
    313 
    314   // If true, we've been told to terminate IO and expect to be destroyed
    315   // shortly.  No future network requests will be made.
    316   bool terminated_;
    317 
    318   // A non-owning pointer to any active http connection, so that we can abort
    319   // it if necessary.
    320   Connection* active_connection_;
    321 
    322  private:
    323   friend class Connection;
    324   friend class ScopedServerStatusWatcher;
    325 
    326   // A class to help deal with cleaning up active Connection objects when (for
    327   // ex) multiple early-exits are present in some scope. ScopedConnectionHelper
    328   // informs the ServerConnectionManager before the Connection object it takes
    329   // ownership of is destroyed.
    330   class ScopedConnectionHelper {
    331    public:
    332     // |manager| must outlive this. Takes ownership of |connection|.
    333     ScopedConnectionHelper(ServerConnectionManager* manager,
    334                            Connection* connection);
    335     ~ScopedConnectionHelper();
    336     Connection* get();
    337    private:
    338     ServerConnectionManager* manager_;
    339     scoped_ptr<Connection> connection_;
    340     DISALLOW_COPY_AND_ASSIGN(ScopedConnectionHelper);
    341   };
    342 
    343   void NotifyStatusChanged();
    344 
    345   DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager);
    346 };
    347 
    348 std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr);
    349 
    350 }  // namespace syncer
    351 
    352 #endif  // SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
    353