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; 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 : 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 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 198 inline HttpResponse::ServerConnectionCode server_status() const { 199 DCHECK(thread_checker_.CalledOnValidThread()); 200 return server_status_; 201 } 202 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 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 bool HasInvalidAuthToken() { 232 return auth_token_.empty(); 233 } 234 235 const std::string auth_token() const { 236 DCHECK(thread_checker_.CalledOnValidThread()); 237 return auth_token_; 238 } 239 240 protected: 241 inline std::string proto_sync_path() const { 242 return proto_sync_path_; 243 } 244 245 // Updates server_status_ and notifies listeners if server_status_ changed 246 void SetServerStatus(HttpResponse::ServerConnectionCode server_status); 247 248 // NOTE: Tests rely on this protected function being virtual. 249 // 250 // Internal PostBuffer base function. 251 virtual bool PostBufferToPath(PostBufferParams*, 252 const std::string& path, 253 const std::string& auth_token, 254 ScopedServerStatusWatcher* watcher); 255 256 // An internal helper to clear our auth_token_ and cache the old version 257 // in |previously_invalidated_token_| to shelter us from retrying with a 258 // known bad token. 259 void InvalidateAndClearAuthToken(); 260 261 // Helper to check terminated flags and build a Connection object, installing 262 // it as the |active_connection_|. If this ServerConnectionManager has been 263 // terminated, this will return NULL. 264 Connection* MakeActiveConnection(); 265 266 // Called by Connection objects as they are destroyed to allow the 267 // ServerConnectionManager to cleanup active connections. 268 void OnConnectionDestroyed(Connection* connection); 269 270 // The sync_server_ is the server that requests will be made to. 271 std::string sync_server_; 272 273 // The sync_server_port_ is the port that HTTP requests will be made on. 274 int sync_server_port_; 275 276 // The unique id of the user's client. 277 std::string client_id_; 278 279 // Indicates whether or not requests should be made using HTTPS. 280 bool use_ssl_; 281 282 // The paths we post to. 283 std::string proto_sync_path_; 284 285 // The auth token to use in authenticated requests. 286 std::string auth_token_; 287 288 // The previous auth token that is invalid now. 289 std::string previously_invalidated_token; 290 291 ObserverList<ServerConnectionEventListener> listeners_; 292 293 HttpResponse::ServerConnectionCode server_status_; 294 295 base::ThreadChecker thread_checker_; 296 297 // Protects all variables below to allow bailing out of active connections. 298 base::Lock terminate_connection_lock_; 299 300 // If true, we've been told to terminate IO and expect to be destroyed 301 // shortly. No future network requests will be made. 302 bool terminated_; 303 304 // A non-owning pointer to any active http connection, so that we can abort 305 // it if necessary. 306 Connection* active_connection_; 307 308 private: 309 friend class Connection; 310 friend class ScopedServerStatusWatcher; 311 312 // A class to help deal with cleaning up active Connection objects when (for 313 // ex) multiple early-exits are present in some scope. ScopedConnectionHelper 314 // informs the ServerConnectionManager before the Connection object it takes 315 // ownership of is destroyed. 316 class ScopedConnectionHelper { 317 public: 318 // |manager| must outlive this. Takes ownership of |connection|. 319 ScopedConnectionHelper(ServerConnectionManager* manager, 320 Connection* connection); 321 ~ScopedConnectionHelper(); 322 Connection* get(); 323 private: 324 ServerConnectionManager* manager_; 325 scoped_ptr<Connection> connection_; 326 DISALLOW_COPY_AND_ASSIGN(ScopedConnectionHelper); 327 }; 328 329 void NotifyStatusChanged(); 330 331 CancelationSignal* const cancelation_signal_; 332 bool signal_handler_registered_; 333 334 DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager); 335 }; 336 337 std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr); 338 339 } // namespace syncer 340 341 #endif // SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ 342