| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/sync/engine/net/server_connection_manager.h" |
| |
| #include <errno.h> |
| |
| #include <ostream> |
| |
| #include "base/check_is_test.h" |
| #include "base/feature_list.h" |
| #include "base/metrics/histogram.h" |
| #include "base/observer_list.h" |
| #include "build/build_config.h" |
| #include "components/sync/base/features.h" |
| #include "components/sync/engine/cancelation_signal.h" |
| #include "components/sync/engine/net/url_translator.h" |
| #include "components/sync/engine/syncer.h" |
| #include "net/http/http_status_code.h" |
| #include "url/gurl.h" |
| |
| namespace syncer { |
| namespace { |
| |
| #define ENUM_CASE(x) \ |
| case HttpResponse::x: \ |
| return #x; \ |
| break |
| |
| const char* GetServerConnectionCodeString( |
| HttpResponse::ServerConnectionCode code) { |
| switch (code) { |
| ENUM_CASE(NONE); |
| ENUM_CASE(CONNECTION_UNAVAILABLE); |
| ENUM_CASE(SYNC_SERVER_ERROR); |
| ENUM_CASE(SYNC_AUTH_ERROR); |
| ENUM_CASE(SERVER_CONNECTION_OK); |
| } |
| NOTREACHED(); |
| } |
| |
| #undef ENUM_CASE |
| |
| } // namespace |
| |
| HttpResponse::HttpResponse() |
| : server_status(NONE), |
| net_error_code(-1), |
| http_status_code(-1), |
| content_length(-1) {} |
| |
| // static |
| HttpResponse HttpResponse::Uninitialized() { |
| return HttpResponse(); |
| } |
| |
| // static |
| HttpResponse HttpResponse::ForNetError(int net_error_code) { |
| HttpResponse response; |
| response.server_status = CONNECTION_UNAVAILABLE; |
| response.net_error_code = net_error_code; |
| return response; |
| } |
| |
| // static |
| HttpResponse HttpResponse::ForUnspecifiedError() { |
| HttpResponse response; |
| response.server_status = CONNECTION_UNAVAILABLE; |
| return response; |
| } |
| |
| // static |
| HttpResponse HttpResponse::ForHttpStatusCode(int http_status_code) { |
| HttpResponse response; |
| if (http_status_code == net::HTTP_OK) { |
| response.server_status = SERVER_CONNECTION_OK; |
| } else if (http_status_code == net::HTTP_UNAUTHORIZED) { |
| response.server_status = SYNC_AUTH_ERROR; |
| } else { |
| response.server_status = SYNC_SERVER_ERROR; |
| } |
| response.http_status_code = http_status_code; |
| return response; |
| } |
| |
| // static |
| HttpResponse HttpResponse::ForSuccessForTest() { |
| CHECK_IS_TEST(); |
| HttpResponse response; |
| response.server_status = SERVER_CONNECTION_OK; |
| response.http_status_code = net::HTTP_OK; |
| return response; |
| } |
| |
| ServerConnectionManager::ServerConnectionManager() |
| : server_response_(HttpResponse::Uninitialized()) {} |
| |
| ServerConnectionManager::~ServerConnectionManager() = default; |
| |
| bool ServerConnectionManager::SetAccessTokenInfo( |
| const signin::AccessTokenInfo& access_token_info) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| access_token_info_ = access_token_info; |
| if (IsAccessTokenValid()) { |
| return true; |
| } |
| |
| ClearAccessToken(); |
| |
| // The token was probably expired. Notify sync frontend again to request new |
| // token, otherwise backend will stay in SYNC_AUTH_ERROR state while frontend |
| // thinks everything is fine and takes no actions. |
| SetServerResponse(HttpResponse::ForHttpStatusCode(net::HTTP_UNAUTHORIZED)); |
| return false; |
| } |
| |
| bool ServerConnectionManager::HasAccessToken() const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return !access_token_info_.token.empty(); |
| } |
| |
| void ServerConnectionManager::ClearAccessToken() { |
| access_token_info_ = signin::AccessTokenInfo(); |
| } |
| |
| std::string ServerConnectionManager::GetAccessToken() const { |
| return access_token_info_.token; |
| } |
| |
| bool ServerConnectionManager::IsAccessTokenValid() const { |
| if (access_token_info_.token.empty()) { |
| return false; |
| } |
| |
| // Assume the token is valid if the expiration time is not set or the |
| // validation feature is disabled. |
| if (access_token_info_.expiration_time.is_null() || |
| !base::FeatureList::IsEnabled(kSyncValidateAccessToken)) { |
| return true; |
| } |
| |
| return access_token_info_.expiration_time > base::Time::Now(); |
| } |
| |
| void ServerConnectionManager::SetServerResponse( |
| const HttpResponse& server_response) { |
| // Notify only if the server status changed, except for SYNC_AUTH_ERROR: In |
| // that case, always notify in order to poke observers to do something about |
| // it. |
| bool notify = |
| (server_response.server_status == HttpResponse::SYNC_AUTH_ERROR || |
| server_response_.server_status != server_response.server_status); |
| server_response_ = server_response; |
| if (notify) { |
| NotifyStatusChanged(); |
| } |
| } |
| |
| void ServerConnectionManager::NotifyStatusChanged() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| for (ServerConnectionEventListener& observer : listeners_) { |
| observer.OnServerConnectionEvent( |
| ServerConnectionEvent(server_response_.server_status)); |
| } |
| } |
| |
| HttpResponse ServerConnectionManager::PostBufferWithCachedAuth( |
| const std::string& buffer_in, |
| std::string* buffer_out) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| HttpResponse http_response = PostBuffer(buffer_in, buffer_out); |
| SetServerResponse(http_response); |
| return server_response_; |
| } |
| |
| void ServerConnectionManager::AddListener( |
| ServerConnectionEventListener* listener) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| listeners_.AddObserver(listener); |
| } |
| |
| void ServerConnectionManager::RemoveListener( |
| ServerConnectionEventListener* listener) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| listeners_.RemoveObserver(listener); |
| } |
| |
| std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr) { |
| s << " Response Code (bogus on error): " << hr.http_status_code; |
| s << " Content-Length (bogus on error): " << hr.content_length; |
| s << " Server Status: " << GetServerConnectionCodeString(hr.server_status); |
| return s; |
| } |
| |
| } // namespace syncer |