ClientSocketPoolBaseHelper can try to read an invalid iterator. Fix that.
If we hit the backup socket timer and there is no pending request, then the
code still tries to create a backup socket using pending_requests.begin().
We change the code to cancel the backup socket timer when the pending_requests
hit zero. We also check before reading pending_requests.begin().
BUG=53860
TEST=ClientsocketPoolBaseTest.CancelBackupSocketWhenThereAreNoRequests
Review URL: http://codereview.chromium.org/3247007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57993 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 49fa09e..379c041 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -336,6 +336,10 @@
RemoveConnectJob(*group->jobs().begin(), group);
CheckForStalledSocketGroups();
}
+
+ // If there are no more requests, we kill the backup timer.
+ if (group->pending_requests().empty())
+ group->CleanupBackupJob();
break;
}
}
@@ -890,6 +894,11 @@
return;
}
+ if (pending_requests_.empty()) {
+ LOG(DFATAL) << "No pending request for backup job.";
+ return;
+ }
+
ConnectJob* backup_job = pool->connect_job_factory_->NewConnectJob(
group_name, **pending_requests_.begin(), pool);
backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED, NULL);
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index ff67e3b..71074a9 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -1940,8 +1940,8 @@
CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
pool_->EnableConnectBackupJobs();
- // Create the first socket and set to ERR_IO_PENDING. This creates a
- // backup job.
+ // Create the first socket and set to ERR_IO_PENDING. This starts the backup
+ // timer.
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
ClientSocketHandle handle;
TestCompletionCallback callback;
@@ -1969,6 +1969,30 @@
EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
}
+TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketWhenThereAreNoRequests) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
+ pool_->EnableConnectBackupJobs();
+
+ // Create the first socket and set to ERR_IO_PENDING. This starts the backup
+ // timer.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("bar", params_, kDefaultPriority,
+ &callback, pool_, BoundNetLog()));
+ ASSERT_TRUE(pool_->HasGroup("bar"));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("bar"));
+
+ // Cancel the socket request. This should cancel the backup timer. Wait for
+ // the backup time to see if it indeed got canceled.
+ handle.Reset();
+ // Wait for the backup timer to fire (add some slop to ensure it fires)
+ PlatformThread::Sleep(ClientSocketPool::kMaxConnectRetryIntervalMs / 2 * 3);
+ MessageLoop::current()->RunAllPending();
+ ASSERT_TRUE(pool_->HasGroup("bar"));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("bar"));
+}
+
// Test delayed socket binding for the case where we have two connects,
// and while one is waiting on a connect, the other frees up.
// The socket waiting on a connect should switch immediately to the freed