server_connection_manager.h revision 868fa2fe829687343ffae624259930155e16dbd8
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 21namespace sync_pb { 22class ClientToServerMessage; 23} 24 25namespace syncer { 26 27namespace syncable { 28class Directory; 29} 30 31static const int32 kUnsetResponseCode = -1; 32static const int32 kUnsetContentLength = -1; 33static 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. 38struct 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 96struct ServerConnectionEvent { 97 HttpResponse::ServerConnectionCode connection_code; 98 explicit ServerConnectionEvent(HttpResponse::ServerConnectionCode code) : 99 connection_code(code) {} 100}; 101 102class SYNC_EXPORT_PRIVATE ServerConnectionEventListener { 103 public: 104 virtual void OnServerConnectionEvent(const ServerConnectionEvent& event) = 0; 105 protected: 106 virtual ~ServerConnectionEventListener() {} 107}; 108 109class 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. 113class 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// 128class 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) 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 185 virtual ~ServerConnectionManager(); 186 187 // POSTS buffer_in and reads a response into buffer_out. Uses our currently 188 // set auth token in our headers. 189 // 190 // Returns true if executed successfully. 191 virtual bool PostBufferWithCachedAuth(PostBufferParams* params, 192 ScopedServerStatusWatcher* watcher); 193 194 void AddListener(ServerConnectionEventListener* listener); 195 void RemoveListener(ServerConnectionEventListener* listener); 196 197 inline HttpResponse::ServerConnectionCode server_status() const { 198 DCHECK(thread_checker_.CalledOnValidThread()); 199 return server_status_; 200 } 201 202 const std::string client_id() const { return client_id_; } 203 204 // Returns the current server parameters in server_url, port and use_ssl. 205 void GetServerParameters(std::string* server_url, 206 int* port, 207 bool* use_ssl) const; 208 209 std::string GetServerHost() const; 210 211 // Factory method to create an Connection object we can use for 212 // communication with the server. 213 virtual Connection* MakeConnection(); 214 215 // Aborts any active HTTP POST request. 216 // We expect this to get called on a different thread than the valid 217 // ThreadChecker thread, as we want to kill any pending http traffic without 218 // having to wait for the request to complete. 219 void TerminateAllIO(); 220 221 void set_client_id(const std::string& client_id) { 222 DCHECK(thread_checker_.CalledOnValidThread()); 223 DCHECK(client_id_.empty()); 224 client_id_.assign(client_id); 225 } 226 227 // Sets a new auth token and time. |auth_token_time| is an optional parameter 228 // that contains the date the auth token was fetched/refreshed, and is used 229 // for histogramms/logging only. 230 bool SetAuthToken(const std::string& auth_token, 231 const base::Time& auth_token_time); 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 // The paths we post to. 292 std::string proto_sync_path_; 293 294 // The auth token to use in authenticated requests. 295 std::string auth_token_; 296 297 // The time at which this auth token was last created/refreshed. 298 // Used for histogramming. 299 base::Time auth_token_time_; 300 301 // The previous auth token that is invalid now. 302 std::string previously_invalidated_token; 303 304 ObserverList<ServerConnectionEventListener> listeners_; 305 306 HttpResponse::ServerConnectionCode server_status_; 307 308 base::ThreadChecker thread_checker_; 309 310 // Protects all variables below to allow bailing out of active connections. 311 base::Lock terminate_connection_lock_; 312 313 // If true, we've been told to terminate IO and expect to be destroyed 314 // shortly. No future network requests will be made. 315 bool terminated_; 316 317 // A non-owning pointer to any active http connection, so that we can abort 318 // it if necessary. 319 Connection* active_connection_; 320 321 private: 322 friend class Connection; 323 friend class ScopedServerStatusWatcher; 324 325 // A class to help deal with cleaning up active Connection objects when (for 326 // ex) multiple early-exits are present in some scope. ScopedConnectionHelper 327 // informs the ServerConnectionManager before the Connection object it takes 328 // ownership of is destroyed. 329 class ScopedConnectionHelper { 330 public: 331 // |manager| must outlive this. Takes ownership of |connection|. 332 ScopedConnectionHelper(ServerConnectionManager* manager, 333 Connection* connection); 334 ~ScopedConnectionHelper(); 335 Connection* get(); 336 private: 337 ServerConnectionManager* manager_; 338 scoped_ptr<Connection> connection_; 339 DISALLOW_COPY_AND_ASSIGN(ScopedConnectionHelper); 340 }; 341 342 void NotifyStatusChanged(); 343 344 DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager); 345}; 346 347std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr); 348 349} // namespace syncer 350 351#endif // SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ 352