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

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

Issue 7841013: sync: take 2 at aborting active HTTP requests. (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>
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 ENUM_CASE(SYNC_AUTH_ERROR); 51 ENUM_CASE(SYNC_AUTH_ERROR);
52 ENUM_CASE(SERVER_CONNECTION_OK); 52 ENUM_CASE(SERVER_CONNECTION_OK);
53 ENUM_CASE(RETRY); 53 ENUM_CASE(RETRY);
54 } 54 }
55 NOTREACHED(); 55 NOTREACHED();
56 return ""; 56 return "";
57 } 57 }
58 58
59 #undef ENUM_CASE 59 #undef ENUM_CASE
60 60
61 bool ServerConnectionManager::Post::ReadBufferResponse( 61 ServerConnectionManager::Connection::Connection(
62 ServerConnectionManager* scm) : scm_(scm) {
63 }
64
65 ServerConnectionManager::Connection::~Connection() {
66 }
67
68 bool ServerConnectionManager::Connection::ReadBufferResponse(
62 string* buffer_out, 69 string* buffer_out,
63 HttpResponse* response, 70 HttpResponse* response,
64 bool require_response) { 71 bool require_response) {
65 if (RC_REQUEST_OK != response->response_code) { 72 if (RC_REQUEST_OK != response->response_code) {
66 response->server_status = HttpResponse::SYNC_SERVER_ERROR; 73 response->server_status = HttpResponse::SYNC_SERVER_ERROR;
67 return false; 74 return false;
68 } 75 }
69 76
70 if (require_response && (1 > response->content_length)) 77 if (require_response && (1 > response->content_length))
71 return false; 78 return false;
72 79
73 const int64 bytes_read = ReadResponse(buffer_out, 80 const int64 bytes_read = ReadResponse(buffer_out,
74 static_cast<int>(response->content_length)); 81 static_cast<int>(response->content_length));
75 if (bytes_read != response->content_length) { 82 if (bytes_read != response->content_length) {
76 response->server_status = HttpResponse::IO_ERROR; 83 response->server_status = HttpResponse::IO_ERROR;
77 return false; 84 return false;
78 } 85 }
79 return true; 86 return true;
80 } 87 }
81 88
82 bool ServerConnectionManager::Post::ReadDownloadResponse( 89 bool ServerConnectionManager::Connection::ReadDownloadResponse(
83 HttpResponse* response, 90 HttpResponse* response,
84 string* buffer_out) { 91 string* buffer_out) {
85 const int64 bytes_read = ReadResponse(buffer_out, 92 const int64 bytes_read = ReadResponse(buffer_out,
86 static_cast<int>(response->content_length)); 93 static_cast<int>(response->content_length));
87 94
88 if (bytes_read != response->content_length) { 95 if (bytes_read != response->content_length) {
89 LOG(ERROR) << "Mismatched content lengths, server claimed " << 96 LOG(ERROR) << "Mismatched content lengths, server claimed " <<
90 response->content_length << ", but sent " << bytes_read; 97 response->content_length << ", but sent " << bytes_read;
91 response->server_status = HttpResponse::IO_ERROR; 98 response->server_status = HttpResponse::IO_ERROR;
92 return false; 99 return false;
93 } 100 }
94 return true; 101 return true;
95 } 102 }
96 103
104 ServerConnectionManager::ScopedConnectionHelper::ScopedConnectionHelper(
105 ServerConnectionManager* manager, Connection* connection)
106 : manager_(manager), connection_(connection) {}
107
108 ServerConnectionManager::ScopedConnectionHelper::~ScopedConnectionHelper() {
109 if (connection_.get())
110 manager_->OnConnectionDestroyed(connection_.get());
111 connection_.reset();
112 }
113
114 ServerConnectionManager::Connection*
115 ServerConnectionManager::ScopedConnectionHelper::get() {
116 return connection_.get();
117 }
118
97 namespace { 119 namespace {
98 120
99 string StripTrailingSlash(const string& s) { 121 string StripTrailingSlash(const string& s) {
100 int stripped_end_pos = s.size(); 122 int stripped_end_pos = s.size();
101 if (s.at(stripped_end_pos - 1) == '/') { 123 if (s.at(stripped_end_pos - 1) == '/') {
102 stripped_end_pos = stripped_end_pos - 1; 124 stripped_end_pos = stripped_end_pos - 1;
103 } 125 }
104 126
105 return s.substr(0, stripped_end_pos); 127 return s.substr(0, stripped_end_pos);
106 } 128 }
107 129
108 } // namespace 130 } // namespace
109 131
110 // TODO(chron): Use a GURL instead of string concatenation. 132 // TODO(chron): Use a GURL instead of string concatenation.
111 string ServerConnectionManager::Post::MakeConnectionURL( 133 string ServerConnectionManager::Connection::MakeConnectionURL(
112 const string& sync_server, 134 const string& sync_server,
113 const string& path, 135 const string& path,
114 bool use_ssl) const { 136 bool use_ssl) const {
115 string connection_url = (use_ssl ? "https://" : "http://"); 137 string connection_url = (use_ssl ? "https://" : "http://");
116 connection_url += sync_server; 138 connection_url += sync_server;
117 connection_url = StripTrailingSlash(connection_url); 139 connection_url = StripTrailingSlash(connection_url);
118 connection_url += path; 140 connection_url += path;
119 141
120 return connection_url; 142 return connection_url;
121 } 143 }
122 144
123 int ServerConnectionManager::Post::ReadResponse(string* out_buffer, 145 int ServerConnectionManager::Connection::ReadResponse(string* out_buffer,
124 int length) { 146 int length) {
125 int bytes_read = buffer_.length(); 147 int bytes_read = buffer_.length();
126 CHECK(length <= bytes_read); 148 CHECK(length <= bytes_read);
127 out_buffer->assign(buffer_); 149 out_buffer->assign(buffer_);
128 return bytes_read; 150 return bytes_read;
129 } 151 }
130 152
131 ScopedServerStatusWatcher::ScopedServerStatusWatcher( 153 ScopedServerStatusWatcher::ScopedServerStatusWatcher(
132 ServerConnectionManager* conn_mgr, HttpResponse* response) 154 ServerConnectionManager* conn_mgr, HttpResponse* response)
133 : conn_mgr_(conn_mgr), 155 : conn_mgr_(conn_mgr),
134 response_(response), 156 response_(response),
(...skipping 18 matching lines...) Expand all
153 bool use_ssl, 175 bool use_ssl,
154 const string& user_agent) 176 const string& user_agent)
155 : sync_server_(server), 177 : sync_server_(server),
156 sync_server_port_(port), 178 sync_server_port_(port),
157 user_agent_(user_agent), 179 user_agent_(user_agent),
158 use_ssl_(use_ssl), 180 use_ssl_(use_ssl),
159 proto_sync_path_(kSyncServerSyncPath), 181 proto_sync_path_(kSyncServerSyncPath),
160 get_time_path_(kSyncServerGetTimePath), 182 get_time_path_(kSyncServerGetTimePath),
161 error_count_(0), 183 error_count_(0),
162 server_status_(HttpResponse::NONE), 184 server_status_(HttpResponse::NONE),
163 server_reachable_(false) { 185 server_reachable_(false),
186 terminated_(false),
187 active_connection_(NULL) {
164 } 188 }
165 189
166 ServerConnectionManager::~ServerConnectionManager() { 190 ServerConnectionManager::~ServerConnectionManager() {
167 } 191 }
168 192
193 ServerConnectionManager::Connection*
194 ServerConnectionManager::MakeActiveConnection() {
195 base::AutoLock lock(terminate_connection_lock_);
196 DCHECK(!active_connection_);
197 if (terminated_)
198 return NULL;
199
200 active_connection_ = MakeConnection();
jar (doing other things) 2011/09/07 06:47:41 It is usually best practice to use locks to only p
tim (not reviewing) 2011/09/07 14:46:56 Thanks for your review Jim. I get the concerns wi
201 return active_connection_;
202 }
203
204 void ServerConnectionManager::OnConnectionDestroyed(Connection* connection) {
205 DCHECK(connection);
206 base::AutoLock lock(terminate_connection_lock_);
207 // |active_connection_| can be NULL already if it was aborted. Also,
208 // it can legitimately be a different Connection object if a new Connection
209 // was created after a previous one was Aborted and destroyed.
210 if (active_connection_ != connection)
211 return;
212
213 active_connection_ = NULL;
214 }
215
169 void ServerConnectionManager::NotifyStatusChanged() { 216 void ServerConnectionManager::NotifyStatusChanged() {
170 DCHECK(CalledOnValidThread()); 217 DCHECK(thread_checker_.CalledOnValidThread());
171 FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_, 218 FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_,
172 OnServerConnectionEvent( 219 OnServerConnectionEvent(
173 ServerConnectionEvent(server_status_, server_reachable_))); 220 ServerConnectionEvent(server_status_, server_reachable_)));
174 } 221 }
175 222
176 bool ServerConnectionManager::PostBufferWithCachedAuth( 223 bool ServerConnectionManager::PostBufferWithCachedAuth(
177 PostBufferParams* params, ScopedServerStatusWatcher* watcher) { 224 PostBufferParams* params, ScopedServerStatusWatcher* watcher) {
178 DCHECK(CalledOnValidThread()); 225 DCHECK(thread_checker_.CalledOnValidThread());
179 string path = 226 string path =
180 MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_)); 227 MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_));
181 return PostBufferToPath(params, path, auth_token(), watcher); 228 return PostBufferToPath(params, path, auth_token(), watcher);
182 } 229 }
183 230
184 bool ServerConnectionManager::PostBufferToPath(PostBufferParams* params, 231 bool ServerConnectionManager::PostBufferToPath(PostBufferParams* params,
185 const string& path, const string& auth_token, 232 const string& path, const string& auth_token,
186 ScopedServerStatusWatcher* watcher) { 233 ScopedServerStatusWatcher* watcher) {
187 DCHECK(CalledOnValidThread()); 234 DCHECK(thread_checker_.CalledOnValidThread());
188 DCHECK(watcher != NULL); 235 DCHECK(watcher != NULL);
189 236
190 if (auth_token.empty()) { 237 if (auth_token.empty()) {
191 params->response.server_status = HttpResponse::SYNC_AUTH_ERROR; 238 params->response.server_status = HttpResponse::SYNC_AUTH_ERROR;
192 return false; 239 return false;
193 } 240 }
194 241
195 scoped_ptr<Post> post(MakePost()); 242 // When our connection object falls out of scope, it clears itself from
196 bool ok = post->Init(path.c_str(), auth_token, params->buffer_in, 243 // active_connection_.
197 &params->response); 244 ScopedConnectionHelper post(this, MakeActiveConnection());
245 if (!post.get()) {
246 params->response.server_status = HttpResponse::CONNECTION_UNAVAILABLE;
247 return false;
248 }
249
250 // Note that |post| may be aborted by now, which will just cause Init to fail
251 // with CONNECTION_UNAVAILABLE.
252 bool ok = post.get()->Init(
253 path.c_str(), auth_token, params->buffer_in, &params->response);
198 254
199 if (params->response.server_status == HttpResponse::SYNC_AUTH_ERROR) { 255 if (params->response.server_status == HttpResponse::SYNC_AUTH_ERROR) {
200 InvalidateAndClearAuthToken(); 256 InvalidateAndClearAuthToken();
201 } 257 }
202 258
203 if (!ok || RC_REQUEST_OK != params->response.response_code) { 259 if (!ok || RC_REQUEST_OK != params->response.response_code) {
204 IncrementErrorCount(); 260 IncrementErrorCount();
205 return false; 261 return false;
206 } 262 }
207 263
208 if (post->ReadBufferResponse(&params->buffer_out, &params->response, true)) { 264 if (post.get()->ReadBufferResponse(
265 &params->buffer_out, &params->response, true)) {
209 params->response.server_status = HttpResponse::SERVER_CONNECTION_OK; 266 params->response.server_status = HttpResponse::SERVER_CONNECTION_OK;
210 server_reachable_ = true; 267 server_reachable_ = true;
211 return true; 268 return true;
212 } 269 }
213 return false; 270 return false;
214 } 271 }
215 272
216 bool ServerConnectionManager::CheckTime(int32* out_time) { 273 bool ServerConnectionManager::CheckTime(int32* out_time) {
217 DCHECK(CalledOnValidThread()); 274 DCHECK(thread_checker_.CalledOnValidThread());
275
218 // Verify that the server really is reachable by checking the time. We need 276 // Verify that the server really is reachable by checking the time. We need
219 // to do this because of wifi interstitials that intercept messages from the 277 // to do this because of wifi interstitials that intercept messages from the
220 // client and return HTTP OK instead of a redirect. 278 // client and return HTTP OK instead of a redirect.
221 HttpResponse response; 279 HttpResponse response;
222 ScopedServerStatusWatcher watcher(this, &response); 280 ScopedServerStatusWatcher watcher(this, &response);
223 string post_body = "command=get_time"; 281 string post_body = "command=get_time";
224 282
225 for (int i = 0 ; i < 3; i++) { 283 for (int i = 0 ; i < 3; i++) {
226 scoped_ptr<Post> post(MakePost()); 284 ScopedConnectionHelper post(this, MakeActiveConnection());
285 if (!post.get())
286 break;
227 287
228 // Note that the server's get_time path doesn't require authentication. 288 // Note that the server's get_time path doesn't require authentication.
229 string get_time_path = 289 string get_time_path =
230 MakeSyncServerPath(kSyncServerGetTimePath, post_body); 290 MakeSyncServerPath(kSyncServerGetTimePath, post_body);
231 VLOG(1) << "Requesting get_time from:" << get_time_path; 291 VLOG(1) << "Requesting get_time from:" << get_time_path;
232 292
233 string blank_post_body; 293 string blank_post_body;
234 bool ok = post->Init(get_time_path.c_str(), blank_post_body, 294 bool ok = post.get()->Init(get_time_path.c_str(), blank_post_body,
235 blank_post_body, &response); 295 blank_post_body, &response);
236 if (!ok) { 296 if (!ok) {
237 VLOG(1) << "Unable to check the time"; 297 VLOG(1) << "Unable to check the time";
238 continue; 298 continue;
239 } 299 }
240 string time_response; 300 string time_response;
241 time_response.resize( 301 time_response.resize(
242 static_cast<string::size_type>(response.content_length)); 302 static_cast<string::size_type>(response.content_length));
243 ok = post->ReadDownloadResponse(&response, &time_response); 303 ok = post.get()->ReadDownloadResponse(&response, &time_response);
244 if (!ok || string::npos != 304 if (!ok || string::npos !=
245 time_response.find_first_not_of("0123456789")) { 305 time_response.find_first_not_of("0123456789")) {
246 LOG(ERROR) << "unable to read a non-numeric response from get_time:" 306 LOG(ERROR) << "unable to read a non-numeric response from get_time:"
247 << time_response; 307 << time_response;
248 continue; 308 continue;
249 } 309 }
250 *out_time = atoi(time_response.c_str()); 310 *out_time = atoi(time_response.c_str());
251 VLOG(1) << "Server was reachable."; 311 VLOG(1) << "Server was reachable.";
252 return true; 312 return true;
253 } 313 }
254 IncrementErrorCount(); 314 IncrementErrorCount();
255 return false; 315 return false;
256 } 316 }
257 317
258 bool ServerConnectionManager::IsServerReachable() { 318 bool ServerConnectionManager::IsServerReachable() {
259 DCHECK(CalledOnValidThread()); 319 DCHECK(thread_checker_.CalledOnValidThread());
260 int32 time; 320 int32 time;
261 return CheckTime(&time); 321 return CheckTime(&time);
262 } 322 }
263 323
264 bool ServerConnectionManager::IsUserAuthenticated() { 324 bool ServerConnectionManager::IsUserAuthenticated() {
265 DCHECK(CalledOnValidThread()); 325 DCHECK(thread_checker_.CalledOnValidThread());
266 return IsGoodReplyFromServer(server_status_); 326 return IsGoodReplyFromServer(server_status_);
267 } 327 }
268 328
269 bool ServerConnectionManager::CheckServerReachable() { 329 bool ServerConnectionManager::CheckServerReachable() {
270 DCHECK(CalledOnValidThread()); 330 DCHECK(thread_checker_.CalledOnValidThread());
271 const bool server_is_reachable = IsServerReachable(); 331 const bool server_is_reachable = IsServerReachable();
272 if (server_reachable_ != server_is_reachable) { 332 if (server_reachable_ != server_is_reachable) {
273 server_reachable_ = server_is_reachable; 333 server_reachable_ = server_is_reachable;
274 NotifyStatusChanged(); 334 NotifyStatusChanged();
275 } 335 }
276 return server_is_reachable; 336 return server_is_reachable;
277 } 337 }
278 338
279 bool ServerConnectionManager::IncrementErrorCount() { 339 bool ServerConnectionManager::IncrementErrorCount() {
280 DCHECK(CalledOnValidThread()); 340 DCHECK(thread_checker_.CalledOnValidThread());
281 error_count_++; 341 error_count_++;
282 342
283 if (error_count_ > kMaxConnectionErrorsBeforeReset) { 343 if (error_count_ > kMaxConnectionErrorsBeforeReset) {
284 error_count_ = 0; 344 error_count_ = 0;
285 345
286 if (!IsServerReachable()) { 346 if (!IsServerReachable()) {
287 LOG(WARNING) << "Too many connection failures, server is not reachable. " 347 LOG(WARNING) << "Too many connection failures, server is not reachable. "
288 << "Resetting connections."; 348 << "Resetting connections.";
289 } else { 349 } else {
290 LOG(WARNING) << "Multiple connection failures while server is reachable."; 350 LOG(WARNING) << "Multiple connection failures while server is reachable.";
291 } 351 }
292 return false; 352 return false;
293 } 353 }
294 354
295 return true; 355 return true;
296 } 356 }
297 357
298 void ServerConnectionManager::SetServerParameters(const string& server_url, 358 void ServerConnectionManager::SetServerParameters(const string& server_url,
299 int port, 359 int port,
300 bool use_ssl) { 360 bool use_ssl) {
301 DCHECK(CalledOnValidThread()); 361 DCHECK(thread_checker_.CalledOnValidThread());
302 sync_server_ = server_url; 362 sync_server_ = server_url;
303 sync_server_port_ = port; 363 sync_server_port_ = port;
304 use_ssl_ = use_ssl; 364 use_ssl_ = use_ssl;
305 } 365 }
306 366
307 // Returns the current server parameters in server_url and port. 367 // Returns the current server parameters in server_url and port.
308 void ServerConnectionManager::GetServerParameters(string* server_url, 368 void ServerConnectionManager::GetServerParameters(string* server_url,
309 int* port, 369 int* port,
310 bool* use_ssl) const { 370 bool* use_ssl) const {
311 if (server_url != NULL) 371 if (server_url != NULL)
(...skipping 14 matching lines...) Expand all
326 return std::string(); 386 return std::string();
327 // We just want the hostname, so we don't need to switch on use_ssl. 387 // We just want the hostname, so we don't need to switch on use_ssl.
328 server_url = "http://" + server_url; 388 server_url = "http://" + server_url;
329 GURL gurl(server_url); 389 GURL gurl(server_url);
330 DCHECK(gurl.is_valid()) << gurl; 390 DCHECK(gurl.is_valid()) << gurl;
331 return gurl.host(); 391 return gurl.host();
332 } 392 }
333 393
334 void ServerConnectionManager::AddListener( 394 void ServerConnectionManager::AddListener(
335 ServerConnectionEventListener* listener) { 395 ServerConnectionEventListener* listener) {
336 DCHECK(CalledOnValidThread()); 396 DCHECK(thread_checker_.CalledOnValidThread());
337 listeners_.AddObserver(listener); 397 listeners_.AddObserver(listener);
338 } 398 }
339 399
340 void ServerConnectionManager::RemoveListener( 400 void ServerConnectionManager::RemoveListener(
341 ServerConnectionEventListener* listener) { 401 ServerConnectionEventListener* listener) {
342 DCHECK(CalledOnValidThread()); 402 DCHECK(thread_checker_.CalledOnValidThread());
343 listeners_.RemoveObserver(listener); 403 listeners_.RemoveObserver(listener);
344 } 404 }
345 405
346 ServerConnectionManager::Post* ServerConnectionManager::MakePost() { 406 ServerConnectionManager::Connection* ServerConnectionManager::MakeConnection()
407 {
347 return NULL; // For testing. 408 return NULL; // For testing.
348 } 409 }
349 410
411 void ServerConnectionManager::TerminateAllIO() {
412 base::AutoLock lock(terminate_connection_lock_);
413 terminated_ = true;
414 if (active_connection_)
415 active_connection_->Abort();
416
417 // Sever our ties to this connection object. Note that it still may exist,
418 // since we don't own it, but it has been neutered.
419 active_connection_ = NULL;
420 }
421
350 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm, 422 bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
351 syncable::DirectoryManager* manager, 423 syncable::DirectoryManager* manager,
352 const std::string& share) { 424 const std::string& share) {
353 syncable::ScopedDirLookup dir(manager, share); 425 syncable::ScopedDirLookup dir(manager, share);
354 if (!dir.good()) { 426 if (!dir.good()) {
355 VLOG(1) << "Dir lookup failed"; 427 VLOG(1) << "Dir lookup failed";
356 return false; 428 return false;
357 } 429 }
358 string birthday = dir->store_birthday(); 430 string birthday = dir->store_birthday();
359 if (!birthday.empty()) 431 if (!birthday.empty())
360 csm->set_store_birthday(birthday); 432 csm->set_store_birthday(birthday);
361 csm->set_share(share); 433 csm->set_share(share);
362 return true; 434 return true;
363 } 435 }
364 436
365 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) { 437 std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) {
366 s << " Response Code (bogus on error): " << hr.response_code; 438 s << " Response Code (bogus on error): " << hr.response_code;
367 s << " Content-Length (bogus on error): " << hr.content_length; 439 s << " Content-Length (bogus on error): " << hr.content_length;
368 s << " Server Status: " << hr.server_status; 440 s << " Server Status: " << hr.server_status;
369 return s; 441 return s;
370 } 442 }
371 443
372 } // namespace browser_sync 444 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/net/server_connection_manager.h ('k') | chrome/browser/sync/internal_api/sync_manager.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698