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

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

Issue 9699057: [Sync] Move 'sync' target to sync/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Tim's comments Created 8 years, 9 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 | Annotate | Revision Log
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 "chrome/browser/sync/engine/net/server_connection_manager.h"
6
7 #include <errno.h>
8
9 #include <ostream>
10 #include <string>
11 #include <vector>
12
13 #include "base/command_line.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/sync/engine/net/url_translator.h"
16 #include "chrome/browser/sync/engine/syncer.h"
17 #include "chrome/browser/sync/engine/syncproto.h"
18 #include "googleurl/src/gurl.h"
19 #include "net/http/http_status_code.h"
20 #include "sync/protocol/sync.pb.h"
21
22 namespace browser_sync {
23
24 using std::ostream;
25 using std::string;
26 using std::vector;
27
28 static const char kSyncServerSyncPath[] = "/command/";
29
30 // At the /time/ path of the sync server, we expect to find a very simple
31 // time of day service that we can use to synchronize the local clock with
32 // server time.
33 static const char kSyncServerGetTimePath[] = "/time";
34
35 HttpResponse::HttpResponse()
36 : response_code(kUnsetResponseCode),
37 content_length(kUnsetContentLength),
38 payload_length(kUnsetPayloadLength),
39 server_status(NONE) {}
40
41 #define ENUM_CASE(x) case x: return #x; break
42
43 const char* HttpResponse::GetServerConnectionCodeString(
44 ServerConnectionCode code) {
45 switch (code) {
46 ENUM_CASE(NONE);
47 ENUM_CASE(CONNECTION_UNAVAILABLE);
48 ENUM_CASE(IO_ERROR);
49 ENUM_CASE(SYNC_SERVER_ERROR);
50 ENUM_CASE(SYNC_AUTH_ERROR);
51 ENUM_CASE(SERVER_CONNECTION_OK);
52 ENUM_CASE(RETRY);
53 }
54 NOTREACHED();
55 return "";
56 }
57
58 #undef ENUM_CASE
59
60 ServerConnectionManager::Connection::Connection(
61 ServerConnectionManager* scm) : scm_(scm) {
62 }
63
64 ServerConnectionManager::Connection::~Connection() {
65 }
66
67 bool ServerConnectionManager::Connection::ReadBufferResponse(
68 string* buffer_out,
69 HttpResponse* response,
70 bool require_response) {
71 if (net::HTTP_OK != response->response_code) {
72 response->server_status = HttpResponse::SYNC_SERVER_ERROR;
73 return false;
74 }
75
76 if (require_response && (1 > response->content_length))
77 return false;
78
79 const int64 bytes_read = ReadResponse(buffer_out,
80 static_cast<int>(response->content_length));
81 if (bytes_read != response->content_length) {
82 response->server_status = HttpResponse::IO_ERROR;
83 return false;
84 }
85 return true;
86 }
87
88 bool ServerConnectionManager::Connection::ReadDownloadResponse(
89 HttpResponse* response,
90 string* buffer_out) {
91 const int64 bytes_read = ReadResponse(buffer_out,
92 static_cast<int>(response->content_length));
93
94 if (bytes_read != response->content_length) {
95 LOG(ERROR) << "Mismatched content lengths, server claimed " <<
96 response->content_length << ", but sent " << bytes_read;
97 response->server_status = HttpResponse::IO_ERROR;
98 return false;
99 }
100 return true;
101 }
102
103 ServerConnectionManager::ScopedConnectionHelper::ScopedConnectionHelper(
104 ServerConnectionManager* manager, Connection* connection)
105 : manager_(manager), connection_(connection) {}
106
107 ServerConnectionManager::ScopedConnectionHelper::~ScopedConnectionHelper() {
108 if (connection_.get())
109 manager_->OnConnectionDestroyed(connection_.get());
110 connection_.reset();
111 }
112
113 ServerConnectionManager::Connection*
114 ServerConnectionManager::ScopedConnectionHelper::get() {
115 return connection_.get();
116 }
117
118 namespace {
119
120 string StripTrailingSlash(const string& s) {
121 int stripped_end_pos = s.size();
122 if (s.at(stripped_end_pos - 1) == '/') {
123 stripped_end_pos = stripped_end_pos - 1;
124 }
125
126 return s.substr(0, stripped_end_pos);
127 }
128
129 } // namespace
130
131 // TODO(chron): Use a GURL instead of string concatenation.
132 string ServerConnectionManager::Connection::MakeConnectionURL(
133 const string& sync_server,
134 const string& path,
135 bool use_ssl) const {
136 string connection_url = (use_ssl ? "https://" : "http://");
137 connection_url += sync_server;
138 connection_url = StripTrailingSlash(connection_url);
139 connection_url += path;
140
141 return connection_url;
142 }
143
144 int ServerConnectionManager::Connection::ReadResponse(string* out_buffer,
145 int length) {
146 int bytes_read = buffer_.length();
147 CHECK(length <= bytes_read);
148 out_buffer->assign(buffer_);
149 return bytes_read;
150 }
151
152 ScopedServerStatusWatcher::ScopedServerStatusWatcher(
153 ServerConnectionManager* conn_mgr, HttpResponse* response)
154 : conn_mgr_(conn_mgr),
155 response_(response),
156 server_reachable_(conn_mgr->server_reachable_) {
157 response->server_status = conn_mgr->server_status_;
158 }
159
160 ScopedServerStatusWatcher::~ScopedServerStatusWatcher() {
161 if (conn_mgr_->server_status_ != response_->server_status) {
162 conn_mgr_->server_status_ = response_->server_status;
163 conn_mgr_->NotifyStatusChanged();
164 return;
165 }
166 // Notify if we've gone on or offline.
167 if (server_reachable_ != conn_mgr_->server_reachable_)
168 conn_mgr_->NotifyStatusChanged();
169 }
170
171 ServerConnectionManager::ServerConnectionManager(
172 const string& server,
173 int port,
174 bool use_ssl,
175 const string& user_agent)
176 : sync_server_(server),
177 sync_server_port_(port),
178 user_agent_(user_agent),
179 use_ssl_(use_ssl),
180 proto_sync_path_(kSyncServerSyncPath),
181 get_time_path_(kSyncServerGetTimePath),
182 server_status_(HttpResponse::NONE),
183 server_reachable_(false),
184 terminated_(false),
185 active_connection_(NULL) {
186 }
187
188 ServerConnectionManager::~ServerConnectionManager() {
189 }
190
191 ServerConnectionManager::Connection*
192 ServerConnectionManager::MakeActiveConnection() {
193 base::AutoLock lock(terminate_connection_lock_);
194 DCHECK(!active_connection_);
195 if (terminated_)
196 return NULL;
197
198 active_connection_ = MakeConnection();
199 return active_connection_;
200 }
201
202 void ServerConnectionManager::OnConnectionDestroyed(Connection* connection) {
203 DCHECK(connection);
204 base::AutoLock lock(terminate_connection_lock_);
205 // |active_connection_| can be NULL already if it was aborted. Also,
206 // it can legitimately be a different Connection object if a new Connection
207 // was created after a previous one was Aborted and destroyed.
208 if (active_connection_ != connection)
209 return;
210
211 active_connection_ = NULL;
212 }
213
214 void ServerConnectionManager::NotifyStatusChanged() {
215 DCHECK(thread_checker_.CalledOnValidThread());
216 FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_,
217 OnServerConnectionEvent(
218 ServerConnectionEvent(server_status_, server_reachable_)));
219 }
220
221 bool ServerConnectionManager::PostBufferWithCachedAuth(
222 PostBufferParams* params, ScopedServerStatusWatcher* watcher) {
223 DCHECK(thread_checker_.CalledOnValidThread());
224 string path =
225 MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_));
226 return PostBufferToPath(params, path, auth_token(), watcher);
227 }
228
229 bool ServerConnectionManager::PostBufferToPath(PostBufferParams* params,
230 const string& path, const string& auth_token,
231 ScopedServerStatusWatcher* watcher) {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 DCHECK(watcher != NULL);
234
235 if (auth_token.empty()) {
236 params->response.server_status = HttpResponse::SYNC_AUTH_ERROR;
237 return false;
238 }
239
240 // When our connection object falls out of scope, it clears itself from
241 // active_connection_.
242 ScopedConnectionHelper post(this, MakeActiveConnection());
243 if (!post.get()) {
244 params->response.server_status = HttpResponse::CONNECTION_UNAVAILABLE;
245 return false;
246 }
247
248 // Note that |post| may be aborted by now, which will just cause Init to fail
249 // with CONNECTION_UNAVAILABLE.
250 bool ok = post.get()->Init(
251 path.c_str(), auth_token, params->buffer_in, &params->response);
252
253 if (params->response.server_status == HttpResponse::SYNC_AUTH_ERROR)
254 InvalidateAndClearAuthToken();
255
256 if (!ok || net::HTTP_OK != params->response.response_code)
257 return false;
258
259 if (post.get()->ReadBufferResponse(
260 &params->buffer_out, &params->response, true)) {
261 params->response.server_status = HttpResponse::SERVER_CONNECTION_OK;
262 server_reachable_ = true;
263 return true;
264 }
265 return false;
266 }
267
268 bool ServerConnectionManager::CheckTime(int32* out_time) {
269 DCHECK(thread_checker_.CalledOnValidThread());
270
271 // Verify that the server really is reachable by checking the time. We need
272 // to do this because of wifi interstitials that intercept messages from the
273 // client and return HTTP OK instead of a redirect.
274 HttpResponse response;
275 ScopedServerStatusWatcher watcher(this, &response);
276 string post_body = "command=get_time";
277
278 for (int i = 0 ; i < 3; i++) {
279 ScopedConnectionHelper post(this, MakeActiveConnection());
280 if (!post.get())
281 break;
282
283 // Note that the server's get_time path doesn't require authentication.
284 string get_time_path =
285 MakeSyncServerPath(kSyncServerGetTimePath, post_body);
286 DVLOG(1) << "Requesting get_time from:" << get_time_path;
287
288 string blank_post_body;
289 bool ok = post.get()->Init(get_time_path.c_str(), blank_post_body,
290 blank_post_body, &response);
291 if (!ok) {
292 DVLOG(1) << "Unable to check the time";
293 continue;
294 }
295 string time_response;
296 time_response.resize(
297 static_cast<string::size_type>(response.content_length));
298 ok = post.get()->ReadDownloadResponse(&response, &time_response);
299 if (!ok || string::npos !=
300 time_response.find_first_not_of("0123456789")) {
301 LOG(ERROR) << "unable to read a non-numeric response from get_time:"
302 << time_response;
303 continue;
304 }
305 *out_time = atoi(time_response.c_str());
306 DVLOG(1) << "Server was reachable.";
307 return true;
308 }
309 return false;
310 }
311
312 bool ServerConnectionManager::IsServerReachable() {
313 DCHECK(thread_checker_.CalledOnValidThread());
314 int32 time;
315 return CheckTime(&time);
316 }
317
318 bool ServerConnectionManager::IsUserAuthenticated() {
319 DCHECK(thread_checker_.CalledOnValidThread());
320 return IsGoodReplyFromServer(server_status_);
321 }
322
323 bool ServerConnectionManager::CheckServerReachable() {
324 DCHECK(thread_checker_.CalledOnValidThread());
325 const bool server_is_reachable = IsServerReachable();
326 if (server_reachable_ != server_is_reachable) {
327 server_reachable_ = server_is_reachable;
328 NotifyStatusChanged();
329 }
330 return server_is_reachable;
331 }
332
333 void ServerConnectionManager::SetServerParameters(const string& server_url,
334 int port,
335 bool use_ssl) {
336 DCHECK(thread_checker_.CalledOnValidThread());
337 sync_server_ = server_url;
338 sync_server_port_ = port;
339 use_ssl_ = use_ssl;
340 }
341
342 // Returns the current server parameters in server_url and port.
343 void ServerConnectionManager::GetServerParameters(string* server_url,
344 int* port,
345 bool* use_ssl) const {
346 if (server_url != NULL)
347 *server_url = sync_server_;
348 if (port != NULL)
349 *port = sync_server_port_;
350 if (use_ssl != NULL)
351 *use_ssl = use_ssl_;
352 }
353
354 std::string ServerConnectionManager::GetServerHost() const {
355 string server_url;
356 int port;
357 bool use_ssl;
358 GetServerParameters(&server_url, &port, &use_ssl);
359 // For unit tests.
360 if (server_url.empty())
361 return std::string();
362 // We just want the hostname, so we don't need to switch on use_ssl.
363 server_url = "http://" + server_url;
364 GURL gurl(server_url);
365 DCHECK(gurl.is_valid()) << gurl;
366 return gurl.host();
367 }
368
369 void ServerConnectionManager::AddListener(
370 ServerConnectionEventListener* listener) {
371 DCHECK(thread_checker_.CalledOnValidThread());
372 listeners_.AddObserver(listener);
373 }
374
375 void ServerConnectionManager::RemoveListener(
376 ServerConnectionEventListener* listener) {
377 DCHECK(thread_checker_.CalledOnValidThread());
378 listeners_.RemoveObserver(listener);
379 }
380
381 ServerConnectionManager::Connection* ServerConnectionManager::MakeConnection()
382 {
383 return NULL; // For testing.
384 }
385
386 void ServerConnectionManager::TerminateAllIO() {
387 base::AutoLock lock(terminate_connection_lock_);
388 terminated_ = true;
389 if (active_connection_)
390 active_connection_->Abort();
391
392 // Sever our ties to this connection object. Note that it still may exist,
393 // since we don't own it, but it has been neutered.
394 active_connection_ = NULL;
395 }
396
397 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
398 syncable::Directory* directory,
399 const std::string& share) {
400 string birthday = directory->store_birthday();
401 if (!birthday.empty())
402 csm->set_store_birthday(birthday);
403 csm->set_share(share);
404 return true;
405 }
406
407 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) {
408 s << " Response Code (bogus on error): " << hr.response_code;
409 s << " Content-Length (bogus on error): " << hr.content_length;
410 s << " Server Status: " << hr.server_status;
411 return s;
412 }
413
414 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/net/server_connection_manager.h ('k') | chrome/browser/sync/engine/net/url_translator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698