Fix a bug in backup socket cleanup where when we call RemoveConnectJob,
we didn't necessarily cleanup the pending backup socket task.

In addition to this, make the OnBackupSocketTimerFired more robust -
in the case that this ever should happen, it will simply fallout
rather than triggering a CRASH (and burn).

Test case included.

BUG=47375
TEST=ClientSocketPoolBaseTest.BackupSocketCancelAtMaxSockets

Review URL: http://codereview.chromium.org/2942006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52049 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 7b84d94..1dcf897 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -1784,6 +1784,45 @@
   EXPECT_EQ(ClientSocketHandle::UNUSED, handle.reuse_type());
 }
 
+// Cancel a pending socket request while we're at max sockets,
+// and verify that the backup socket firing doesn't cause a crash.
+TEST_F(ClientSocketPoolBaseTest, BackupSocketCancelAtMaxSockets) {
+  // Max 4 sockets globally, max 4 sockets per group.
+  CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
+  pool_->EnableBackupJobs();
+
+  // Create the first socket and set to ERR_IO_PENDING.  This creates a
+  // backup job.
+  connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
+  ClientSocketHandle handle;
+  TestCompletionCallback callback;
+  EXPECT_EQ(
+      ERR_IO_PENDING,
+      InitHandle(
+          &handle, "bar", kDefaultPriority, &callback, pool_, BoundNetLog()));
+
+  // Start (MaxSockets - 1) connected sockets to reach max sockets.
+  connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
+  ClientSocketHandle handles[kDefaultMaxSockets];
+  for (int i = 1; i < kDefaultMaxSockets; ++i) {
+    TestCompletionCallback callback;
+    EXPECT_EQ(OK,
+              InitHandle(&handles[i], "bar", kDefaultPriority,
+                         &callback, pool_, BoundNetLog()));
+  }
+
+  MessageLoop::current()->RunAllPending();
+
+  // Cancel the pending request.
+  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();
+  EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
+}
+
 }  // namespace
 
 }  // namespace net