| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ |
| #define SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ |
| |
| #include <stdint.h> |
| |
| #include <iosfwd> |
| #include <memory> |
| #include <string> |
| |
| #include "base/atomicops.h" |
| #include "base/macros.h" |
| #include "base/observer_list.h" |
| #include "base/strings/string_util.h" |
| #include "base/synchronization/lock.h" |
| #include "base/threading/non_thread_safe.h" |
| #include "base/threading/thread_checker.h" |
| #include "sync/base/sync_export.h" |
| #include "sync/internal_api/public/base/cancelation_observer.h" |
| #include "sync/syncable/syncable_id.h" |
| |
| namespace sync_pb { |
| class ClientToServerMessage; |
| } |
| |
| namespace syncer { |
| |
| class CancelationSignal; |
| |
| namespace syncable { |
| class Directory; |
| } |
| |
| static const int32_t kUnsetResponseCode = -1; |
| static const int32_t kUnsetContentLength = -1; |
| static const int32_t kUnsetPayloadLength = -1; |
| |
| // HttpResponse gathers the relevant output properties of an HTTP request. |
| // Depending on the value of the server_status code, response_code, and |
| // content_length may not be valid. |
| struct SYNC_EXPORT HttpResponse { |
| enum ServerConnectionCode { |
| // For uninitialized state. |
| NONE, |
| |
| // CONNECTION_UNAVAILABLE is returned when InternetConnect() fails. |
| CONNECTION_UNAVAILABLE, |
| |
| // IO_ERROR is returned when reading/writing to a buffer has failed. |
| IO_ERROR, |
| |
| // SYNC_SERVER_ERROR is returned when the HTTP status code indicates that |
| // a non-auth error has occured. |
| SYNC_SERVER_ERROR, |
| |
| // SYNC_AUTH_ERROR is returned when the HTTP status code indicates that an |
| // auth error has occured (i.e. a 401 or sync-specific AUTH_INVALID |
| // response) |
| // TODO(tim): Caring about AUTH_INVALID is a layering violation. But |
| // this app-specific logic is being added as a stable branch hotfix so |
| // minimal changes prevail for the moment. Fix this! Bug 35060. |
| SYNC_AUTH_ERROR, |
| |
| // SERVER_CONNECTION_OK is returned when request was handled correctly. |
| SERVER_CONNECTION_OK, |
| |
| // RETRY is returned when a Commit request fails with a RETRY response from |
| // the server. |
| // |
| // TODO(idana): the server no longer returns RETRY so we should remove this |
| // value. |
| RETRY, |
| }; |
| |
| // The HTTP Status code. |
| int64_t response_code; |
| |
| // The value of the Content-length header. |
| int64_t content_length; |
| |
| // The size of a download request's payload. |
| int64_t payload_length; |
| |
| // Identifies the type of failure, if any. |
| ServerConnectionCode server_status; |
| |
| HttpResponse(); |
| |
| static const char* GetServerConnectionCodeString( |
| ServerConnectionCode code); |
| }; |
| |
| struct ServerConnectionEvent { |
| HttpResponse::ServerConnectionCode connection_code; |
| explicit ServerConnectionEvent(HttpResponse::ServerConnectionCode code) : |
| connection_code(code) {} |
| }; |
| |
| class SYNC_EXPORT ServerConnectionEventListener { |
| public: |
| virtual void OnServerConnectionEvent(const ServerConnectionEvent& event) = 0; |
| protected: |
| virtual ~ServerConnectionEventListener() {} |
| }; |
| |
| // Use this class to interact with the sync server. |
| // The ServerConnectionManager currently supports POSTing protocol buffers. |
| // |
| class SYNC_EXPORT ServerConnectionManager : public CancelationObserver { |
| public: |
| // buffer_in - will be POSTed |
| // buffer_out - string will be overwritten with response |
| struct PostBufferParams { |
| std::string buffer_in; |
| std::string buffer_out; |
| HttpResponse response; |
| }; |
| |
| // Abstract class providing network-layer functionality to the |
| // ServerConnectionManager. Subclasses implement this using an HTTP stack of |
| // their choice. |
| class Connection { |
| public: |
| explicit Connection(ServerConnectionManager* scm); |
| virtual ~Connection(); |
| |
| // Called to initialize and perform an HTTP POST. |
| virtual bool Init(const char* path, |
| const std::string& auth_token, |
| const std::string& payload, |
| HttpResponse* response) = 0; |
| |
| // Immediately abandons a pending HTTP POST request and unblocks caller |
| // in Init. |
| virtual void Abort() = 0; |
| |
| bool ReadBufferResponse(std::string* buffer_out, HttpResponse* response, |
| bool require_response); |
| bool ReadDownloadResponse(HttpResponse* response, std::string* buffer_out); |
| |
| protected: |
| std::string MakeConnectionURL(const std::string& sync_server, |
| const std::string& path, |
| bool use_ssl) const; |
| |
| void GetServerParams(std::string* server, |
| int* server_port, |
| bool* use_ssl) const { |
| server->assign(scm_->sync_server_); |
| *server_port = scm_->sync_server_port_; |
| *use_ssl = scm_->use_ssl_; |
| } |
| |
| std::string buffer_; |
| ServerConnectionManager* scm_; |
| |
| private: |
| int ReadResponse(std::string* buffer, int length); |
| }; |
| |
| ServerConnectionManager(const std::string& server, |
| int port, |
| bool use_ssl, |
| CancelationSignal* cancelation_signal); |
| |
| ~ServerConnectionManager() override; |
| |
| // POSTS buffer_in and reads a response into buffer_out. Uses our currently |
| // set auth token in our headers. |
| // |
| // Returns true if executed successfully. |
| virtual bool PostBufferWithCachedAuth(PostBufferParams* params); |
| |
| void AddListener(ServerConnectionEventListener* listener); |
| void RemoveListener(ServerConnectionEventListener* listener); |
| |
| inline HttpResponse::ServerConnectionCode server_status() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return server_status_; |
| } |
| |
| const std::string client_id() const { return client_id_; } |
| |
| // Factory method to create an Connection object we can use for |
| // communication with the server. |
| virtual Connection* MakeConnection(); |
| |
| // Closes any active network connections to the sync server. |
| // We expect this to get called on a different thread than the valid |
| // ThreadChecker thread, as we want to kill any pending http traffic without |
| // having to wait for the request to complete. |
| void OnSignalReceived() final; |
| |
| void set_client_id(const std::string& client_id) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| DCHECK(client_id_.empty()); |
| client_id_.assign(client_id); |
| } |
| |
| // Sets a new auth token and time. |
| bool SetAuthToken(const std::string& auth_token); |
| |
| bool HasInvalidAuthToken() { |
| return auth_token_.empty(); |
| } |
| |
| const std::string auth_token() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return auth_token_; |
| } |
| |
| protected: |
| inline std::string proto_sync_path() const { |
| return proto_sync_path_; |
| } |
| |
| // Updates server_status_ and notifies listeners if server_status_ changed |
| void SetServerStatus(HttpResponse::ServerConnectionCode server_status); |
| |
| // NOTE: Tests rely on this protected function being virtual. |
| // |
| // Internal PostBuffer base function. |
| virtual bool PostBufferToPath(PostBufferParams*, |
| const std::string& path, |
| const std::string& auth_token); |
| |
| // An internal helper to clear our auth_token_ and cache the old version |
| // in |previously_invalidated_token_| to shelter us from retrying with a |
| // known bad token. |
| void InvalidateAndClearAuthToken(); |
| |
| // Helper to check terminated flags and build a Connection object, installing |
| // it as the |active_connection_|. If this ServerConnectionManager has been |
| // terminated, this will return NULL. |
| Connection* MakeActiveConnection(); |
| |
| // Called by Connection objects as they are destroyed to allow the |
| // ServerConnectionManager to cleanup active connections. |
| void OnConnectionDestroyed(Connection* connection); |
| |
| // The sync_server_ is the server that requests will be made to. |
| std::string sync_server_; |
| |
| // The sync_server_port_ is the port that HTTP requests will be made on. |
| int sync_server_port_; |
| |
| // The unique id of the user's client. |
| std::string client_id_; |
| |
| // Indicates whether or not requests should be made using HTTPS. |
| bool use_ssl_; |
| |
| // The paths we post to. |
| std::string proto_sync_path_; |
| |
| // The auth token to use in authenticated requests. |
| std::string auth_token_; |
| |
| // The previous auth token that is invalid now. |
| std::string previously_invalidated_token; |
| |
| base::ObserverList<ServerConnectionEventListener> listeners_; |
| |
| HttpResponse::ServerConnectionCode server_status_; |
| |
| base::ThreadChecker thread_checker_; |
| |
| // Protects all variables below to allow bailing out of active connections. |
| base::Lock terminate_connection_lock_; |
| |
| // If true, we've been told to terminate IO and expect to be destroyed |
| // shortly. No future network requests will be made. |
| bool terminated_; |
| |
| // A non-owning pointer to any active http connection, so that we can abort |
| // it if necessary. |
| Connection* active_connection_; |
| |
| private: |
| // A class to help deal with cleaning up active Connection objects when (for |
| // ex) multiple early-exits are present in some scope. ScopedConnectionHelper |
| // informs the ServerConnectionManager before the Connection object it takes |
| // ownership of is destroyed. |
| class ScopedConnectionHelper { |
| public: |
| // |manager| must outlive this. Takes ownership of |connection|. |
| ScopedConnectionHelper(ServerConnectionManager* manager, |
| Connection* connection); |
| ~ScopedConnectionHelper(); |
| Connection* get(); |
| private: |
| ServerConnectionManager* manager_; |
| std::unique_ptr<Connection> connection_; |
| DISALLOW_COPY_AND_ASSIGN(ScopedConnectionHelper); |
| }; |
| |
| void NotifyStatusChanged(); |
| |
| CancelationSignal* const cancelation_signal_; |
| bool signal_handler_registered_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager); |
| }; |
| |
| std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr); |
| |
| } // namespace syncer |
| |
| #endif // SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_ |