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