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

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

Issue 7792022: sync: abort active HTTP requests on shutdown. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: initial Created 9 years, 3 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sync/engine/net/server_connection_manager.h" 5 #include "chrome/browser/sync/engine/net/server_connection_manager.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 8
9 #include <ostream> 9 #include <ostream>
10 #include <string> 10 #include <string>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/auto_reset.h"
13 #include "base/command_line.h" 14 #include "base/command_line.h"
14 #include "build/build_config.h" 15 #include "build/build_config.h"
15 #include "chrome/browser/sync/engine/net/url_translator.h" 16 #include "chrome/browser/sync/engine/net/url_translator.h"
16 #include "chrome/browser/sync/engine/syncer.h" 17 #include "chrome/browser/sync/engine/syncer.h"
17 #include "chrome/browser/sync/engine/syncproto.h" 18 #include "chrome/browser/sync/engine/syncproto.h"
18 #include "chrome/browser/sync/protocol/sync.pb.h" 19 #include "chrome/browser/sync/protocol/sync.pb.h"
19 #include "chrome/browser/sync/syncable/directory_manager.h" 20 #include "chrome/browser/sync/syncable/directory_manager.h"
20 #include "chrome/common/net/http_return.h" 21 #include "chrome/common/net/http_return.h"
21 #include "googleurl/src/gurl.h" 22 #include "googleurl/src/gurl.h"
22 23
(...skipping 28 matching lines...) Expand all
51 ENUM_CASE(SYNC_AUTH_ERROR); 52 ENUM_CASE(SYNC_AUTH_ERROR);
52 ENUM_CASE(SERVER_CONNECTION_OK); 53 ENUM_CASE(SERVER_CONNECTION_OK);
53 ENUM_CASE(RETRY); 54 ENUM_CASE(RETRY);
54 } 55 }
55 NOTREACHED(); 56 NOTREACHED();
56 return ""; 57 return "";
57 } 58 }
58 59
59 #undef ENUM_CASE 60 #undef ENUM_CASE
60 61
61 bool ServerConnectionManager::Post::ReadBufferResponse( 62 ServerConnectionManager::Connection::Connection(
63 ServerConnectionManager* scm) : scm_(scm), timing_info_(0) {
64 }
65
66 ServerConnectionManager::Connection::~Connection() {
67 }
68
69 bool ServerConnectionManager::Connection::ReadBufferResponse(
62 string* buffer_out, 70 string* buffer_out,
63 HttpResponse* response, 71 HttpResponse* response,
64 bool require_response) { 72 bool require_response) {
65 if (RC_REQUEST_OK != response->response_code) { 73 if (RC_REQUEST_OK != response->response_code) {
66 response->server_status = HttpResponse::SYNC_SERVER_ERROR; 74 response->server_status = HttpResponse::SYNC_SERVER_ERROR;
67 return false; 75 return false;
68 } 76 }
69 77
70 if (require_response && (1 > response->content_length)) 78 if (require_response && (1 > response->content_length))
71 return false; 79 return false;
72 80
73 const int64 bytes_read = ReadResponse(buffer_out, 81 const int64 bytes_read = ReadResponse(buffer_out,
74 static_cast<int>(response->content_length)); 82 static_cast<int>(response->content_length));
75 if (bytes_read != response->content_length) { 83 if (bytes_read != response->content_length) {
76 response->server_status = HttpResponse::IO_ERROR; 84 response->server_status = HttpResponse::IO_ERROR;
77 return false; 85 return false;
78 } 86 }
79 return true; 87 return true;
80 } 88 }
81 89
82 bool ServerConnectionManager::Post::ReadDownloadResponse( 90 bool ServerConnectionManager::Connection::ReadDownloadResponse(
83 HttpResponse* response, 91 HttpResponse* response,
84 string* buffer_out) { 92 string* buffer_out) {
85 const int64 bytes_read = ReadResponse(buffer_out, 93 const int64 bytes_read = ReadResponse(buffer_out,
86 static_cast<int>(response->content_length)); 94 static_cast<int>(response->content_length));
87 95
88 if (bytes_read != response->content_length) { 96 if (bytes_read != response->content_length) {
89 LOG(ERROR) << "Mismatched content lengths, server claimed " << 97 LOG(ERROR) << "Mismatched content lengths, server claimed " <<
90 response->content_length << ", but sent " << bytes_read; 98 response->content_length << ", but sent " << bytes_read;
91 response->server_status = HttpResponse::IO_ERROR; 99 response->server_status = HttpResponse::IO_ERROR;
92 return false; 100 return false;
93 } 101 }
94 return true; 102 return true;
95 } 103 }
96 104
97 namespace { 105 namespace {
98 106
99 string StripTrailingSlash(const string& s) { 107 string StripTrailingSlash(const string& s) {
100 int stripped_end_pos = s.size(); 108 int stripped_end_pos = s.size();
101 if (s.at(stripped_end_pos - 1) == '/') { 109 if (s.at(stripped_end_pos - 1) == '/') {
102 stripped_end_pos = stripped_end_pos - 1; 110 stripped_end_pos = stripped_end_pos - 1;
103 } 111 }
104 112
105 return s.substr(0, stripped_end_pos); 113 return s.substr(0, stripped_end_pos);
106 } 114 }
107 115
108 } // namespace 116 } // namespace
109 117
110 // TODO(chron): Use a GURL instead of string concatenation. 118 // TODO(chron): Use a GURL instead of string concatenation.
111 string ServerConnectionManager::Post::MakeConnectionURL( 119 string ServerConnectionManager::Connection::MakeConnectionURL(
112 const string& sync_server, 120 const string& sync_server,
113 const string& path, 121 const string& path,
114 bool use_ssl) const { 122 bool use_ssl) const {
115 string connection_url = (use_ssl ? "https://" : "http://"); 123 string connection_url = (use_ssl ? "https://" : "http://");
116 connection_url += sync_server; 124 connection_url += sync_server;
117 connection_url = StripTrailingSlash(connection_url); 125 connection_url = StripTrailingSlash(connection_url);
118 connection_url += path; 126 connection_url += path;
119 127
120 return connection_url; 128 return connection_url;
121 } 129 }
122 130
123 int ServerConnectionManager::Post::ReadResponse(string* out_buffer, 131 int ServerConnectionManager::Connection::ReadResponse(string* out_buffer,
124 int length) { 132 int length) {
125 int bytes_read = buffer_.length(); 133 int bytes_read = buffer_.length();
126 CHECK(length <= bytes_read); 134 CHECK(length <= bytes_read);
127 out_buffer->assign(buffer_); 135 out_buffer->assign(buffer_);
128 return bytes_read; 136 return bytes_read;
129 } 137 }
130 138
131 ScopedServerStatusWatcher::ScopedServerStatusWatcher( 139 ScopedServerStatusWatcher::ScopedServerStatusWatcher(
132 ServerConnectionManager* conn_mgr, HttpResponse* response) 140 ServerConnectionManager* conn_mgr, HttpResponse* response)
133 : conn_mgr_(conn_mgr), 141 : conn_mgr_(conn_mgr),
134 response_(response), 142 response_(response),
(...skipping 18 matching lines...) Expand all
153 bool use_ssl, 161 bool use_ssl,
154 const string& user_agent) 162 const string& user_agent)
155 : sync_server_(server), 163 : sync_server_(server),
156 sync_server_port_(port), 164 sync_server_port_(port),
157 user_agent_(user_agent), 165 user_agent_(user_agent),
158 use_ssl_(use_ssl), 166 use_ssl_(use_ssl),
159 proto_sync_path_(kSyncServerSyncPath), 167 proto_sync_path_(kSyncServerSyncPath),
160 get_time_path_(kSyncServerGetTimePath), 168 get_time_path_(kSyncServerGetTimePath),
161 error_count_(0), 169 error_count_(0),
162 server_status_(HttpResponse::NONE), 170 server_status_(HttpResponse::NONE),
163 server_reachable_(false) { 171 server_reachable_(false),
172 terminated_(false),
173 active_connection_(false) {
164 } 174 }
165 175
166 ServerConnectionManager::~ServerConnectionManager() { 176 ServerConnectionManager::~ServerConnectionManager() {
167 } 177 }
168 178
169 void ServerConnectionManager::NotifyStatusChanged() { 179 void ServerConnectionManager::NotifyStatusChanged() {
170 DCHECK(CalledOnValidThread()); 180 DCHECK(thread_checker_.CalledOnValidThread());
171 FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_, 181 FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_,
172 OnServerConnectionEvent( 182 OnServerConnectionEvent(
173 ServerConnectionEvent(server_status_, server_reachable_))); 183 ServerConnectionEvent(server_status_, server_reachable_)));
174 } 184 }
175 185
176 bool ServerConnectionManager::PostBufferWithCachedAuth( 186 bool ServerConnectionManager::PostBufferWithCachedAuth(
177 const PostBufferParams* params, ScopedServerStatusWatcher* watcher) { 187 const PostBufferParams* params, ScopedServerStatusWatcher* watcher) {
178 DCHECK(CalledOnValidThread()); 188 DCHECK(thread_checker_.CalledOnValidThread());
179 string path = 189 string path =
180 MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_)); 190 MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_));
181 return PostBufferToPath(params, path, auth_token(), watcher); 191 return PostBufferToPath(params, path, auth_token(), watcher);
182 } 192 }
183 193
184 bool ServerConnectionManager::PostBufferToPath(const PostBufferParams* params, 194 bool ServerConnectionManager::PostBufferToPath(const PostBufferParams* params,
185 const string& path, const string& auth_token, 195 const string& path, const string& auth_token,
186 ScopedServerStatusWatcher* watcher) { 196 ScopedServerStatusWatcher* watcher) {
187 DCHECK(CalledOnValidThread()); 197 DCHECK(thread_checker_.CalledOnValidThread());
188 DCHECK(watcher != NULL); 198 DCHECK(watcher != NULL);
189 199
190 if (auth_token.empty()) { 200 if (auth_token.empty()) {
191 params->response->server_status = HttpResponse::SYNC_AUTH_ERROR; 201 params->response->server_status = HttpResponse::SYNC_AUTH_ERROR;
192 return false; 202 return false;
193 } 203 }
194 204
195 scoped_ptr<Post> post(MakePost()); 205 // The AutoReset is to temporarily bind active_connection_ to the local
196 post->set_timing_info(params->timing_info); 206 // |post|. It's done this way to protect against a race between a call
197 bool ok = post->Init(path.c_str(), auth_token, params->buffer_in, 207 // to Abort and assignment of active_connection_.
akalin 2011/08/31 07:20:39 I don't get it. What race? This still seems racy
tim (not reviewing) 2011/08/31 14:46:17 We have to make sure that if terminate is called,
198 params->response); 208 scoped_ptr<Connection> post;
209 scoped_ptr<AutoReset<Connection*> > active_connection_resetter;
210 {
akalin 2011/08/31 07:20:39 I suggest making MakeConnection() (or some non-vir
211 base::AutoLock lock(terminate_connection_lock_);
212 if (terminated_) {
213 params->response->server_status = HttpResponse::CONNECTION_UNAVAILABLE;
214 return false;
215 }
216
217 DCHECK(!active_connection_);
218 post.reset(MakeConnection());
219 active_connection_resetter.reset(
220 new AutoReset<Connection*>(&active_connection_, post.get()));
221 post->set_timing_info(params->timing_info);
222 }
223
224 // Note that |post| may be aborted by now, which will just cause Init to fail
225 // with CONNECTION_UNAVAILABLE.
226 bool ok = active_connection_->Init(
akalin 2011/08/31 07:20:39 clearer to do post->Init() here, I think
227 path.c_str(), auth_token, params->buffer_in, params->response);
199 228
200 if (params->response->server_status == HttpResponse::SYNC_AUTH_ERROR) { 229 if (params->response->server_status == HttpResponse::SYNC_AUTH_ERROR) {
201 InvalidateAndClearAuthToken(); 230 InvalidateAndClearAuthToken();
202 } 231 }
203 232
204 if (!ok || RC_REQUEST_OK != params->response->response_code) { 233 if (!ok || RC_REQUEST_OK != params->response->response_code) {
205 IncrementErrorCount(); 234 IncrementErrorCount();
206 return false; 235 return false;
207 } 236 }
208 237
209 if (post->ReadBufferResponse(params->buffer_out, params->response, true)) { 238 if (post->ReadBufferResponse(params->buffer_out, params->response, true)) {
210 params->response->server_status = HttpResponse::SERVER_CONNECTION_OK; 239 params->response->server_status = HttpResponse::SERVER_CONNECTION_OK;
211 server_reachable_ = true; 240 server_reachable_ = true;
212 return true; 241 return true;
213 } 242 }
214 return false; 243 return false;
215 } 244 }
216 245
217 bool ServerConnectionManager::CheckTime(int32* out_time) { 246 bool ServerConnectionManager::CheckTime(int32* out_time) {
218 DCHECK(CalledOnValidThread()); 247 DCHECK(thread_checker_.CalledOnValidThread());
248
219 // Verify that the server really is reachable by checking the time. We need 249 // Verify that the server really is reachable by checking the time. We need
220 // to do this because of wifi interstitials that intercept messages from the 250 // to do this because of wifi interstitials that intercept messages from the
221 // client and return HTTP OK instead of a redirect. 251 // client and return HTTP OK instead of a redirect.
222 HttpResponse response; 252 HttpResponse response;
223 ScopedServerStatusWatcher watcher(this, &response); 253 ScopedServerStatusWatcher watcher(this, &response);
224 string post_body = "command=get_time"; 254 string post_body = "command=get_time";
225 255
226 for (int i = 0 ; i < 3; i++) { 256 for (int i = 0 ; i < 3; i++) {
227 scoped_ptr<Post> post(MakePost()); 257 scoped_ptr<Connection> post;
akalin 2011/08/31 07:20:39 similarly as above, you can just do: scoped_ptr<C
258 scoped_ptr<AutoReset<Connection*> > active_connection_resetter;
259 {
260 base::AutoLock lock(terminate_connection_lock_);
261 if (terminated_)
262 break;
263 DCHECK(!active_connection_);
264 post.reset(MakeConnection());
265 active_connection_resetter.reset(
266 new AutoReset<Connection*>(&active_connection_, post.get()));
267 }
228 268
229 // Note that the server's get_time path doesn't require authentication. 269 // Note that the server's get_time path doesn't require authentication.
230 string get_time_path = 270 string get_time_path =
231 MakeSyncServerPath(kSyncServerGetTimePath, post_body); 271 MakeSyncServerPath(kSyncServerGetTimePath, post_body);
232 VLOG(1) << "Requesting get_time from:" << get_time_path; 272 VLOG(1) << "Requesting get_time from:" << get_time_path;
233 273
234 string blank_post_body; 274 string blank_post_body;
235 bool ok = post->Init(get_time_path.c_str(), blank_post_body, 275 bool ok = post->Init(get_time_path.c_str(), blank_post_body,
236 blank_post_body, &response); 276 blank_post_body, &response);
237 if (!ok) { 277 if (!ok) {
(...skipping 12 matching lines...) Expand all
250 } 290 }
251 *out_time = atoi(time_response.c_str()); 291 *out_time = atoi(time_response.c_str());
252 VLOG(1) << "Server was reachable."; 292 VLOG(1) << "Server was reachable.";
253 return true; 293 return true;
254 } 294 }
255 IncrementErrorCount(); 295 IncrementErrorCount();
256 return false; 296 return false;
257 } 297 }
258 298
259 bool ServerConnectionManager::IsServerReachable() { 299 bool ServerConnectionManager::IsServerReachable() {
260 DCHECK(CalledOnValidThread()); 300 DCHECK(thread_checker_.CalledOnValidThread());
261 int32 time; 301 int32 time;
262 return CheckTime(&time); 302 return CheckTime(&time);
263 } 303 }
264 304
265 bool ServerConnectionManager::IsUserAuthenticated() { 305 bool ServerConnectionManager::IsUserAuthenticated() {
266 DCHECK(CalledOnValidThread()); 306 DCHECK(thread_checker_.CalledOnValidThread());
267 return IsGoodReplyFromServer(server_status_); 307 return IsGoodReplyFromServer(server_status_);
268 } 308 }
269 309
270 bool ServerConnectionManager::CheckServerReachable() { 310 bool ServerConnectionManager::CheckServerReachable() {
271 DCHECK(CalledOnValidThread()); 311 DCHECK(thread_checker_.CalledOnValidThread());
272 const bool server_is_reachable = IsServerReachable(); 312 const bool server_is_reachable = IsServerReachable();
273 if (server_reachable_ != server_is_reachable) { 313 if (server_reachable_ != server_is_reachable) {
274 server_reachable_ = server_is_reachable; 314 server_reachable_ = server_is_reachable;
275 NotifyStatusChanged(); 315 NotifyStatusChanged();
276 } 316 }
277 return server_is_reachable; 317 return server_is_reachable;
278 } 318 }
279 319
280 bool ServerConnectionManager::IncrementErrorCount() { 320 bool ServerConnectionManager::IncrementErrorCount() {
281 DCHECK(CalledOnValidThread()); 321 DCHECK(thread_checker_.CalledOnValidThread());
282 error_count_++; 322 error_count_++;
283 323
284 if (error_count_ > kMaxConnectionErrorsBeforeReset) { 324 if (error_count_ > kMaxConnectionErrorsBeforeReset) {
285 error_count_ = 0; 325 error_count_ = 0;
286 326
287 if (!IsServerReachable()) { 327 if (!IsServerReachable()) {
288 LOG(WARNING) << "Too many connection failures, server is not reachable. " 328 LOG(WARNING) << "Too many connection failures, server is not reachable. "
289 << "Resetting connections."; 329 << "Resetting connections.";
290 } else { 330 } else {
291 LOG(WARNING) << "Multiple connection failures while server is reachable."; 331 LOG(WARNING) << "Multiple connection failures while server is reachable.";
292 } 332 }
293 return false; 333 return false;
294 } 334 }
295 335
296 return true; 336 return true;
297 } 337 }
298 338
299 void ServerConnectionManager::SetServerParameters(const string& server_url, 339 void ServerConnectionManager::SetServerParameters(const string& server_url,
300 int port, 340 int port,
301 bool use_ssl) { 341 bool use_ssl) {
302 DCHECK(CalledOnValidThread()); 342 DCHECK(thread_checker_.CalledOnValidThread());
303 sync_server_ = server_url; 343 sync_server_ = server_url;
304 sync_server_port_ = port; 344 sync_server_port_ = port;
305 use_ssl_ = use_ssl; 345 use_ssl_ = use_ssl;
306 } 346 }
307 347
308 // Returns the current server parameters in server_url and port. 348 // Returns the current server parameters in server_url and port.
309 void ServerConnectionManager::GetServerParameters(string* server_url, 349 void ServerConnectionManager::GetServerParameters(string* server_url,
310 int* port, 350 int* port,
311 bool* use_ssl) const { 351 bool* use_ssl) const {
312 if (server_url != NULL) 352 if (server_url != NULL)
(...skipping 14 matching lines...) Expand all
327 return std::string(); 367 return std::string();
328 // We just want the hostname, so we don't need to switch on use_ssl. 368 // We just want the hostname, so we don't need to switch on use_ssl.
329 server_url = "http://" + server_url; 369 server_url = "http://" + server_url;
330 GURL gurl(server_url); 370 GURL gurl(server_url);
331 DCHECK(gurl.is_valid()) << gurl; 371 DCHECK(gurl.is_valid()) << gurl;
332 return gurl.host(); 372 return gurl.host();
333 } 373 }
334 374
335 void ServerConnectionManager::AddListener( 375 void ServerConnectionManager::AddListener(
336 ServerConnectionEventListener* listener) { 376 ServerConnectionEventListener* listener) {
337 DCHECK(CalledOnValidThread()); 377 DCHECK(thread_checker_.CalledOnValidThread());
338 listeners_.AddObserver(listener); 378 listeners_.AddObserver(listener);
339 } 379 }
340 380
341 void ServerConnectionManager::RemoveListener( 381 void ServerConnectionManager::RemoveListener(
342 ServerConnectionEventListener* listener) { 382 ServerConnectionEventListener* listener) {
343 DCHECK(CalledOnValidThread()); 383 DCHECK(thread_checker_.CalledOnValidThread());
344 listeners_.RemoveObserver(listener); 384 listeners_.RemoveObserver(listener);
345 } 385 }
346 386
347 ServerConnectionManager::Post* ServerConnectionManager::MakePost() { 387 ServerConnectionManager::Connection* ServerConnectionManager::MakeConnection()
388 {
348 return NULL; // For testing. 389 return NULL; // For testing.
349 } 390 }
350 391
392 void ServerConnectionManager::TerminateAllIO() {
393 base::AutoLock lock(terminate_connection_lock_);
394 terminated_ = true;
395 if (active_connection_)
396 active_connection_->Abort();
397
398 // Sever our ties to this connection object. Note that it still may exist,
399 // since we don't own it, but it has been neutered.
400 active_connection_ = NULL;
401 }
402
351 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm, 403 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
352 syncable::DirectoryManager* manager, 404 syncable::DirectoryManager* manager,
353 const std::string& share) { 405 const std::string& share) {
354 syncable::ScopedDirLookup dir(manager, share); 406 syncable::ScopedDirLookup dir(manager, share);
355 if (!dir.good()) { 407 if (!dir.good()) {
356 VLOG(1) << "Dir lookup failed"; 408 VLOG(1) << "Dir lookup failed";
357 return false; 409 return false;
358 } 410 }
359 string birthday = dir->store_birthday(); 411 string birthday = dir->store_birthday();
360 if (!birthday.empty()) 412 if (!birthday.empty())
361 csm->set_store_birthday(birthday); 413 csm->set_store_birthday(birthday);
362 csm->set_share(share); 414 csm->set_share(share);
363 return true; 415 return true;
364 } 416 }
365 417
366 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) { 418 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) {
367 s << " Response Code (bogus on error): " << hr.response_code; 419 s << " Response Code (bogus on error): " << hr.response_code;
368 s << " Content-Length (bogus on error): " << hr.content_length; 420 s << " Content-Length (bogus on error): " << hr.content_length;
369 s << " Server Status: " << hr.server_status; 421 s << " Server Status: " << hr.server_status;
370 return s; 422 return s;
371 } 423 }
372 424
373 } // namespace browser_sync 425 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698