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
21 namespace syncable {
22 class WriteTransaction;
23 class DirectoryManager;
24 }
25
26 namespace sync_pb {
27 class ClientToServerMessage;
28 }
29
30 struct RequestTimingInfo;
31
32 namespace browser_sync {
33
34 class ClientToServerMessage;
35
36 // How many connection errors are accepted before network handles are closed
37 // and reopened.
38 static const int32 kMaxConnectionErrorsBeforeReset = 10;
39
40 static const int32 kUnsetResponseCode = -1;
41 static const int32 kUnsetContentLength = -1;
42 static 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.
47 struct 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
HttpResponseHttpResponse100 HttpResponse()
101 : response_code(kUnsetResponseCode),
102 content_length(kUnsetContentLength),
103 payload_length(kUnsetPayloadLength),
104 server_status(NONE) {}
105 };
106
IsGoodReplyFromServer(HttpResponse::ServerConnectionCode code)107 inline bool IsGoodReplyFromServer(HttpResponse::ServerConnectionCode code) {
108 return code >= HttpResponse::SERVER_CONNECTION_OK;
109 }
110
111 // TODO(tim): Deprecated.
112 struct ServerConnectionEvent {
113 // Traits.
114 typedef ServerConnectionEvent EventType;
115 enum WhatHappened {
116 SHUTDOWN,
117 STATUS_CHANGED
118 };
119
IsChannelShutdownEventServerConnectionEvent120 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
129 struct ServerConnectionEvent2 {
130 HttpResponse::ServerConnectionCode connection_code;
131 bool server_reachable;
ServerConnectionEvent2ServerConnectionEvent2132 ServerConnectionEvent2(HttpResponse::ServerConnectionCode code,
133 bool server_reachable) :
134 connection_code(code), server_reachable(server_reachable) {}
135 };
136
137 class ServerConnectionEventListener {
138 public:
139 virtual void OnServerConnectionEvent(const ServerConnectionEvent2& event) = 0;
140 protected:
~ServerConnectionEventListener()141 virtual ~ServerConnectionEventListener() {}
142 };
143
144 class 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.
148 class 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.
167 class 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:
Post(ServerConnectionManager * scm)185 explicit Post(ServerConnectionManager* scm) : scm_(scm), timing_info_(0) {
186 }
~Post()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
set_timing_info(RequestTimingInfo * timing_info)199 void set_timing_info(RequestTimingInfo* timing_info) {
200 timing_info_ = timing_info;
201 }
timing_info()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
GetServerParams(std::string * server,int * server_port,bool * use_ssl)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
channel()258 inline Channel* channel() const { return channel_; }
259
260 void AddListener(ServerConnectionEventListener* listener);
261 void RemoveListener(ServerConnectionEventListener* listener);
262
user_agent()263 inline std::string user_agent() const { return user_agent_; }
264
server_status()265 inline HttpResponse::ServerConnectionCode server_status() const {
266 return server_status_;
267 }
268
server_reachable()269 inline bool server_reachable() const { return server_reachable_; }
270
client_id()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
terminate_all_io()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
set_client_id(const std::string & client_id)298 void set_client_id(const std::string& client_id) {
299 DCHECK(client_id_.empty());
300 client_id_.assign(client_id);
301 }
302
set_auth_token(const std::string & auth_token)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
auth_token()309 const std::string auth_token() const {
310 base::AutoLock lock(auth_token_mutex_);
311 return auth_token_;
312 }
313
314 protected:
proto_sync_path()315 inline std::string proto_sync_path() const {
316 base::AutoLock lock(path_mutex_);
317 return proto_sync_path_;
318 }
319
get_time_path()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.
395 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
396 syncable::DirectoryManager* manager,
397 const std::string& share);
398
399 std::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