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