Skip to content

Commit 0d86380

Browse files
authored
HttpListener fix: Operations that change non-concurrent collections must have exclusive access (#107804)
1 parent 6906730 commit 0d86380

File tree

1 file changed

+32
-6
lines changed

1 file changed

+32
-6
lines changed

src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpListener.Windows.cs

+32-6
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ public bool UnsafeConnectionNtlmAuthentication
7070
{
7171
return;
7272
}
73-
lock ((DisconnectResults as ICollection).SyncRoot)
73+
74+
var disconnectResults = DisconnectResults;
75+
lock ((disconnectResults as ICollection).SyncRoot)
7476
{
7577
if (_unsafeConnectionNtlmAuthentication == value)
7678
{
@@ -79,7 +81,7 @@ public bool UnsafeConnectionNtlmAuthentication
7981
_unsafeConnectionNtlmAuthentication = value;
8082
if (!value)
8183
{
82-
foreach (DisconnectAsyncResult result in DisconnectResults.Values)
84+
foreach (DisconnectAsyncResult result in disconnectResults.Values)
8385
{
8486
result.AuthenticatedConnection = null;
8587
}
@@ -694,7 +696,13 @@ public HttpListenerContext EndGetContext(IAsyncResult asyncResult)
694696
// assurance that we do this only for NTLM/Negotiate is not here, but in the
695697
// code that caches WindowsIdentity instances in the Dictionary.
696698
DisconnectAsyncResult? disconnectResult;
697-
DisconnectResults.TryGetValue(connectionId, out disconnectResult);
699+
700+
var disconnectResults = DisconnectResults;
701+
lock ((disconnectResults as ICollection).SyncRoot)
702+
{
703+
disconnectResults.TryGetValue(connectionId, out disconnectResult);
704+
}
705+
698706
if (UnsafeConnectionNtlmAuthentication)
699707
{
700708
if (authorizationHeader == null)
@@ -1327,7 +1335,12 @@ private static void RegisterForDisconnectNotification(HttpListenerSession sessio
13271335
// Need to make sure it's going to get returned before adding it to the hash. That way it'll be handled
13281336
// correctly in HandleAuthentication's finally.
13291337
disconnectResult = result;
1330-
session.Listener.DisconnectResults[connectionId] = disconnectResult;
1338+
1339+
var disconnectResults = session.Listener.DisconnectResults;
1340+
lock ((disconnectResults as ICollection).SyncRoot)
1341+
{
1342+
disconnectResults[connectionId] = disconnectResult;
1343+
}
13311344
}
13321345

13331346
if (statusCode == Interop.HttpApi.ERROR_SUCCESS && HttpListener.SkipIOCPCallbackOnSuccess)
@@ -1646,8 +1659,21 @@ private void HandleDisconnect()
16461659
{
16471660
HttpListener listener = _listenerSession.Listener;
16481661

1649-
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"DisconnectResults {listener.DisconnectResults} removing for _connectionId: {_connectionId}");
1650-
listener.DisconnectResults.Remove(_connectionId);
1662+
var disconnectResults = listener.DisconnectResults;
1663+
if (NetEventSource.Log.IsEnabled())
1664+
{
1665+
string? results;
1666+
lock ((disconnectResults as ICollection).SyncRoot)
1667+
{
1668+
results = disconnectResults.ToString();
1669+
}
1670+
NetEventSource.Info(this, $"DisconnectResults {results} removing for _connectionId: {_connectionId}");
1671+
}
1672+
1673+
lock ((disconnectResults as ICollection).SyncRoot)
1674+
{
1675+
disconnectResults.Remove(_connectionId);
1676+
}
16511677

16521678
// Cached identity is disposed with the session context
16531679
Session?.Dispose();

0 commit comments

Comments
 (0)