Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
HttpConnectionPool.cs
Go to the documentation of this file.
4using System.IO;
15using System.Text;
19
20namespace System.Net.Http;
21
22internal sealed class HttpConnectionPool : IDisposable
23{
24 private struct RequestQueue<T>
25 {
32
34
35 public bool IsEmpty => Count == 0;
36
37 public int Count => _queue?.Count ?? 0;
38
53
55 {
56 if (_queue != null)
57 {
58 QueueItem result;
59 while (_queue.TryDequeue(out result))
60 {
61 if (result.Waiter.TrySetException(e))
62 {
63 return true;
64 }
65 }
66 }
67 return false;
68 }
69
70 public bool TryDequeueNextRequest(T connection)
71 {
72 if (_queue != null)
73 {
74 QueueItem result;
75 while (_queue.TryDequeue(out result))
76 {
77 if (result.Waiter.TrySetResult(connection))
78 {
79 return true;
80 }
81 }
82 }
83 return false;
84 }
85
87 {
88 if (_queue != null && _queue.TryPeek(out var result))
89 {
90 request = result.Request;
91 return true;
92 }
93 request = null;
94 return false;
95 }
96 }
97
98 private static readonly bool s_isWindows7Or2008R2 = GetIsWindows7Or2008R2();
99
101
102 private readonly HttpConnectionKind _kind;
103
104 private readonly Uri _proxyUri;
105
107
109
111
112 private bool _persistAuthority;
113
115
117
118 private volatile bool _altSvcEnabled = true;
119
121
122 private readonly int _maxHttp11Connections;
123
125
127
129
131
133
135
137
138 private bool _http2Enabled;
139
140 private byte[] _http2AltSvcOriginUri;
141
142 internal readonly byte[] _http2EncodedAuthorityHostHeader;
143
144 private readonly bool _http3Enabled;
145
147
149
150 internal readonly byte[] _http3EncodedAuthorityHostHeader;
151
152 private readonly byte[] _hostHeaderValueBytes;
153
155
157
159
161
162 private bool _usedSinceLastCleanup = true;
163
164 private bool _disposed;
165
166 private static readonly List<SslApplicationProtocol> s_http3ApplicationProtocols = new List<SslApplicationProtocol> { SslApplicationProtocol.Http3 };
167
169 {
171 SslApplicationProtocol.Http11
172 };
173
174 private static readonly List<SslApplicationProtocol> s_http2OnlyApplicationProtocols = new List<SslApplicationProtocol> { SslApplicationProtocol.Http2 };
175
177
179
180 public bool IsSecure
181 {
182 get
183 {
184 if (_kind != HttpConnectionKind.Https && _kind != HttpConnectionKind.SslProxyTunnel)
185 {
186 return _kind == HttpConnectionKind.SslSocksTunnel;
187 }
188 return true;
189 }
190 }
191
193
195
197
199
222
224
226
227 private bool DoProxyAuth
228 {
229 get
230 {
231 if (_kind != HttpConnectionKind.Proxy)
232 {
233 return _kind == HttpConnectionKind.ProxyConnect;
234 }
235 return true;
236 }
237 }
238
240 {
242 _kind = kind;
245 if (host != null)
246 {
248 }
249 _http2Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version20;
250 if (IsHttp3Supported())
251 {
252 _http3Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version30 && (_poolManager.Settings._quicImplementationProvider ?? QuicImplementationProviders.Default).IsSupported;
253 }
254 switch (kind)
255 {
256 case HttpConnectionKind.Http:
257 _http3Enabled = false;
258 break;
259 case HttpConnectionKind.Proxy:
260 _http2Enabled = false;
261 _http3Enabled = false;
262 break;
263 case HttpConnectionKind.ProxyTunnel:
264 _http2Enabled = false;
265 _http3Enabled = false;
266 break;
267 case HttpConnectionKind.SslProxyTunnel:
268 _http3Enabled = false;
269 break;
270 case HttpConnectionKind.ProxyConnect:
271 _maxHttp11Connections = int.MaxValue;
272 _http2Enabled = false;
273 _http3Enabled = false;
274 break;
275 case HttpConnectionKind.SocksTunnel:
276 case HttpConnectionKind.SslSocksTunnel:
277 _http3Enabled = false;
278 break;
279 }
280 if (!_http3Enabled)
281 {
282 _altSvcEnabled = false;
283 }
284 string text = null;
285 if (_originAuthority != null)
286 {
287 text = ((_originAuthority.Port != ((sslHostName == null) ? 80 : 443)) ? $"{_originAuthority.IdnHost}:{_originAuthority.Port}" : _originAuthority.IdnHost);
289 if (sslHostName == null)
290 {
293 }
294 }
295 if (sslHostName != null)
296 {
298 _sslOptionsHttp11.ApplicationProtocols = null;
299 if (_http2Enabled)
300 {
302 _sslOptionsHttp2.ApplicationProtocols = s_http2ApplicationProtocols;
304 _sslOptionsHttp2Only.ApplicationProtocols = s_http2OnlyApplicationProtocols;
307 }
309 {
311 _sslOptionsHttp3.ApplicationProtocols = s_http3ApplicationProtocols;
312 }
313 }
315 {
317 }
318 if (System.Net.NetEventSource.Log.IsEnabled())
319 {
320 Trace($"{this}", ".ctor");
321 }
322 }
323
324 [SupportedOSPlatformGuard("linux")]
325 [SupportedOSPlatformGuard("macOS")]
326 [SupportedOSPlatformGuard("Windows")]
327 internal static bool IsHttp3Supported()
328 {
330 {
331 return OperatingSystem.IsMacOS();
332 }
333 return true;
334 }
335
337 {
339 sslClientAuthenticationOptions.TargetHost = sslHostName;
340 if (s_isWindows7Or2008R2 && sslClientAuthenticationOptions.EnabledSslProtocols == SslProtocols.None)
341 {
342 if (System.Net.NetEventSource.Log.IsEnabled())
343 {
344 System.Net.NetEventSource.Info(poolManager, $"Win7OrWin2K8R2 platform, Changing default TLS protocols to {SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13}", "ConstructSslOptions");
345 }
346 sslClientAuthenticationOptions.EnabledSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
347 }
349 }
350
356
358 {
361 {
362 return (double)connection.GetLifetimeTicks(Environment.TickCount64) > pooledConnectionLifetime.TotalMilliseconds;
363 }
364 return false;
365 }
366
374
376 {
377 if (System.Net.NetEventSource.Log.IsEnabled())
378 {
379 Trace("Creating new HTTP/1.1 connection for pool.", "AddHttp11ConnectionAsync");
380 }
381 HttpConnection connection;
383 {
384 try
385 {
386 connection = await CreateHttp11ConnectionAsync(request, async: true, cts.Token).ConfigureAwait(continueOnCapturedContext: false);
387 }
388 catch (OperationCanceledException ex) when (ex.CancellationToken == cts.Token)
389 {
391 return;
392 }
393 catch (Exception e)
394 {
396 return;
397 }
398 }
399 ReturnHttp11Connection(connection, isNewConnection: true);
400 }
401
411
413 {
415 while (true)
416 {
418 lock (SyncObj)
419 {
422 if (count > 0)
423 {
426 goto IL_0095;
427 }
430 }
431 break;
432 IL_0095:
434 {
435 if (System.Net.NetEventSource.Log.IsEnabled())
436 {
437 httpConnection.Trace("Found expired HTTP/1.1 connection in pool.", "GetHttp11ConnectionAsync");
438 }
439 httpConnection.Dispose();
440 continue;
441 }
442 if (!httpConnection.PrepareForReuse(async))
443 {
444 if (System.Net.NetEventSource.Log.IsEnabled())
445 {
446 httpConnection.Trace("Found invalid HTTP/1.1 connection in pool.", "GetHttp11ConnectionAsync");
447 }
448 httpConnection.Dispose();
449 continue;
450 }
451 if (System.Net.NetEventSource.Log.IsEnabled())
452 {
453 httpConnection.Trace("Found usable HTTP/1.1 connection in pool.", "GetHttp11ConnectionAsync");
454 }
455 return httpConnection;
456 }
457 if (System.Net.NetEventSource.Log.IsEnabled())
458 {
459 Trace("No available HTTP/1.1 connections; request queued.", "GetHttp11ConnectionAsync");
460 }
462 try
463 {
464 return await taskCompletionSourceWithCancellation.WaitWithCancellationAsync(async, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
465 }
466 finally
467 {
468 if (HttpTelemetry.Log.IsEnabled())
469 {
470 HttpTelemetry.Log.Http11RequestLeftQueue(stopwatch.GetElapsedTime().TotalMilliseconds);
471 }
472 }
473 }
474
476 {
477 if (System.Net.NetEventSource.Log.IsEnabled())
478 {
479 Trace("Server does not support HTTP2; disabling HTTP2 use and proceeding with HTTP/1.1 connection", "HandleHttp11Downgrade");
480 }
481 bool flag = true;
482 lock (SyncObj)
483 {
484 _http2Enabled = false;
487 while (_http2RequestQueue.TryDequeueNextRequest(null))
488 {
489 }
491 {
494 }
495 else
496 {
497 flag = false;
498 }
499 }
500 if (!flag)
501 {
502 if (System.Net.NetEventSource.Log.IsEnabled())
503 {
504 Trace("Discarding downgraded HTTP/1.1 connection because HTTP/1.1 connection limit is exceeded", "HandleHttp11Downgrade");
505 }
506 stream.Dispose();
507 }
508 HttpConnection connection;
509 try
510 {
512 }
513 catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken)
514 {
516 return;
517 }
518 catch (Exception e)
519 {
521 return;
522 }
523 ReturnHttp11Connection(connection, isNewConnection: true);
524 }
525
527 {
528 if (System.Net.NetEventSource.Log.IsEnabled())
529 {
530 Trace("Creating new HTTP/2 connection for pool.", "AddHttp2ConnectionAsync");
531 }
532 Http2Connection connection;
534 {
535 _ = 3;
536 try
537 {
538 var (socket, stream, transportContext) = await ConnectAsync(request, async: true, cts.Token).ConfigureAwait(continueOnCapturedContext: false);
539 if (IsSecure)
540 {
542 if (!(sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2))
543 {
545 return;
546 }
547 if (sslStream.SslProtocol < SslProtocols.Tls12)
548 {
549 stream.Dispose();
551 }
552 connection = await ConstructHttp2ConnectionAsync(stream, request, cts.Token).ConfigureAwait(continueOnCapturedContext: false);
553 }
554 else
555 {
556 connection = await ConstructHttp2ConnectionAsync(stream, request, cts.Token).ConfigureAwait(continueOnCapturedContext: false);
557 }
558 }
559 catch (OperationCanceledException ex) when (ex.CancellationToken == cts.Token)
560 {
562 return;
563 }
564 catch (Exception e)
565 {
567 return;
568 }
569 }
571 ReturnHttp2Connection(connection, isNewConnection: true);
572 await valueTask.ConfigureAwait(continueOnCapturedContext: false);
573 InvalidateHttp2Connection(connection);
574 }
575
590
592 {
594 while (true)
595 {
597 lock (SyncObj)
598 {
600 if (!_http2Enabled)
601 {
602 return null;
603 }
604 int num = _availableHttp2Connections?.Count ?? 0;
605 if (num > 0)
606 {
608 goto IL_0099;
609 }
612 }
613 break;
614 IL_0099:
616 {
617 if (System.Net.NetEventSource.Log.IsEnabled())
618 {
619 http2Connection.Trace("Found expired HTTP/2 connection in pool.", "GetHttp2ConnectionAsync");
620 }
622 continue;
623 }
624 if (!http2Connection.TryReserveStream())
625 {
626 if (System.Net.NetEventSource.Log.IsEnabled())
627 {
628 http2Connection.Trace("Found HTTP/2 connection in pool without available streams.", "GetHttp2ConnectionAsync");
629 }
630 bool flag = false;
631 lock (SyncObj)
632 {
634 if (num2 != -1)
635 {
636 flag = true;
638 }
639 }
640 if (flag)
641 {
643 }
644 continue;
645 }
646 if (System.Net.NetEventSource.Log.IsEnabled())
647 {
648 http2Connection.Trace("Found usable HTTP/2 connection in pool.", "GetHttp2ConnectionAsync");
649 }
650 return http2Connection;
651 }
652 if (System.Net.NetEventSource.Log.IsEnabled())
653 {
654 Trace("No available HTTP/2 connections; request queued.", "GetHttp2ConnectionAsync");
655 }
657 try
658 {
659 return await taskCompletionSourceWithCancellation.WaitWithCancellationAsync(async, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
660 }
661 finally
662 {
663 if (HttpTelemetry.Log.IsEnabled())
664 {
665 HttpTelemetry.Log.Http20RequestLeftQueue(stopwatch.GetElapsedTime().TotalMilliseconds);
666 }
667 }
668 }
669
670 [SupportedOSPlatform("windows")]
671 [SupportedOSPlatform("linux")]
672 [SupportedOSPlatform("macos")]
674 {
676 if (http3Connection != null)
677 {
679 {
680 if (System.Net.NetEventSource.Log.IsEnabled())
681 {
682 Trace("Using existing HTTP3 connection.", "GetHttp3ConnectionAsync");
683 }
685 return http3Connection;
686 }
687 if (System.Net.NetEventSource.Log.IsEnabled())
688 {
689 http3Connection.Trace("Found expired HTTP3 connection.", "GetHttp3ConnectionAsync");
690 }
691 http3Connection.Dispose();
693 }
694 if (_http3ConnectionCreateLock == null)
695 {
696 lock (SyncObj)
697 {
698 if (_http3ConnectionCreateLock == null)
699 {
701 }
702 }
703 }
705 try
706 {
707 if (_http3Connection != null)
708 {
709 if (System.Net.NetEventSource.Log.IsEnabled())
710 {
711 Trace("Using existing HTTP3 connection.", "GetHttp3ConnectionAsync");
712 }
713 return _http3Connection;
714 }
715 if (System.Net.NetEventSource.Log.IsEnabled())
716 {
717 Trace("Attempting new HTTP3 connection.", "GetHttp3ConnectionAsync");
718 }
719 QuicConnection connection;
720 try
721 {
723 }
724 catch
725 {
727 throw;
728 }
730 if (System.Net.NetEventSource.Log.IsEnabled())
731 {
732 Trace("New HTTP3 connection established.", "GetHttp3ConnectionAsync");
733 }
734 return http3Connection;
735 }
736 finally
737 {
739 }
740 }
741
742 [SupportedOSPlatform("windows")]
743 [SupportedOSPlatform("linux")]
744 [SupportedOSPlatform("macos")]
746 {
748 while (true)
749 {
751 if (request.Version.Major >= 3 && request.VersionPolicy != 0 && httpAuthority == null)
752 {
754 }
755 if (httpAuthority == null)
756 {
757 return null;
758 }
760 {
762 }
765 if (httpResponseMessage.StatusCode != HttpStatusCode.MisdirectedRequest || connection.Authority == _originAuthority)
766 {
767 break;
768 }
769 httpResponseMessage.Dispose();
770 BlocklistAuthority(connection.Authority);
771 }
772 return httpResponseMessage;
773 }
774
776 {
777 if (_altSvcEnabled && response.Headers.TryGetValues(KnownHeaders.AltSvc.Descriptor, out var values))
778 {
779 HandleAltSvc(values, response.Headers.Age);
780 }
781 }
782
784 {
785 int retryCount = 0;
786 while (true)
787 {
788 try
789 {
791 if (IsHttp3Supported() && _http3Enabled && (request.Version.Major >= 3 || (request.VersionPolicy == HttpVersionPolicy.RequestVersionOrHigher && IsSecure)))
792 {
794 }
795 if (response == null)
796 {
797 if (request.Version.Major >= 3 && request.VersionPolicy != 0)
798 {
800 }
801 if (_http2Enabled && (request.Version.Major >= 2 || (request.VersionPolicy == HttpVersionPolicy.RequestVersionOrHigher && IsSecure)) && (request.VersionPolicy != 0 || IsSecure))
802 {
804 if (http2Connection != null)
805 {
807 }
808 }
809 if (response == null)
810 {
811 if (request.Version.Major >= 2 && request.VersionPolicy != 0)
812 {
814 }
816 connection.Acquire();
817 try
818 {
820 }
821 finally
822 {
823 connection.Release();
824 }
825 }
826 }
828 return response;
829 }
830 catch (HttpRequestException ex) when (ex.AllowRetry == RequestRetryType.RetryOnConnectionFailure)
831 {
832 if (retryCount == 3)
833 {
834 if (System.Net.NetEventSource.Log.IsEnabled())
835 {
836 Trace($"MaxConnectionFailureRetries limit of {3} hit. Retryable request will not be retried. Exception: {ex}", "SendWithVersionDetectionAndRetryAsync");
837 }
838 throw;
839 }
840 retryCount++;
841 if (System.Net.NetEventSource.Log.IsEnabled())
842 {
843 Trace($"Retry attempt {retryCount} after connection failure. Connection exception: {ex}", "SendWithVersionDetectionAndRetryAsync");
844 }
845 }
846 catch (HttpRequestException ex2) when (ex2.AllowRetry == RequestRetryType.RetryOnLowerHttpVersion)
847 {
848 if (request.VersionPolicy != 0)
849 {
851 }
852 if (System.Net.NetEventSource.Log.IsEnabled())
853 {
854 Trace($"Retrying request because server requested version fallback: {ex2}", "SendWithVersionDetectionAndRetryAsync");
855 }
856 request.Version = HttpVersion.Version11;
857 }
858 catch (HttpRequestException ex3) when (ex3.AllowRetry == RequestRetryType.RetryOnStreamLimitReached)
859 {
860 if (System.Net.NetEventSource.Log.IsEnabled())
861 {
862 Trace($"Retrying request on another HTTP/2 connection after active streams limit is reached on existing one: {ex3}", "SendWithVersionDetectionAndRetryAsync");
863 }
864 }
865 }
866 }
867
869 {
871 TimeSpan dueTime = default(TimeSpan);
872 bool flag = false;
873 foreach (string altSvcHeaderValue2 in altSvcHeaderValues)
874 {
875 int index = 0;
877 {
878 continue;
879 }
882 {
885 break;
886 }
887 if (httpAuthority != null || altSvcHeaderValue == null || !(altSvcHeaderValue.AlpnProtocolName == "h3"))
888 {
889 continue;
890 }
893 {
895 if (responseAge.HasValue)
896 {
897 maxAge -= responseAge.GetValueOrDefault();
898 }
899 if (maxAge > TimeSpan.Zero)
900 {
902 dueTime = maxAge;
903 flag = altSvcHeaderValue.Persist;
904 }
905 }
906 }
907 if (httpAuthority == null || httpAuthority.Equals(_http3Authority))
908 {
909 return;
910 }
911 if (dueTime.Ticks > 25920000000000L)
912 {
913 dueTime = TimeSpan.FromTicks(25920000000000L);
914 }
915 lock (SyncObj)
916 {
917 if (_authorityExpireTimer == null)
918 {
920 bool flag2 = false;
921 try
922 {
924 {
926 flag2 = true;
927 }
929 {
931 if (weakReference.TryGetTarget(out var target))
932 {
933 target.ExpireAltSvcAuthority();
934 }
936 }
937 finally
938 {
939 if (flag2)
940 {
942 }
943 }
944 }
945 else
946 {
948 }
950 _persistAuthority = flag;
951 }
952 if (!flag)
953 {
955 }
956 }
957
959 {
960 _http3Authority = null;
961 }
962
964 {
965 if (_altSvcBlocklist != null)
966 {
968 {
970 }
971 }
972 return false;
973 }
974
976 {
978 if (altSvcBlocklist == null)
979 {
980 lock (SyncObj)
981 {
983 if (altSvcBlocklist == null)
984 {
988 }
989 }
990 }
991 bool flag = false;
992 bool flag2;
994 {
997 {
998 _altSvcEnabled = false;
999 flag = true;
1000 }
1001 }
1002 lock (SyncObj)
1003 {
1005 {
1008 }
1009 }
1010 if (flag2)
1011 {
1012 Task.Delay(600000).ContinueWith(delegate
1013 {
1015 {
1017 }
1019 }
1020 if (flag)
1021 {
1022 Task.Delay(600000).ContinueWith(delegate
1023 {
1024 _altSvcEnabled = true;
1026 }
1027 }
1028
1029 public void OnNetworkChanged()
1030 {
1031 lock (SyncObj)
1032 {
1033 if (_http3Authority != null && !_persistAuthority)
1034 {
1037 }
1038 }
1039 }
1040
1049
1058
1067
1076
1081
1083 {
1084 Stream stream = null;
1085 Socket socket = null;
1086 switch (_kind)
1087 {
1088 case HttpConnectionKind.Http:
1089 case HttpConnectionKind.Https:
1090 case HttpConnectionKind.ProxyConnect:
1092 break;
1093 case HttpConnectionKind.Proxy:
1095 break;
1096 case HttpConnectionKind.ProxyTunnel:
1097 case HttpConnectionKind.SslProxyTunnel:
1098 stream = await EstablishProxyTunnelAsync(async, request.HasHeaders ? request.Headers : null, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
1099 break;
1100 case HttpConnectionKind.SocksTunnel:
1101 case HttpConnectionKind.SslSocksTunnel:
1103 break;
1104 }
1106 {
1107 socket = networkStream.Socket;
1108 }
1109 TransportContext item = null;
1110 if (IsSecure)
1111 {
1113 item = sslStream.TransportContext;
1114 stream = sslStream;
1115 }
1116 return (socket, stream, item);
1117 }
1118
1120 {
1121 cancellationToken.ThrowIfCancellationRequested();
1123 Socket socket = null;
1124 try
1125 {
1126 Stream item;
1127 if (Settings._connectCallback != null)
1128 {
1130 if (!async && !valueTask.IsCompleted)
1131 {
1132 Trace("ConnectCallback completing asynchronously for a synchronous request.", "ConnectToTcpHostAsync");
1133 }
1135 }
1136 else
1137 {
1138 socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
1139 {
1140 NoDelay = true
1141 };
1142 if (async)
1143 {
1144 await socket.ConnectAsync(endPoint, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
1145 }
1146 else
1147 {
1148 using (cancellationToken.UnsafeRegister(delegate(object s)
1149 {
1150 ((Socket)s).Dispose();
1151 }, socket))
1152 {
1153 socket.Connect(endPoint);
1154 }
1155 }
1156 item = new NetworkStream(socket, ownsSocket: true);
1157 }
1158 return (socket, item);
1159 }
1160 catch (Exception ex)
1161 {
1162 socket?.Dispose();
1164 }
1165 }
1166
1172
1174 {
1175 if (_http2Enabled)
1176 {
1177 if (request.Version.Major >= 2 && request.VersionPolicy != 0)
1178 {
1179 return _sslOptionsHttp2Only;
1180 }
1181 if (request.Version.Major >= 2 || request.VersionPolicy == HttpVersionPolicy.RequestVersionOrHigher)
1182 {
1183 return _sslOptionsHttp2;
1184 }
1185 }
1186 return _sslOptionsHttp11;
1187 }
1188
1190 {
1191 if (Settings._plaintextStreamFilter == null)
1192 {
1193 return stream;
1194 }
1196 try
1197 {
1199 if (!async && !valueTask.IsCompleted)
1200 {
1201 Trace("PlaintextStreamFilter completing asynchronously for a synchronous request.", "ApplyPlaintextFilterAsync");
1202 }
1203 stream2 = await valueTask.ConfigureAwait(continueOnCapturedContext: false);
1204 }
1205 catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationToken)
1206 {
1207 stream.Dispose();
1208 throw;
1209 }
1210 catch (Exception inner)
1211 {
1212 stream.Dispose();
1214 }
1215 if (stream2 == null)
1216 {
1217 stream.Dispose();
1219 }
1220 return stream2;
1221 }
1222
1232
1247
1249 {
1251 httpRequestMessage.Headers.Host = $"{_originAuthority.IdnHost}:{_originAuthority.Port}";
1252 if (headers != null && headers.TryGetValues("User-Agent", out IEnumerable<string> values))
1253 {
1254 httpRequestMessage.Headers.TryAddWithoutValidation("User-Agent", values);
1255 }
1257 if (httpResponseMessage.StatusCode != HttpStatusCode.OK)
1258 {
1259 httpResponseMessage.Dispose();
1261 }
1262 try
1263 {
1264 return httpResponseMessage.Content.ReadAsStream(cancellationToken);
1265 }
1266 catch
1267 {
1268 httpResponseMessage.Dispose();
1269 throw;
1270 }
1271 }
1272
1286
1288 {
1289 if (System.Net.NetEventSource.Log.IsEnabled())
1290 {
1291 Trace("HTTP/1.1 connection failed", "HandleHttp11ConnectionFailure");
1292 }
1293 lock (SyncObj)
1294 {
1297 _http11RequestQueue.TryFailNextRequest(e);
1299 }
1300 }
1301
1303 {
1304 if (System.Net.NetEventSource.Log.IsEnabled())
1305 {
1306 Trace("HTTP2 connection failed", "HandleHttp2ConnectionFailure");
1307 }
1308 lock (SyncObj)
1309 {
1312 _http2RequestQueue.TryFailNextRequest(e);
1314 }
1315 }
1316
1317 public void InvalidateHttp11Connection(HttpConnection connection, bool disposing = true)
1318 {
1319 lock (SyncObj)
1320 {
1323 }
1324 }
1325
1327 {
1328 if (System.Net.NetEventSource.Log.IsEnabled())
1329 {
1330 connection.Trace("", "InvalidateHttp2Connection");
1331 }
1332 bool flag = false;
1333 lock (SyncObj)
1334 {
1335 if (_availableHttp2Connections != null)
1336 {
1337 int num = _availableHttp2Connections.IndexOf(connection);
1338 if (num != -1)
1339 {
1340 flag = true;
1341 _availableHttp2Connections.RemoveAt(num);
1343 }
1344 }
1346 }
1347 if (flag)
1348 {
1349 connection.Dispose();
1350 }
1351 }
1352
1354 {
1357 {
1359 {
1360 return (double)connection.GetLifetimeTicks(Environment.TickCount64) > pooledConnectionLifetime.TotalMilliseconds;
1361 }
1362 return true;
1363 }
1364 return false;
1365 }
1366
1367 public void ReturnHttp11Connection(HttpConnection connection, bool isNewConnection = false)
1368 {
1369 if (System.Net.NetEventSource.Log.IsEnabled())
1370 {
1371 connection.Trace($"{"isNewConnection"}={isNewConnection}", "ReturnHttp11Connection");
1372 }
1373 if (!isNewConnection && CheckExpirationOnReturn(connection))
1374 {
1375 if (System.Net.NetEventSource.Log.IsEnabled())
1376 {
1377 connection.Trace("Disposing HTTP/1.1 connection return to pool. Connection lifetime expired.", "ReturnHttp11Connection");
1378 }
1379 connection.Dispose();
1380 return;
1381 }
1382 lock (SyncObj)
1383 {
1384 if (isNewConnection)
1385 {
1387 }
1388 if (_http11RequestQueue.TryDequeueNextRequest(connection))
1389 {
1390 if (System.Net.NetEventSource.Log.IsEnabled())
1391 {
1392 connection.Trace("Dequeued waiting HTTP/1.1 request.", "ReturnHttp11Connection");
1393 }
1394 return;
1395 }
1396 if (!_disposed)
1397 {
1398 _availableHttp11Connections.Add(connection);
1399 if (System.Net.NetEventSource.Log.IsEnabled())
1400 {
1401 connection.Trace("Put connection in pool.", "ReturnHttp11Connection");
1402 }
1403 return;
1404 }
1405 if (System.Net.NetEventSource.Log.IsEnabled())
1406 {
1407 connection.Trace("Disposing connection returned to pool. Pool was disposed.", "ReturnHttp11Connection");
1408 }
1409 }
1410 connection.Dispose();
1411 }
1412
1414 {
1415 if (System.Net.NetEventSource.Log.IsEnabled())
1416 {
1417 connection.Trace($"{"isNewConnection"}={isNewConnection}", "ReturnHttp2Connection");
1418 }
1419 if (!isNewConnection && CheckExpirationOnReturn(connection))
1420 {
1421 lock (SyncObj)
1422 {
1424 }
1425 if (System.Net.NetEventSource.Log.IsEnabled())
1426 {
1427 connection.Trace("Disposing HTTP/2 connection return to pool. Connection lifetime expired.", "ReturnHttp2Connection");
1428 }
1429 connection.Dispose();
1430 return;
1431 }
1432 bool flag = true;
1433 bool flag2 = false;
1434 lock (SyncObj)
1435 {
1436 if (isNewConnection)
1437 {
1439 }
1440 while (!_http2RequestQueue.IsEmpty)
1441 {
1442 if (!connection.TryReserveStream())
1443 {
1444 flag = false;
1445 if (isNewConnection)
1446 {
1449 _http2RequestQueue.TryFailNextRequest(ex);
1450 }
1451 break;
1452 }
1453 isNewConnection = false;
1454 if (!_http2RequestQueue.TryDequeueNextRequest(connection))
1455 {
1456 connection.ReleaseStream();
1457 break;
1458 }
1459 if (System.Net.NetEventSource.Log.IsEnabled())
1460 {
1461 connection.Trace("Dequeued waiting HTTP/2 request.", "ReturnHttp2Connection");
1462 }
1463 }
1465 if (_disposed)
1466 {
1468 flag2 = true;
1469 }
1470 else if (flag)
1471 {
1472 if (_availableHttp2Connections == null)
1473 {
1475 }
1476 _availableHttp2Connections.Add(connection);
1477 if (System.Net.NetEventSource.Log.IsEnabled())
1478 {
1479 connection.Trace("Put HTTP/2 connection in pool.", "ReturnHttp2Connection");
1480 }
1481 return;
1482 }
1483 }
1484 if (flag2)
1485 {
1486 if (System.Net.NetEventSource.Log.IsEnabled())
1487 {
1488 connection.Trace("Disposing HTTP/2 connection returned to pool. Pool was disposed.", "ReturnHttp2Connection");
1489 }
1490 connection.Dispose();
1491 }
1492 else
1493 {
1494 DisableHttp2Connection(connection);
1495 }
1496 }
1497
1499 {
1500 if (System.Net.NetEventSource.Log.IsEnabled())
1501 {
1502 connection.Trace("", "DisableHttp2Connection");
1503 }
1505 {
1506 bool flag = await connection.WaitForAvailableStreamsAsync().ConfigureAwait(continueOnCapturedContext: false);
1507 if (System.Net.NetEventSource.Log.IsEnabled())
1508 {
1509 connection.Trace($"WaitForAvailableStreamsAsync completed, {"usable"}={flag}", "DisableHttp2Connection");
1510 }
1511 if (flag)
1512 {
1513 ReturnHttp2Connection(connection, isNewConnection: false);
1514 }
1515 else
1516 {
1517 lock (SyncObj)
1518 {
1521 }
1522 if (System.Net.NetEventSource.Log.IsEnabled())
1523 {
1524 connection.Trace("HTTP2 connection no longer usable", "DisableHttp2Connection");
1525 }
1526 connection.Dispose();
1527 }
1528 });
1529 }
1530
1532 {
1533 lock (SyncObj)
1534 {
1535 if (_http3Connection == connection)
1536 {
1537 _http3Connection = null;
1538 }
1539 }
1540 }
1541
1542 public void Dispose()
1543 {
1545 lock (SyncObj)
1546 {
1547 if (!_disposed)
1548 {
1549 if (System.Net.NetEventSource.Log.IsEnabled())
1550 {
1551 Trace("Disposing pool.", "Dispose");
1552 }
1553 _disposed = true;
1556 if (_availableHttp2Connections != null)
1557 {
1559 }
1563 if (_http3Connection != null)
1564 {
1566 _http3Connection = null;
1567 }
1568 if (_authorityExpireTimer != null)
1569 {
1571 _authorityExpireTimer = null;
1572 }
1574 {
1578 }
1579 }
1580 }
1581 list?.ForEach(delegate(HttpConnectionBase c)
1582 {
1583 c.Dispose();
1584 });
1585 }
1586
1588 {
1592 lock (SyncObj)
1593 {
1595 {
1596 _disposed = true;
1597 return true;
1598 }
1599 _usedSinceLastCleanup = false;
1600 long tickCount = Environment.TickCount64;
1602 if (_availableHttp2Connections != null)
1603 {
1606 }
1607 }
1609 {
1610 c.Dispose();
1611 });
1612 return false;
1614 {
1616 {
1617 long idleTicks = connection.GetIdleTicks(nowTicks);
1618 if ((double)idleTicks > pooledConnectionIdleTimeout.TotalMilliseconds)
1619 {
1620 if (System.Net.NetEventSource.Log.IsEnabled())
1621 {
1622 connection.Trace($"Scavenging connection. Idle {TimeSpan.FromMilliseconds(idleTicks)} > {pooledConnectionIdleTimeout}.", "CleanCacheAndDisposeIfUnused");
1623 }
1624 return false;
1625 }
1626 }
1628 {
1629 long lifetimeTicks = connection.GetLifetimeTicks(nowTicks);
1630 if ((double)lifetimeTicks > pooledConnectionLifetime.TotalMilliseconds)
1631 {
1632 if (System.Net.NetEventSource.Log.IsEnabled())
1633 {
1634 connection.Trace($"Scavenging connection. Lifetime {TimeSpan.FromMilliseconds(lifetimeTicks)} > {pooledConnectionLifetime}.", "CleanCacheAndDisposeIfUnused");
1635 }
1636 return false;
1637 }
1638 }
1639 if (!connection.CheckUsabilityOnScavenge())
1640 {
1641 if (System.Net.NetEventSource.Log.IsEnabled())
1642 {
1643 connection.Trace("Scavenging connection. Unexpected data or EOF received.", "CleanCacheAndDisposeIfUnused");
1644 }
1645 return false;
1646 }
1647 return true;
1648 }
1650 {
1651 int i;
1653 {
1654 }
1655 int num2 = 0;
1656 if (i < list.Count)
1657 {
1658 if (toDispose == null)
1659 {
1661 }
1662 int j = i + 1;
1663 while (j < list.Count)
1664 {
1666 {
1667 toDispose.Add(list[j]);
1668 }
1669 if (j < list.Count)
1670 {
1671 list[i++] = list[j++];
1672 }
1673 }
1674 num2 = list.Count - i;
1675 list.RemoveRange(i, num2);
1676 }
1677 return num2;
1678 }
1679 }
1680
1681 private static bool GetIsWindows7Or2008R2()
1682 {
1684 if (oSVersion.Platform == PlatformID.Win32NT)
1685 {
1686 Version version = oSVersion.Version;
1687 if (version.Major == 6)
1688 {
1689 return version.Minor == 1;
1690 }
1691 return false;
1692 }
1693 return false;
1694 }
1695
1696 internal void HeartBeat()
1697 {
1699 lock (SyncObj)
1700 {
1701 array = _availableHttp2Connections?.ToArray();
1702 }
1703 if (array != null)
1704 {
1707 {
1708 http2Connection.HeartBeat();
1709 }
1710 }
1711 }
1712
1713 public override string ToString()
1714 {
1715 return "HttpConnectionPool " + ((!(_proxyUri == null)) ? ((_sslOptionsHttp11 == null) ? $"Proxy {_proxyUri}" : ($"https://{_originAuthority}/ tunnelled via Proxy {_proxyUri}" + ((_sslOptionsHttp11.TargetHost != _originAuthority.IdnHost) ? (", SSL TargetHost=" + _sslOptionsHttp11.TargetHost) : null))) : ((_sslOptionsHttp11 == null) ? $"http://{_originAuthority}" : ($"https://{_originAuthority}" + ((_sslOptionsHttp11.TargetHost != _originAuthority.IdnHost) ? (", SSL TargetHost=" + _sslOptionsHttp11.TargetHost) : null))));
1716 }
1717
1718 private void Trace(string message, [CallerMemberName] string memberName = null)
1719 {
1720 System.Net.NetEventSource.Log.HandlerMessage(GetHashCode(), 0, 0, memberName, message);
1721 }
1722}
bool ICollection< KeyValuePair< TKey, TValue > >. Remove(KeyValuePair< TKey, TValue > keyValuePair)
bool ICollection< KeyValuePair< TKey, TValue > >. Contains(KeyValuePair< TKey, TValue > keyValuePair)
void Add(TKey key, TValue value)
static long TickCount64
static OperatingSystem OSVersion
static CultureInfo InvariantCulture
static readonly Version Version20
static readonly Version Version11
Definition HttpVersion.cs:9
static ValueTask< HttpResponseMessage > SendWithRequestAuthAsync(HttpRequestMessage request, bool async, ICredentials credentials, bool preAuthenticate, HttpConnectionPool pool, CancellationToken cancellationToken)
static Task< HttpResponseMessage > SendWithNtProxyAuthAsync(HttpRequestMessage request, Uri proxyUri, bool async, ICredentials proxyCredentials, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken)
static Task< HttpResponseMessage > SendWithNtConnectionAuthAsync(HttpRequestMessage request, bool async, ICredentials credentials, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken)
static ValueTask< HttpResponseMessage > SendWithProxyAuthAsync(HttpRequestMessage request, Uri proxyUri, bool async, ICredentials proxyCredentials, bool doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
static Exception CreateOperationCanceledException(Exception innerException, CancellationToken cancellationToken)
static Exception CreateWrappedException(Exception error, string host, int port, CancellationToken cancellationToken)
static async ValueTask< SslStream > EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, bool async, Stream stream, CancellationToken cancellationToken)
static async ValueTask< QuicConnection > ConnectQuicAsync(HttpRequestMessage request, QuicImplementationProvider quicImplementationProvider, DnsEndPoint endPoint, SslClientAuthenticationOptions clientAuthenticationOptions, CancellationToken cancellationToken)
static byte[] EncodeLiteralHeaderFieldWithoutIndexingToAllocatedArray(int index)
static readonly KnownHeader AltSvc
ValueTask< bool > WaitForAvailableStreamsAsync()
override void Trace(string message, [CallerMemberName] string memberName=null)
async Task< HttpResponseMessage > SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
void Trace(string message, [CallerMemberName] string memberName=null)
long GetIdleTicks(long nowTicks)
ValueTask< HttpResponseMessage > SendProxyConnectAsync(HttpRequestMessage request, Uri proxyUri, bool async, CancellationToken cancellationToken)
readonly SslClientAuthenticationOptions _sslOptionsHttp2
RequestQueue< Http2Connection > _http2RequestQueue
static readonly List< SslApplicationProtocol > s_http2ApplicationProtocols
Task< HttpResponseMessage > SendWithNtProxyAuthAsync(HttpConnection connection, HttpRequestMessage request, bool async, CancellationToken cancellationToken)
readonly SslClientAuthenticationOptions _sslOptionsHttp3
async ValueTask<(Socket, Stream)> ConnectToTcpHostAsync(string host, int port, HttpRequestMessage initialRequest, bool async, CancellationToken cancellationToken)
async Task AddHttp2ConnectionAsync(HttpRequestMessage request)
async ValueTask< HttpResponseMessage > SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, bool async, bool doRequestAuth, CancellationToken cancellationToken)
static void ThrowGetVersionException(HttpRequestMessage request, int desiredVersion)
void InvalidateHttp11Connection(HttpConnection connection, bool disposing=true)
static Exception CreateConnectTimeoutException(OperationCanceledException oce)
readonly HttpConnectionKind _kind
void ProcessAltSvc(HttpResponseMessage response)
HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionKind kind, string host, int port, string sslHostName, Uri proxyUri)
async ValueTask< Http3Connection > GetHttp3ConnectionAsync(HttpRequestMessage request, HttpAuthority authority, CancellationToken cancellationToken)
static readonly List< SslApplicationProtocol > s_http3ApplicationProtocols
void InvalidateHttp3Connection(Http3Connection connection)
void BlocklistAuthority(HttpAuthority badAuthority)
static readonly List< SslApplicationProtocol > s_http2OnlyApplicationProtocols
async ValueTask< HttpResponseMessage > TrySendUsingHttp3Async(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
List< Http2Connection > _availableHttp2Connections
bool CheckExpirationOnReturn(HttpConnectionBase connection)
async ValueTask< Stream > EstablishProxyTunnelAsync(bool async, HttpRequestHeaders headers, CancellationToken cancellationToken)
void ReturnHttp11Connection(HttpConnection connection, bool isNewConnection=false)
async Task HandleHttp11Downgrade(HttpRequestMessage request, Socket socket, Stream stream, TransportContext transportContext, CancellationToken cancellationToken)
CancellationTokenSource GetConnectTimeoutCancellationTokenSource()
Task< HttpResponseMessage > SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, bool async, bool doRequestAuth, CancellationToken cancellationToken)
async ValueTask<(Socket, Stream, TransportContext)> ConnectAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
async ValueTask< HttpConnection > CreateHttp11ConnectionAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
static SslClientAuthenticationOptions ConstructSslOptions(HttpConnectionPoolManager poolManager, string sslHostName)
bool CheckExpirationOnGet(HttpConnectionBase connection)
readonly List< HttpConnection > _availableHttp11Connections
SslClientAuthenticationOptions GetSslOptionsForRequest(HttpRequestMessage request)
async ValueTask< Http2Connection > GetHttp2ConnectionAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
async ValueTask<(Socket socket, Stream stream)> EstablishSocksTunnel(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
void InvalidateHttp2Connection(Http2Connection connection)
void Trace(string message, [CallerMemberName] string memberName=null)
async Task AddHttp11ConnectionAsync(HttpRequestMessage request)
void ReturnHttp2Connection(Http2Connection connection, bool isNewConnection)
void HandleAltSvc(IEnumerable< string > altSvcHeaderValues, TimeSpan? responseAge)
readonly HttpConnectionPoolManager _poolManager
volatile HashSet< HttpAuthority > _altSvcBlocklist
CancellationTokenSource _altSvcBlocklistTimerCancellation
async ValueTask< HttpConnection > GetHttp11ConnectionAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
ValueTask< HttpResponseMessage > SendWithProxyAuthAsync(HttpRequestMessage request, bool async, bool doRequestAuth, CancellationToken cancellationToken)
RequestQueue< HttpConnection > _http11RequestQueue
async ValueTask< Http2Connection > ConstructHttp2ConnectionAsync(Stream stream, HttpRequestMessage request, CancellationToken cancellationToken)
bool IsAltSvcBlocked(HttpAuthority authority)
async ValueTask< Stream > ApplyPlaintextFilterAsync(bool async, Stream stream, Version httpVersion, HttpRequestMessage request, CancellationToken cancellationToken)
async ValueTask< HttpConnection > ConstructHttp11ConnectionAsync(bool async, Socket socket, Stream stream, TransportContext transportContext, HttpRequestMessage request, CancellationToken cancellationToken)
void DisableHttp2Connection(Http2Connection connection)
readonly SslClientAuthenticationOptions _sslOptionsHttp2Only
readonly SslClientAuthenticationOptions _sslOptionsHttp11
ValueTask< HttpResponseMessage > SendAsync(HttpRequestMessage request, bool async, bool doRequestAuth, CancellationToken cancellationToken)
QuicImplementationProvider _quicImplementationProvider
Func< SocketsHttpPlaintextStreamFilterContext, CancellationToken, ValueTask< Stream > > _plaintextStreamFilter
Func< SocketsHttpConnectionContext, CancellationToken, ValueTask< Stream > > _connectCallback
Task< HttpResponseMessage > SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
override void Trace(string message, [CallerMemberName] string memberName=null)
static HttpMethod Connect
Definition HttpMethod.cs:51
static readonly HttpTelemetry Log
static byte[] EncodeLiteralHeaderFieldWithStaticNameReferenceToArray(int index)
static async ValueTask EstablishSocksTunnelAsync(Stream stream, string host, int port, Uri proxyUri, ICredentials proxyCredentials, bool async, CancellationToken cancellationToken)
static readonly System.Net.NetEventSource Log
static void Info(object thisOrContextObject, FormattableString formattableString=null, [CallerMemberName] string memberName=null)
static string net_http_proxy_tunnel_returned_failure_status_code
Definition SR.cs:228
static string net_http_connect_timedout
Definition SR.cs:192
static string Format(string resourceFormat, object p1)
Definition SR.cs:118
static string net_http_exception_during_plaintext_filter
Definition SR.cs:204
static string net_http_client_execution_error
Definition SR.cs:58
static string net_http_requested_version_cannot_establish
Definition SR.cs:200
static string net_http_null_from_connect_callback
Definition SR.cs:206
static string net_http_http2_connection_not_established
Definition SR.cs:150
static string net_http_null_from_plaintext_filter
Definition SR.cs:208
static string net_http_request_aborted
Definition SR.cs:120
static string net_ssl_http2_requires_tls12
Definition SR.cs:142
static string net_http_requested_version_server_refused
Definition SR.cs:202
Definition SR.cs:7
static Encoding ASCII
Definition Encoding.cs:511
static AsyncFlowControl SuppressFlow()
new ConfiguredTaskAwaitable< TResult > ConfigureAwait(bool continueOnCapturedContext)
Definition Task.cs:226
static Task Run(Action action)
Definition Task.cs:3395
static Task Delay(TimeSpan delay)
Definition Task.cs:3453
static readonly TimeSpan InfiniteTimeSpan
Definition Timeout.cs:5
bool Dispose(WaitHandle notifyObject)
Definition Timer.cs:176
bool Change(int dueTime, int period)
Definition Timer.cs:131
static bool Read(ref bool location)
Definition Volatile.cs:67
string IdnHost
Definition Uri.cs:537
int Port
Definition Uri.cs:453
static Microsoft.Extensions.Internal.ValueStopwatch StartNew()
TaskCompletionSourceWithCancellation< T > Waiter
bool TryPeekNextRequest([NotNullWhen(true)] out HttpRequestMessage request)
TaskCompletionSourceWithCancellation< T > EnqueueRequest(HttpRequestMessage request)
static readonly SslApplicationProtocol Http2
static readonly TimeSpan Zero
Definition TimeSpan.cs:21
static TimeSpan FromTicks(long value)
Definition TimeSpan.cs:277