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