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