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