• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/internal_api/public/base/cancelation_observer.h"
20 #include "sync/syncable/syncable_id.h"
21 
22 namespace sync_pb {
23 class ClientToServerMessage;
24 }
25 
26 namespace syncer {
27 
28 class CancelationSignal;
29 
30 namespace syncable {
31 class Directory;
32 }
33 
34 static const int32 kUnsetResponseCode = -1;
35 static const int32 kUnsetContentLength = -1;
36 static const int32 kUnsetPayloadLength = -1;
37 
38 // HttpResponse gathers the relevant output properties of an HTTP request.
39 // Depending on the value of the server_status code, response_code, and
40 // content_length may not be valid.
41 struct SYNC_EXPORT_PRIVATE HttpResponse {
42   enum ServerConnectionCode {
43     // For uninitialized state.
44     NONE,
45 
46     // CONNECTION_UNAVAILABLE is returned when InternetConnect() fails.
47     CONNECTION_UNAVAILABLE,
48 
49     // IO_ERROR is returned when reading/writing to a buffer has failed.
50     IO_ERROR,
51 
52     // SYNC_SERVER_ERROR is returned when the HTTP status code indicates that
53     // a non-auth error has occured.
54     SYNC_SERVER_ERROR,
55 
56     // SYNC_AUTH_ERROR is returned when the HTTP status code indicates that an
57     // auth error has occured (i.e. a 401 or sync-specific AUTH_INVALID
58     // response)
59     // TODO(tim): Caring about AUTH_INVALID is a layering violation. But
60     // this app-specific logic is being added as a stable branch hotfix so
61     // minimal changes prevail for the moment.  Fix this! Bug 35060.
62     SYNC_AUTH_ERROR,
63 
64     // SERVER_CONNECTION_OK is returned when request was handled correctly.
65     SERVER_CONNECTION_OK,
66 
67     // RETRY is returned when a Commit request fails with a RETRY response from
68     // the server.
69     //
70     // TODO(idana): the server no longer returns RETRY so we should remove this
71     // value.
72     RETRY,
73   };
74 
75   // The HTTP Status code.
76   int64 response_code;
77 
78   // The value of the Content-length header.
79   int64 content_length;
80 
81   // The size of a download request's payload.
82   int64 payload_length;
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 
96 struct ServerConnectionEvent {
97   HttpResponse::ServerConnectionCode connection_code;
ServerConnectionEventServerConnectionEvent98   explicit ServerConnectionEvent(HttpResponse::ServerConnectionCode code) :
99       connection_code(code) {}
100 };
101 
102 class SYNC_EXPORT_PRIVATE ServerConnectionEventListener {
103  public:
104   virtual void OnServerConnectionEvent(const ServerConnectionEvent& event) = 0;
105  protected:
~ServerConnectionEventListener()106   virtual ~ServerConnectionEventListener() {}
107 };
108 
109 class 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.
113 class 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 //
128 class SYNC_EXPORT_PRIVATE ServerConnectionManager : public CancelationObserver {
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 
GetServerParams(std::string * server,int * server_port,bool * use_ssl)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                           CancelationSignal* cancelation_signal);
185 
186   virtual ~ServerConnectionManager();
187 
188   // POSTS buffer_in and reads a response into buffer_out. Uses our currently
189   // set auth token in our headers.
190   //
191   // Returns true if executed successfully.
192   virtual bool PostBufferWithCachedAuth(PostBufferParams* params,
193                                         ScopedServerStatusWatcher* watcher);
194 
195   void AddListener(ServerConnectionEventListener* listener);
196   void RemoveListener(ServerConnectionEventListener* listener);
197 
server_status()198   inline HttpResponse::ServerConnectionCode server_status() const {
199     DCHECK(thread_checker_.CalledOnValidThread());
200     return server_status_;
201   }
202 
client_id()203   const std::string client_id() const { return client_id_; }
204 
205   // Returns the current server parameters in server_url, port and use_ssl.
206   void GetServerParameters(std::string* server_url,
207                            int* port,
208                            bool* use_ssl) const;
209 
210   std::string GetServerHost() const;
211 
212   // Factory method to create an Connection object we can use for
213   // communication with the server.
214   virtual Connection* MakeConnection();
215 
216   // Closes any active network connections to the sync server.
217   // We expect this to get called on a different thread than the valid
218   // ThreadChecker thread, as we want to kill any pending http traffic without
219   // having to wait for the request to complete.
220   virtual void OnSignalReceived() OVERRIDE FINAL;
221 
set_client_id(const std::string & client_id)222   void set_client_id(const std::string& client_id) {
223     DCHECK(thread_checker_.CalledOnValidThread());
224     DCHECK(client_id_.empty());
225     client_id_.assign(client_id);
226   }
227 
228   // Sets a new auth token and time.
229   bool SetAuthToken(const std::string& auth_token);
230 
231   // Our out-of-band invalidations channel can encounter auth errors,
232   // and when it does so it tells us via this method to prevent making more
233   // requests with known-bad tokens. This will put the
234   // ServerConnectionManager in an auth error state as if it received an
235   // HTTP 401 from sync servers.
236   void OnInvalidationCredentialsRejected();
237 
HasInvalidAuthToken()238   bool HasInvalidAuthToken() {
239     return auth_token_.empty();
240   }
241 
auth_token()242   const std::string auth_token() const {
243     DCHECK(thread_checker_.CalledOnValidThread());
244     return auth_token_;
245   }
246 
247  protected:
proto_sync_path()248   inline std::string proto_sync_path() const {
249     return proto_sync_path_;
250   }
251 
252   // Updates server_status_ and notifies listeners if server_status_ changed
253   void SetServerStatus(HttpResponse::ServerConnectionCode server_status);
254 
255   // NOTE: Tests rely on this protected function being virtual.
256   //
257   // Internal PostBuffer base function.
258   virtual bool PostBufferToPath(PostBufferParams*,
259                                 const std::string& path,
260                                 const std::string& auth_token,
261                                 ScopedServerStatusWatcher* watcher);
262 
263   // An internal helper to clear our auth_token_ and cache the old version
264   // in |previously_invalidated_token_| to shelter us from retrying with a
265   // known bad token.
266   void InvalidateAndClearAuthToken();
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 
292   // The auth token to use in authenticated requests.
293   std::string auth_token_;
294 
295   // The previous auth token that is invalid now.
296   std::string previously_invalidated_token;
297 
298   ObserverList<ServerConnectionEventListener> listeners_;
299 
300   HttpResponse::ServerConnectionCode server_status_;
301 
302   base::ThreadChecker thread_checker_;
303 
304   // Protects all variables below to allow bailing out of active connections.
305   base::Lock terminate_connection_lock_;
306 
307   // If true, we've been told to terminate IO and expect to be destroyed
308   // shortly.  No future network requests will be made.
309   bool terminated_;
310 
311   // A non-owning pointer to any active http connection, so that we can abort
312   // it if necessary.
313   Connection* active_connection_;
314 
315  private:
316   friend class Connection;
317   friend class ScopedServerStatusWatcher;
318 
319   // A class to help deal with cleaning up active Connection objects when (for
320   // ex) multiple early-exits are present in some scope. ScopedConnectionHelper
321   // informs the ServerConnectionManager before the Connection object it takes
322   // ownership of is destroyed.
323   class ScopedConnectionHelper {
324    public:
325     // |manager| must outlive this. Takes ownership of |connection|.
326     ScopedConnectionHelper(ServerConnectionManager* manager,
327                            Connection* connection);
328     ~ScopedConnectionHelper();
329     Connection* get();
330    private:
331     ServerConnectionManager* manager_;
332     scoped_ptr<Connection> connection_;
333     DISALLOW_COPY_AND_ASSIGN(ScopedConnectionHelper);
334   };
335 
336   void NotifyStatusChanged();
337 
338   CancelationSignal* const cancelation_signal_;
339   bool signal_handler_registered_;
340 
341   DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager);
342 };
343 
344 std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr);
345 
346 }  // namespace syncer
347 
348 #endif  // SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
349