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