Home | History | Annotate | Download | only in net
      1 // Copyright (c) 2010 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 CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
      6 #define CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
      7 #pragma once
      8 
      9 #include <iosfwd>
     10 #include <string>
     11 
     12 #include "base/atomicops.h"
     13 #include "base/observer_list_threadsafe.h"
     14 #include "base/string_util.h"
     15 #include "base/synchronization/lock.h"
     16 #include "chrome/browser/sync/syncable/syncable_id.h"
     17 #include "chrome/common/deprecated/event_sys.h"
     18 #include "chrome/common/deprecated/event_sys-inl.h"
     19 #include "chrome/common/net/http_return.h"
     20 
     21 namespace syncable {
     22 class WriteTransaction;
     23 class DirectoryManager;
     24 }
     25 
     26 namespace sync_pb {
     27 class ClientToServerMessage;
     28 }
     29 
     30 struct RequestTimingInfo;
     31 
     32 namespace browser_sync {
     33 
     34 class ClientToServerMessage;
     35 
     36 // How many connection errors are accepted before network handles are closed
     37 // and reopened.
     38 static const int32 kMaxConnectionErrorsBeforeReset = 10;
     39 
     40 static const int32 kUnsetResponseCode = -1;
     41 static const int32 kUnsetContentLength = -1;
     42 static const int32 kUnsetPayloadLength = -1;
     43 
     44 // HttpResponse gathers the relevant output properties of an HTTP request.
     45 // Depending on the value of the server_status code, response_code, and
     46 // content_length may not be valid.
     47 struct HttpResponse {
     48   enum ServerConnectionCode {
     49     // For uninitialized state.
     50     NONE,
     51 
     52     // CONNECTION_UNAVAILABLE is returned when InternetConnect() fails.
     53     CONNECTION_UNAVAILABLE,
     54 
     55     // IO_ERROR is returned when reading/writing to a buffer has failed.
     56     IO_ERROR,
     57 
     58     // SYNC_SERVER_ERROR is returned when the HTTP status code indicates that
     59     // a non-auth error has occured.
     60     SYNC_SERVER_ERROR,
     61 
     62     // SYNC_AUTH_ERROR is returned when the HTTP status code indicates that an
     63     // auth error has occured (i.e. a 401 or sync-specific AUTH_INVALID
     64     // response)
     65     // TODO(tim): Caring about AUTH_INVALID is a layering violation. But
     66     // this app-specific logic is being added as a stable branch hotfix so
     67     // minimal changes prevail for the moment.  Fix this! Bug 35060.
     68     SYNC_AUTH_ERROR,
     69 
     70     // All the following connection codes are valid responses from the server.
     71     // Means the server is up.  If you update this list, be sure to also update
     72     // IsGoodReplyFromServer().
     73 
     74     // SERVER_CONNECTION_OK is returned when request was handled correctly.
     75     SERVER_CONNECTION_OK,
     76 
     77     // RETRY is returned when a Commit request fails with a RETRY response from
     78     // the server.
     79     //
     80     // TODO(idana): the server no longer returns RETRY so we should remove this
     81     // value.
     82     RETRY,
     83   };
     84 
     85   // The HTTP Status code.
     86   int64 response_code;
     87 
     88   // The value of the Content-length header.
     89   int64 content_length;
     90 
     91   // The size of a download request's payload.
     92   int64 payload_length;
     93 
     94   // Value of the Update-Client-Auth header.
     95   std::string update_client_auth_header;
     96 
     97   // Identifies the type of failure, if any.
     98   ServerConnectionCode server_status;
     99 
    100   HttpResponse()
    101       : response_code(kUnsetResponseCode),
    102         content_length(kUnsetContentLength),
    103         payload_length(kUnsetPayloadLength),
    104         server_status(NONE) {}
    105 };
    106 
    107 inline bool IsGoodReplyFromServer(HttpResponse::ServerConnectionCode code) {
    108   return code >= HttpResponse::SERVER_CONNECTION_OK;
    109 }
    110 
    111 // TODO(tim): Deprecated.
    112 struct ServerConnectionEvent {
    113   // Traits.
    114   typedef ServerConnectionEvent EventType;
    115   enum WhatHappened {
    116     SHUTDOWN,
    117     STATUS_CHANGED
    118   };
    119 
    120   static inline bool IsChannelShutdownEvent(const EventType& event) {
    121     return SHUTDOWN == event.what_happened;
    122   }
    123 
    124   WhatHappened what_happened;
    125   HttpResponse::ServerConnectionCode connection_code;
    126   bool server_reachable;
    127 };
    128 
    129 struct ServerConnectionEvent2 {
    130   HttpResponse::ServerConnectionCode connection_code;
    131   bool server_reachable;
    132   ServerConnectionEvent2(HttpResponse::ServerConnectionCode code,
    133                          bool server_reachable) :
    134       connection_code(code), server_reachable(server_reachable) {}
    135 };
    136 
    137 class ServerConnectionEventListener {
    138  public:
    139   virtual void OnServerConnectionEvent(const ServerConnectionEvent2& event) = 0;
    140  protected:
    141   virtual ~ServerConnectionEventListener() {}
    142 };
    143 
    144 class ServerConnectionManager;
    145 // A helper class that automatically notifies when the status changes.
    146 // TODO(tim): This class shouldn't be exposed outside of the implementation,
    147 // bug 35060.
    148 class ScopedServerStatusWatcher {
    149  public:
    150   ScopedServerStatusWatcher(ServerConnectionManager* conn_mgr,
    151                             HttpResponse* response);
    152   ~ScopedServerStatusWatcher();
    153  private:
    154   ServerConnectionManager* const conn_mgr_;
    155   HttpResponse* const response_;
    156   // TODO(tim): Should this be Barrier:AtomicIncrement?
    157   base::subtle::AtomicWord reset_count_;
    158   bool server_reachable_;
    159   DISALLOW_COPY_AND_ASSIGN(ScopedServerStatusWatcher);
    160 };
    161 
    162 // Use this class to interact with the sync server.
    163 // The ServerConnectionManager currently supports POSTing protocol buffers.
    164 //
    165 //  *** This class is thread safe. In fact, you should consider creating only
    166 //  one instance for every server that you need to talk to.
    167 class ServerConnectionManager {
    168  public:
    169   typedef EventChannel<ServerConnectionEvent, base::Lock> Channel;
    170 
    171   // buffer_in - will be POSTed
    172   // buffer_out - string will be overwritten with response
    173   struct PostBufferParams {
    174     const std::string& buffer_in;
    175     std::string* buffer_out;
    176     HttpResponse* response;
    177     RequestTimingInfo* timing_info;
    178   };
    179 
    180   // Abstract class providing network-layer functionality to the
    181   // ServerConnectionManager. Subclasses implement this using an HTTP stack of
    182   // their choice.
    183   class Post {
    184    public:
    185     explicit Post(ServerConnectionManager* scm) : scm_(scm), timing_info_(0) {
    186     }
    187     virtual ~Post() { }
    188 
    189     // Called to initialize and perform an HTTP POST.
    190     virtual bool Init(const char* path,
    191                       const std::string& auth_token,
    192                       const std::string& payload,
    193                       HttpResponse* response) = 0;
    194 
    195     bool ReadBufferResponse(std::string* buffer_out, HttpResponse* response,
    196                             bool require_response);
    197     bool ReadDownloadResponse(HttpResponse* response, std::string* buffer_out);
    198 
    199     void set_timing_info(RequestTimingInfo* timing_info) {
    200       timing_info_ = timing_info;
    201     }
    202     RequestTimingInfo* timing_info() { return timing_info_; }
    203 
    204    protected:
    205     std::string MakeConnectionURL(const std::string& sync_server,
    206                                   const std::string& path,
    207                                   bool use_ssl) const;
    208 
    209     void GetServerParams(std::string* server,
    210                          int* server_port,
    211                          bool* use_ssl) const {
    212       base::AutoLock lock(scm_->server_parameters_mutex_);
    213       server->assign(scm_->sync_server_);
    214       *server_port = scm_->sync_server_port_;
    215       *use_ssl = scm_->use_ssl_;
    216     }
    217 
    218     std::string buffer_;
    219     ServerConnectionManager* scm_;
    220 
    221    private:
    222     int ReadResponse(void* buffer, int length);
    223     int ReadResponse(std::string* buffer, int length);
    224     RequestTimingInfo* timing_info_;
    225   };
    226 
    227   ServerConnectionManager(const std::string& server,
    228                           int port,
    229                           bool use_ssl,
    230                           const std::string& user_agent);
    231 
    232   virtual ~ServerConnectionManager();
    233 
    234   // POSTS buffer_in and reads a response into buffer_out. Uses our currently
    235   // set auth token in our headers.
    236   //
    237   // Returns true if executed successfully.
    238   virtual bool PostBufferWithCachedAuth(const PostBufferParams* params,
    239                                         ScopedServerStatusWatcher* watcher);
    240 
    241   // Checks the time on the server. Returns false if the request failed. |time|
    242   // is an out parameter that stores the value returned from the server.
    243   virtual bool CheckTime(int32* out_time);
    244 
    245   // Returns true if sync_server_ is reachable. This method verifies that the
    246   // server is pingable and that traffic can be sent to and from it.
    247   virtual bool IsServerReachable();
    248 
    249   // Returns true if user has been successfully authenticated.
    250   virtual bool IsUserAuthenticated();
    251 
    252   // Updates status and broadcasts events on change.
    253   bool CheckServerReachable();
    254 
    255   // Signal the shutdown event to notify listeners.
    256   virtual void kill();
    257 
    258   inline Channel* channel() const { return channel_; }
    259 
    260   void AddListener(ServerConnectionEventListener* listener);
    261   void RemoveListener(ServerConnectionEventListener* listener);
    262 
    263   inline std::string user_agent() const { return user_agent_; }
    264 
    265   inline HttpResponse::ServerConnectionCode server_status() const {
    266     return server_status_;
    267   }
    268 
    269   inline bool server_reachable() const { return server_reachable_; }
    270 
    271   const std::string client_id() const { return client_id_; }
    272 
    273   // This changes the server info used by the connection manager. This allows
    274   // a single client instance to talk to different backing servers. This is
    275   // typically called during / after authentication so that the server url
    276   // can be a function of the user's login id. A side effect of this call is
    277   // that ResetConnection is called.
    278   void SetServerParameters(const std::string& server_url,
    279                            int port,
    280                            bool use_ssl);
    281 
    282   // Returns the current server parameters in server_url, port and use_ssl.
    283   void GetServerParameters(std::string* server_url,
    284                            int* port,
    285                            bool* use_ssl) const;
    286 
    287   std::string GetServerHost() const;
    288 
    289   bool terminate_all_io() const {
    290     base::AutoLock lock(terminate_all_io_mutex_);
    291     return terminate_all_io_;
    292   }
    293 
    294   // Factory method to create a Post object we can use for communication with
    295   // the server.
    296   virtual Post* MakePost();
    297 
    298   void set_client_id(const std::string& client_id) {
    299     DCHECK(client_id_.empty());
    300     client_id_.assign(client_id);
    301   }
    302 
    303   void set_auth_token(const std::string& auth_token) {
    304     // TODO(chron): Consider adding a message loop check here.
    305     base::AutoLock lock(auth_token_mutex_);
    306     auth_token_.assign(auth_token);
    307   }
    308 
    309   const std::string auth_token() const {
    310     base::AutoLock lock(auth_token_mutex_);
    311     return auth_token_;
    312   }
    313 
    314  protected:
    315   inline std::string proto_sync_path() const {
    316     base::AutoLock lock(path_mutex_);
    317     return proto_sync_path_;
    318   }
    319 
    320   std::string get_time_path() const {
    321     base::AutoLock lock(path_mutex_);
    322     return get_time_path_;
    323   }
    324 
    325   // Called wherever a failure should be taken as an indication that we may
    326   // be experiencing connection difficulties.
    327   virtual bool IncrementErrorCount();
    328 
    329   // NOTE: Tests rely on this protected function being virtual.
    330   //
    331   // Internal PostBuffer base function.
    332   virtual bool PostBufferToPath(const PostBufferParams*,
    333                                 const std::string& path,
    334                                 const std::string& auth_token,
    335                                 ScopedServerStatusWatcher* watcher);
    336 
    337   // Protects access to sync_server_, sync_server_port_ and use_ssl_:
    338   mutable base::Lock server_parameters_mutex_;
    339 
    340   // The sync_server_ is the server that requests will be made to.
    341   std::string sync_server_;
    342 
    343   // The sync_server_port_ is the port that HTTP requests will be made on.
    344   int sync_server_port_;
    345 
    346   // The unique id of the user's client.
    347   std::string client_id_;
    348 
    349   // The user-agent string for HTTP.
    350   std::string user_agent_;
    351 
    352   // Indicates whether or not requests should be made using HTTPS.
    353   bool use_ssl_;
    354 
    355   // The paths we post to.
    356   mutable base::Lock path_mutex_;
    357   std::string proto_sync_path_;
    358   std::string get_time_path_;
    359 
    360   mutable base::Lock auth_token_mutex_;
    361   // The auth token to use in authenticated requests. Set by the AuthWatcher.
    362   std::string auth_token_;
    363 
    364   base::Lock error_count_mutex_;  // Protects error_count_
    365   int error_count_;  // Tracks the number of connection errors.
    366 
    367   // TODO(tim): Deprecated.
    368   Channel* const channel_;
    369 
    370   scoped_refptr<ObserverListThreadSafe<ServerConnectionEventListener> >
    371      listeners_;
    372 
    373   // Volatile so various threads can call server_status() without
    374   // synchronization.
    375   volatile HttpResponse::ServerConnectionCode server_status_;
    376   bool server_reachable_;
    377 
    378   // A counter that is incremented everytime ResetAuthStatus() is called.
    379   volatile base::subtle::AtomicWord reset_count_;
    380 
    381  private:
    382   friend class Post;
    383   friend class ScopedServerStatusWatcher;
    384 
    385   void NotifyStatusChanged();
    386   void ResetConnection();
    387 
    388   mutable base::Lock terminate_all_io_mutex_;
    389   bool terminate_all_io_;  // When set to true, terminate all connections asap.
    390   DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager);
    391 };
    392 
    393 // Fills a ClientToServerMessage with the appropriate share and birthday
    394 // settings.
    395 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
    396                                  syncable::DirectoryManager* manager,
    397                                  const std::string& share);
    398 
    399 std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr);
    400 
    401 }  // namespace browser_sync
    402 
    403 #endif  // CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
    404