Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: sync/engine/net/server_connection_manager.cc

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sync/engine/net/server_connection_manager.h ('k') | sync/engine/net/url_translator.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 #include "sync/engine/net/server_connection_manager.h"
6
7 #include <errno.h>
8 #include <stdint.h>
9
10 #include <ostream>
11 #include <string>
12 #include <vector>
13
14 #include "base/metrics/histogram.h"
15 #include "build/build_config.h"
16 #include "net/base/net_errors.h"
17 #include "net/http/http_status_code.h"
18 #include "sync/engine/net/url_translator.h"
19 #include "sync/engine/syncer.h"
20 #include "sync/internal_api/public/base/cancelation_signal.h"
21 #include "sync/protocol/sync.pb.h"
22 #include "sync/syncable/directory.h"
23 #include "url/gurl.h"
24
25 namespace syncer {
26
27 using std::ostream;
28 using std::string;
29 using std::vector;
30
31 static const char kSyncServerSyncPath[] = "/command/";
32
33 HttpResponse::HttpResponse()
34 : response_code(kUnsetResponseCode),
35 content_length(kUnsetContentLength),
36 payload_length(kUnsetPayloadLength),
37 server_status(NONE) {}
38
39 #define ENUM_CASE(x) case x: return #x; break
40
41 const char* HttpResponse::GetServerConnectionCodeString(
42 ServerConnectionCode code) {
43 switch (code) {
44 ENUM_CASE(NONE);
45 ENUM_CASE(CONNECTION_UNAVAILABLE);
46 ENUM_CASE(IO_ERROR);
47 ENUM_CASE(SYNC_SERVER_ERROR);
48 ENUM_CASE(SYNC_AUTH_ERROR);
49 ENUM_CASE(SERVER_CONNECTION_OK);
50 ENUM_CASE(RETRY);
51 }
52 NOTREACHED();
53 return "";
54 }
55
56 #undef ENUM_CASE
57
58 ServerConnectionManager::Connection::Connection(
59 ServerConnectionManager* scm) : scm_(scm) {
60 }
61
62 ServerConnectionManager::Connection::~Connection() {
63 }
64
65 bool ServerConnectionManager::Connection::ReadBufferResponse(
66 string* buffer_out,
67 HttpResponse* response,
68 bool require_response) {
69 if (net::HTTP_OK != response->response_code) {
70 response->server_status = HttpResponse::SYNC_SERVER_ERROR;
71 return false;
72 }
73
74 if (require_response && (1 > response->content_length))
75 return false;
76
77 const int64_t bytes_read =
78 ReadResponse(buffer_out, static_cast<int>(response->content_length));
79 if (bytes_read != response->content_length) {
80 response->server_status = HttpResponse::IO_ERROR;
81 return false;
82 }
83 return true;
84 }
85
86 bool ServerConnectionManager::Connection::ReadDownloadResponse(
87 HttpResponse* response,
88 string* buffer_out) {
89 const int64_t bytes_read =
90 ReadResponse(buffer_out, static_cast<int>(response->content_length));
91
92 if (bytes_read != response->content_length) {
93 LOG(ERROR) << "Mismatched content lengths, server claimed " <<
94 response->content_length << ", but sent " << bytes_read;
95 response->server_status = HttpResponse::IO_ERROR;
96 return false;
97 }
98 return true;
99 }
100
101 ServerConnectionManager::ScopedConnectionHelper::ScopedConnectionHelper(
102 ServerConnectionManager* manager, Connection* connection)
103 : manager_(manager), connection_(connection) {}
104
105 ServerConnectionManager::ScopedConnectionHelper::~ScopedConnectionHelper() {
106 if (connection_)
107 manager_->OnConnectionDestroyed(connection_.get());
108 connection_.reset();
109 }
110
111 ServerConnectionManager::Connection*
112 ServerConnectionManager::ScopedConnectionHelper::get() {
113 return connection_.get();
114 }
115
116 namespace {
117
118 string StripTrailingSlash(const string& s) {
119 int stripped_end_pos = s.size();
120 if (s.at(stripped_end_pos - 1) == '/') {
121 stripped_end_pos = stripped_end_pos - 1;
122 }
123
124 return s.substr(0, stripped_end_pos);
125 }
126
127 } // namespace
128
129 // TODO(chron): Use a GURL instead of string concatenation.
130 string ServerConnectionManager::Connection::MakeConnectionURL(
131 const string& sync_server,
132 const string& path,
133 bool use_ssl) const {
134 string connection_url = (use_ssl ? "https://" : "http://");
135 connection_url += sync_server;
136 connection_url = StripTrailingSlash(connection_url);
137 connection_url += path;
138
139 return connection_url;
140 }
141
142 int ServerConnectionManager::Connection::ReadResponse(string* out_buffer,
143 int length) {
144 int bytes_read = buffer_.length();
145 CHECK(length <= bytes_read);
146 out_buffer->assign(buffer_);
147 return bytes_read;
148 }
149
150 ServerConnectionManager::ServerConnectionManager(
151 const string& server,
152 int port,
153 bool use_ssl,
154 CancelationSignal* cancelation_signal)
155 : sync_server_(server),
156 sync_server_port_(port),
157 use_ssl_(use_ssl),
158 proto_sync_path_(kSyncServerSyncPath),
159 server_status_(HttpResponse::NONE),
160 terminated_(false),
161 active_connection_(NULL),
162 cancelation_signal_(cancelation_signal),
163 signal_handler_registered_(false) {
164 signal_handler_registered_ = cancelation_signal_->TryRegisterHandler(this);
165 if (!signal_handler_registered_) {
166 // Calling a virtual function from a constructor. We can get away with it
167 // here because ServerConnectionManager::OnSignalReceived() is the function
168 // we want to call.
169 OnSignalReceived();
170 }
171 }
172
173 ServerConnectionManager::~ServerConnectionManager() {
174 if (signal_handler_registered_) {
175 cancelation_signal_->UnregisterHandler(this);
176 }
177 }
178
179 ServerConnectionManager::Connection*
180 ServerConnectionManager::MakeActiveConnection() {
181 base::AutoLock lock(terminate_connection_lock_);
182 DCHECK(!active_connection_);
183 if (terminated_)
184 return NULL;
185
186 active_connection_ = MakeConnection();
187 return active_connection_;
188 }
189
190 void ServerConnectionManager::OnConnectionDestroyed(Connection* connection) {
191 DCHECK(connection);
192 base::AutoLock lock(terminate_connection_lock_);
193 // |active_connection_| can be NULL already if it was aborted. Also,
194 // it can legitimately be a different Connection object if a new Connection
195 // was created after a previous one was Aborted and destroyed.
196 if (active_connection_ != connection)
197 return;
198
199 active_connection_ = NULL;
200 }
201
202 bool ServerConnectionManager::SetAuthToken(const std::string& auth_token) {
203 DCHECK(thread_checker_.CalledOnValidThread());
204 if (previously_invalidated_token != auth_token) {
205 auth_token_.assign(auth_token);
206 previously_invalidated_token = std::string();
207 return true;
208 }
209
210 // This could happen in case like server outage/bug. E.g. token returned by
211 // first request is considered invalid by sync server and because
212 // of token server's caching policy, etc, same token is returned on second
213 // request. Need to notify sync frontend again to request new token,
214 // otherwise backend will stay in SYNC_AUTH_ERROR state while frontend thinks
215 // everything is fine and takes no actions.
216 SetServerStatus(HttpResponse::SYNC_AUTH_ERROR);
217 return false;
218 }
219
220 void ServerConnectionManager::InvalidateAndClearAuthToken() {
221 DCHECK(thread_checker_.CalledOnValidThread());
222 // Copy over the token to previous invalid token.
223 if (!auth_token_.empty()) {
224 previously_invalidated_token.assign(auth_token_);
225 auth_token_ = std::string();
226 }
227 }
228
229 void ServerConnectionManager::SetServerStatus(
230 HttpResponse::ServerConnectionCode server_status) {
231 // SYNC_AUTH_ERROR is permanent error. Need to notify observer to take
232 // action externally to resolve.
233 if (server_status != HttpResponse::SYNC_AUTH_ERROR &&
234 server_status_ == server_status) {
235 return;
236 }
237 server_status_ = server_status;
238 NotifyStatusChanged();
239 }
240
241 void ServerConnectionManager::NotifyStatusChanged() {
242 DCHECK(thread_checker_.CalledOnValidThread());
243 FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_,
244 OnServerConnectionEvent(
245 ServerConnectionEvent(server_status_)));
246 }
247
248 bool ServerConnectionManager::PostBufferWithCachedAuth(
249 PostBufferParams* params) {
250 DCHECK(thread_checker_.CalledOnValidThread());
251 string path =
252 MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_));
253 bool result = PostBufferToPath(params, path, auth_token());
254 SetServerStatus(params->response.server_status);
255 return result;
256 }
257
258 bool ServerConnectionManager::PostBufferToPath(PostBufferParams* params,
259 const string& path,
260 const string& auth_token) {
261 DCHECK(thread_checker_.CalledOnValidThread());
262
263 // TODO(pavely): crbug.com/273096. Check for "credentials_lost" is added as
264 // workaround for M29 blocker to avoid sending RPC to sync with known invalid
265 // token but instead to trigger refreshing token in ProfileSyncService. Need
266 // to clean it.
267 if (auth_token.empty() || auth_token == "credentials_lost") {
268 params->response.server_status = HttpResponse::SYNC_AUTH_ERROR;
269 // Print a log to distinguish this "known failure" from others.
270 LOG(WARNING) << "ServerConnectionManager forcing SYNC_AUTH_ERROR";
271 return false;
272 }
273
274 // When our connection object falls out of scope, it clears itself from
275 // active_connection_.
276 ScopedConnectionHelper post(this, MakeActiveConnection());
277 if (!post.get()) {
278 params->response.server_status = HttpResponse::CONNECTION_UNAVAILABLE;
279 return false;
280 }
281
282 // Note that |post| may be aborted by now, which will just cause Init to fail
283 // with CONNECTION_UNAVAILABLE.
284 bool ok = post.get()->Init(
285 path.c_str(), auth_token, params->buffer_in, &params->response);
286
287 if (params->response.server_status == HttpResponse::SYNC_AUTH_ERROR) {
288 InvalidateAndClearAuthToken();
289 }
290
291 if (!ok || net::HTTP_OK != params->response.response_code)
292 return false;
293
294 if (post.get()->ReadBufferResponse(
295 &params->buffer_out, &params->response, true)) {
296 params->response.server_status = HttpResponse::SERVER_CONNECTION_OK;
297 return true;
298 }
299 return false;
300 }
301
302 void ServerConnectionManager::AddListener(
303 ServerConnectionEventListener* listener) {
304 DCHECK(thread_checker_.CalledOnValidThread());
305 listeners_.AddObserver(listener);
306 }
307
308 void ServerConnectionManager::RemoveListener(
309 ServerConnectionEventListener* listener) {
310 DCHECK(thread_checker_.CalledOnValidThread());
311 listeners_.RemoveObserver(listener);
312 }
313
314 ServerConnectionManager::Connection* ServerConnectionManager::MakeConnection() {
315 return NULL; // For testing.
316 }
317
318 void ServerConnectionManager::OnSignalReceived() {
319 base::AutoLock lock(terminate_connection_lock_);
320 terminated_ = true;
321 if (active_connection_)
322 active_connection_->Abort();
323
324 // Sever our ties to this connection object. Note that it still may exist,
325 // since we don't own it, but it has been neutered.
326 active_connection_ = NULL;
327 }
328
329 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) {
330 s << " Response Code (bogus on error): " << hr.response_code;
331 s << " Content-Length (bogus on error): " << hr.content_length;
332 s << " Server Status: "
333 << HttpResponse::GetServerConnectionCodeString(hr.server_status);
334 return s;
335 }
336
337 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/engine/net/server_connection_manager.h ('k') | sync/engine/net/url_translator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698