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/internal_api/public/base/cancelation_observer.h" 20 #include "sync/syncable/syncable_id.h" 21 22 namespace sync_pb { 23 class ClientToServerMessage; 24 } 25 26 namespace syncer { 27 28 class CancelationSignal; 29 30 namespace syncable { 31 class Directory; 32 } 33 34 static const int32 kUnsetResponseCode = -1; 35 static const int32 kUnsetContentLength = -1; 36 static const int32 kUnsetPayloadLength = -1; 37 38 // HttpResponse gathers the relevant output properties of an HTTP request. 39 // Depending on the value of the server_status code, response_code, and 40 // content_length may not be valid. 41 struct SYNC_EXPORT_PRIVATE HttpResponse { 42 enum ServerConnectionCode { 43 // For uninitialized state. 44 NONE, 45 46 // CONNECTION_UNAVAILABLE is returned when InternetConnect() fails. 47 CONNECTION_UNAVAILABLE, 48 49 // IO_ERROR is returned when reading/writing to a buffer has failed. 50 IO_ERROR, 51 52 // SYNC_SERVER_ERROR is returned when the HTTP status code indicates that 53 // a non-auth error has occured. 54 SYNC_SERVER_ERROR, 55 56 // SYNC_AUTH_ERROR is returned when the HTTP status code indicates that an 57 // auth error has occured (i.e. a 401 or sync-specific AUTH_INVALID 58 // response) 59 // TODO(tim): Caring about AUTH_INVALID is a layering violation. But 60 // this app-specific logic is being added as a stable branch hotfix so 61 // minimal changes prevail for the moment. Fix this! Bug 35060. 62 SYNC_AUTH_ERROR, 63 64 // SERVER_CONNECTION_OK is returned when request was handled correctly. 65 SERVER_CONNECTION_OK, 66 67 // RETRY is returned when a Commit request fails with a RETRY response from 68 // the server. 69 // 70 // TODO(idana): the server no longer returns RETRY so we should remove this 71 // value. 72 RETRY, 73 }; 74 75 // The HTTP Status code. 76 int64 response_code; 77 78 // The value of the Content-length header. 79 int64 content_length; 80 81 // The size of a download request's payload. 82 int64 payload_length; 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; ServerConnectionEventServerConnectionEvent98 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: ~ServerConnectionEventListener()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 : public CancelationObserver { 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 GetServerParams(std::string * server,int * server_port,bool * use_ssl)165 void GetServerParams(std::string* server, 166 int* server_port, 167 bool* use_ssl) const { 168 server->assign(scm_->sync_server_); 169 *server_port = scm_->sync_server_port_; 170 *use_ssl = scm_->use_ssl_; 171 } 172 173 std::string buffer_; 174 ServerConnectionManager* scm_; 175 176 private: 177 int ReadResponse(void* buffer, int length); 178 int ReadResponse(std::string* buffer, int length); 179 }; 180 181 ServerConnectionManager(const std::string& server, 182 int port, 183 bool use_ssl, 184 CancelationSignal* cancelation_signal); 185 186 virtual ~ServerConnectionManager(); 187 188 // POSTS buffer_in and reads a response into buffer_out. Uses our currently 189 // set auth token in our headers. 190 // 191 // Returns true if executed successfully. 192 virtual bool PostBufferWithCachedAuth(PostBufferParams* params, 193 ScopedServerStatusWatcher* watcher); 194 195 void AddListener(ServerConnectionEventListener* listener); 196 void RemoveListener(ServerConnectionEventListener* listener); 197 server_status()198 inline HttpResponse::ServerConnectionCode server_status() const { 199 DCHECK(thread_checker_.CalledOnValidThread()); 200 return server_status_; 201 } 202 client_id()203 const std::string client_id() const { return client_id_; } 204 205 // Returns the current server parameters in server_url, port and use_ssl. 206 void GetServerParameters(std::string* server_url, 207 int* port, 208 bool* use_ssl) const; 209 210 std::string GetServerHost() const; 211 212 // Factory method to create an Connection object we can use for 213 // communication with the server. 214 virtual Connection* MakeConnection(); 215 216 // Closes any active network connections to the sync server. 217 // We expect this to get called on a different thread than the valid 218 // ThreadChecker thread, as we want to kill any pending http traffic without 219 // having to wait for the request to complete. 220 virtual void OnSignalReceived() OVERRIDE FINAL; 221 set_client_id(const std::string & client_id)222 void set_client_id(const std::string& client_id) { 223 DCHECK(thread_checker_.CalledOnValidThread()); 224 DCHECK(client_id_.empty()); 225 client_id_.assign(client_id); 226 } 227 228 // Sets a new auth token and time. 229 bool SetAuthToken(const std::string& auth_token); 230 231 // Our out-of-band invalidations channel can encounter auth errors, 232 // and when it does so it tells us via this method to prevent making more 233 // requests with known-bad tokens. This will put the 234 // ServerConnectionManager in an auth error state as if it received an 235 // HTTP 401 from sync servers. 236 void OnInvalidationCredentialsRejected(); 237 HasInvalidAuthToken()238 bool HasInvalidAuthToken() { 239 return auth_token_.empty(); 240 } 241 auth_token()242 const std::string auth_token() const { 243 DCHECK(thread_checker_.CalledOnValidThread()); 244 return auth_token_; 245 } 246 247 protected: proto_sync_path()248 inline std::string proto_sync_path() const { 249 return proto_sync_path_; 250 } 251 252 // Updates server_status_ and notifies listeners if server_status_ changed 253 void SetServerStatus(HttpResponse::ServerConnectionCode server_status); 254 255 // NOTE: Tests rely on this protected function being virtual. 256 // 257 // Internal PostBuffer base function. 258 virtual bool PostBufferToPath(PostBufferParams*, 259 const std::string& path, 260 const std::string& auth_token, 261 ScopedServerStatusWatcher* watcher); 262 263 // An internal helper to clear our auth_token_ and cache the old version 264 // in |previously_invalidated_token_| to shelter us from retrying with a 265 // known bad token. 266 void InvalidateAndClearAuthToken(); 267 268 // Helper to check terminated flags and build a Connection object, installing 269 // it as the |active_connection_|. If this ServerConnectionManager has been 270 // terminated, this will return NULL. 271 Connection* MakeActiveConnection(); 272 273 // Called by Connection objects as they are destroyed to allow the 274 // ServerConnectionManager to cleanup active connections. 275 void OnConnectionDestroyed(Connection* connection); 276 277 // The sync_server_ is the server that requests will be made to. 278 std::string sync_server_; 279 280 // The sync_server_port_ is the port that HTTP requests will be made on. 281 int sync_server_port_; 282 283 // The unique id of the user's client. 284 std::string client_id_; 285 286 // Indicates whether or not requests should be made using HTTPS. 287 bool use_ssl_; 288 289 // The paths we post to. 290 std::string proto_sync_path_; 291 292 // The auth token to use in authenticated requests. 293 std::string auth_token_; 294 295 // The previous auth token that is invalid now. 296 std::string previously_invalidated_token; 297 298 ObserverList<ServerConnectionEventListener> listeners_; 299 300 HttpResponse::ServerConnectionCode server_status_; 301 302 base::ThreadChecker thread_checker_; 303 304 // Protects all variables below to allow bailing out of active connections. 305 base::Lock terminate_connection_lock_; 306 307 // If true, we've been told to terminate IO and expect to be destroyed 308 // shortly. No future network requests will be made. 309 bool terminated_; 310 311 // A non-owning pointer to any active http connection, so that we can abort 312 // it if necessary. 313 Connection* active_connection_; 314 315 private: 316 friend class Connection; 317 friend class ScopedServerStatusWatcher; 318 319 // A class to help deal with cleaning up active Connection objects when (for 320 // ex) multiple early-exits are present in some scope. ScopedConnectionHelper 321 // informs the ServerConnectionManager before the Connection object it takes 322 // ownership of is destroyed. 323 class ScopedConnectionHelper { 324 public: 325 // |manager| must outlive this. Takes ownership of |connection|. 326 ScopedConnectionHelper(ServerConnectionManager* manager, 327 Connection* connection); 328 ~ScopedConnectionHelper(); 329 Connection* get(); 330 private: 331 ServerConnectionManager* manager_; 332 scoped_ptr<Connection> connection_; 333 DISALLOW_COPY_AND_ASSIGN(ScopedConnectionHelper); 334 }; 335 336 void NotifyStatusChanged(); 337 338 CancelationSignal* const cancelation_signal_; 339 bool signal_handler_registered_; 340 341 DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager); 342 }; 343 344 std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr); 345 346 } // namespace syncer 347 348 #endif // SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ 349