summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-25 17:49:51 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-25 17:49:51 +0000
commit2abfe90a9461dfa9a8b1252a94e464e46864ca35 (patch)
treed7bab53d05e1ae8cdd4dfaad076a72f14424ed34 /net/socket
parent19fbd619f3ce5562ed34ce0fea80250a2a296b19 (diff)
downloadchromium_src-2abfe90a9461dfa9a8b1252a94e464e46864ca35.zip
chromium_src-2abfe90a9461dfa9a8b1252a94e464e46864ca35.tar.gz
chromium_src-2abfe90a9461dfa9a8b1252a94e464e46864ca35.tar.bz2
Fix a crash in ClientSocketPoolBaseHelper where we double erase a Group from the GroupMap.
BUG=49254 Review URL: http://codereview.chromium.org/3104026 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57346 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r--net/socket/client_socket_pool_base.cc12
-rw-r--r--net/socket/client_socket_pool_base.h6
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc40
3 files changed, 54 insertions, 4 deletions
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 2e8534e..3c2a9c7 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -401,6 +401,10 @@ void ClientSocketPoolBaseHelper::CancelRequest(
}
}
+bool ClientSocketPoolBaseHelper::HasGroup(const std::string& group_name) const {
+ return ContainsKey(group_map_, group_name);
+}
+
void ClientSocketPoolBaseHelper::CloseIdleSockets() {
CleanupIdleSockets(true);
}
@@ -691,11 +695,11 @@ void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
const std::string& group_name, Group* group) {
- if (!group->pending_requests.empty())
- ProcessPendingRequest(group_name, group);
-
+ DCHECK(ContainsKey(group_map_, group_name));
if (group->IsEmpty())
group_map_.erase(group_name);
+ else if (!group->pending_requests.empty())
+ ProcessPendingRequest(group_name, group);
}
void ClientSocketPoolBaseHelper::ProcessPendingRequest(
@@ -705,6 +709,8 @@ void ClientSocketPoolBaseHelper::ProcessPendingRequest(
if (rv != ERR_IO_PENDING) {
scoped_ptr<const Request> request(RemoveRequestFromQueue(
group->pending_requests.begin(), &group->pending_requests));
+ if (group->IsEmpty())
+ group_map_.erase(group_name);
scoped_refptr<NetLog::EventParameters> params;
if (rv != OK)
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index ee727f0..b1ea6e3 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -231,6 +231,8 @@ class ClientSocketPoolBaseHelper
return group_map_.find(group_name)->second.jobs.size();
}
+ bool HasGroup(const std::string& group_name) const;
+
// Closes all idle sockets if |force| is true. Else, only closes idle
// sockets that timed out or can't be reused. Made public for testing.
void CleanupIdleSockets(bool force);
@@ -584,6 +586,10 @@ class ClientSocketPoolBase {
return helper_->NumConnectJobsInGroup(group_name);
}
+ bool HasGroup(const std::string& group_name) const {
+ return helper_->HasGroup(group_name);
+ }
+
void CleanupIdleSockets(bool force) {
return helper_->CleanupIdleSockets(force);
}
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index d8ea1d9..89db61d 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -420,6 +420,10 @@ class TestClientSocketPool : public ClientSocketPool {
return base_.NumConnectJobsInGroup(group_name);
}
+ bool HasGroup(const std::string& group_name) const {
+ return base_.HasGroup(group_name);
+ }
+
void CleanupTimedOutIdleSockets() { base_.CleanupIdleSockets(false); }
void EnableConnectBackupJobs() { base_.EnableConnectBackupJobs(); }
@@ -2057,7 +2061,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) {
// Test out the case where we have one socket connected, one
// connecting, when the first socket finishes and goes idle.
-// Although the second connection is pending, th second request
+// Although the second connection is pending, the second request
// should complete, by taking the first socket's idle socket.
TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
@@ -2105,6 +2109,40 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
MessageLoop::current()->RunAllPending();
}
+// Cover the case where on an available socket slot, we have one pending
+// request that completes synchronously, thereby making the Group empty.
+TEST_F(ClientSocketPoolBaseTest, SynchronouslyProcessOnePendingRequest) {
+ const int kUnlimitedSockets = 100;
+ const int kOneSocketPerGroup = 1;
+ CreatePool(kUnlimitedSockets, kOneSocketPerGroup);
+
+ // Make the first request asynchronous fail.
+ // This will free up a socket slot later.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a", params_, kDefaultPriority,
+ &callback1, pool_, BoundNetLog()));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+
+ // Make the second request synchronously fail. This should make the Group
+ // empty.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ // It'll be ERR_IO_PENDING now, but the TestConnectJob will synchronously fail
+ // when created.
+ EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a", params_, kDefaultPriority,
+ &callback2, pool_, BoundNetLog()));
+
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+
+ EXPECT_EQ(ERR_CONNECTION_FAILED, callback1.WaitForResult());
+ EXPECT_EQ(ERR_CONNECTION_FAILED, callback2.WaitForResult());
+ EXPECT_FALSE(pool_->HasGroup("a"));
+}
+
} // namespace
} // namespace net