diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs index 7ac85b3155bbc..82a8218338ca5 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs @@ -13,8 +13,8 @@ internal static partial class WinHttp public static extern SafeWinHttpHandle WinHttpOpen( IntPtr userAgent, uint accessType, - string proxyName, - string proxyBypass, int flags); + string? proxyName, + string? proxyBypass, int flags); [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] @@ -33,7 +33,7 @@ public static extern SafeWinHttpHandle WinHttpOpenRequest( SafeWinHttpHandle connectHandle, string verb, string objectName, - string version, + string? version, string referrer, string acceptTypes, uint flags); @@ -161,8 +161,8 @@ public static extern bool WinHttpSetCredentials( SafeWinHttpHandle requestHandle, uint authTargets, uint authScheme, - string userName, - string password, + string? userName, + string? password, IntPtr reserved); [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = true)] diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj b/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj index 525d50608ff7d..99e54a8c729c9 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj @@ -10,8 +10,6 @@ SR.PlatformNotSupported_WinHttpHandler - - annotations diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs index f659c9c2f07e2..b0b6d86c67541 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; - +using System.Diagnostics.CodeAnalysis; using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle; namespace System.Net.Http @@ -14,7 +14,7 @@ internal sealed class WinHttpAuthHelper // WINHTTP_AUTH_SCHEME_NTLM = 0x00000002; // WINHTTP_AUTH_SCHEME_DIGEST = 0x00000008; // WINHTTP_AUTH_SCHEME_NEGOTIATE = 0x00000010; - private static readonly string[] s_authSchemeStringMapping = + private static readonly string?[] s_authSchemeStringMapping = { null, "Basic", @@ -54,6 +54,10 @@ public void CheckResponseForAuthentication( uint supportedSchemes = 0; uint firstSchemeIgnored = 0; uint authTarget = 0; + + Debug.Assert(state.RequestMessage != null); + Debug.Assert(state.RequestMessage.RequestUri != null); + Debug.Assert(state.RequestHandle != null); Uri uri = state.RequestMessage.RequestUri; state.RetryRequest = false; @@ -121,7 +125,7 @@ public void CheckResponseForAuthentication( state.LastStatusCode = statusCode; // If we don't have any proxy credentials to try, then we end up with 407. - ICredentials proxyCreds = state.Proxy == null ? + ICredentials? proxyCreds = state.Proxy == null ? state.DefaultProxyCredentials : state.Proxy.Credentials; if (proxyCreds == null) @@ -161,6 +165,7 @@ public void CheckResponseForAuthentication( default: if (state.PreAuthenticate && serverAuthScheme != 0) { + Debug.Assert(state.ServerCredentials != null); SaveServerCredentialsToCache(uri, serverAuthScheme, state.ServerCredentials); } break; @@ -169,6 +174,10 @@ public void CheckResponseForAuthentication( public void PreAuthenticateRequest(WinHttpRequestState state, uint proxyAuthScheme) { + Debug.Assert(state.RequestHandle != null); + Debug.Assert(state.RequestMessage != null); + Debug.Assert(state.RequestMessage.RequestUri != null); + // Set proxy credentials if we have them. // If a proxy authentication challenge was responded to, reset // those credentials before each SendRequest, because the proxy @@ -177,8 +186,9 @@ public void PreAuthenticateRequest(WinHttpRequestState state, uint proxyAuthSche // 407-401-407-401- loop. if (proxyAuthScheme != 0) { - ICredentials proxyCredentials; - Uri proxyUri; + ICredentials? proxyCredentials; + Uri? proxyUri; + if (state.Proxy != null) { proxyCredentials = state.Proxy.Credentials; @@ -190,6 +200,9 @@ public void PreAuthenticateRequest(WinHttpRequestState state, uint proxyAuthSche proxyUri = state.RequestMessage.RequestUri; } + Debug.Assert(proxyCredentials != null); + Debug.Assert(proxyUri != null); + SetWinHttpCredential( state.RequestHandle, proxyCredentials, @@ -202,7 +215,7 @@ public void PreAuthenticateRequest(WinHttpRequestState state, uint proxyAuthSche if (state.PreAuthenticate) { uint authScheme; - NetworkCredential serverCredentials; + NetworkCredential? serverCredentials; if (GetServerCredentialsFromCache( state.RequestMessage.RequestUri, out authScheme, @@ -226,18 +239,18 @@ public void PreAuthenticateRequest(WinHttpRequestState state, uint proxyAuthSche public bool GetServerCredentialsFromCache( Uri uri, out uint serverAuthScheme, - out NetworkCredential serverCredentials) + [NotNullWhen(true)] out NetworkCredential? serverCredentials) { serverAuthScheme = 0; serverCredentials = null; - NetworkCredential cred = null; + NetworkCredential? cred = null; lock (_credentialCacheLock) { foreach (uint authScheme in s_authSchemePriorityOrder) { - cred = _credentialCache.GetCredential(uri, s_authSchemeStringMapping[authScheme]); + cred = _credentialCache.GetCredential(uri, s_authSchemeStringMapping[authScheme]!); if (cred != null) { serverAuthScheme = authScheme; @@ -253,10 +266,10 @@ public bool GetServerCredentialsFromCache( public void SaveServerCredentialsToCache(Uri uri, uint authScheme, ICredentials serverCredentials) { - string authType = s_authSchemeStringMapping[authScheme]; + string? authType = s_authSchemeStringMapping[authScheme]; Debug.Assert(!string.IsNullOrEmpty(authType)); - NetworkCredential cred = serverCredentials.GetCredential(uri, authType); + NetworkCredential? cred = serverCredentials.GetCredential(uri, authType); if (cred != null) { lock (_credentialCacheLock) @@ -303,15 +316,17 @@ private bool SetWinHttpCredential( uint authScheme, uint authTarget) { - string userName; - string password; + string? userName; + string? password; Debug.Assert(credentials != null); Debug.Assert(authScheme != 0); Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY || authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER); - NetworkCredential networkCredential = credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]); + string? authType = s_authSchemeStringMapping[authScheme]; + Debug.Assert(!string.IsNullOrEmpty(authType)); + NetworkCredential? networkCredential = credentials.GetCredential(uri, authType); if (networkCredential == null) { @@ -367,7 +382,7 @@ private bool SetWinHttpCredential( return true; } - private static uint ChooseAuthScheme(uint supportedSchemes, Uri uri, ICredentials credentials) + private static uint ChooseAuthScheme(uint supportedSchemes, Uri? uri, ICredentials? credentials) { if (credentials == null) { @@ -383,9 +398,11 @@ private static uint ChooseAuthScheme(uint supportedSchemes, Uri uri, ICredential return 0; } + Debug.Assert(uri != null); + foreach (uint authScheme in s_authSchemePriorityOrder) { - if ((supportedSchemes & authScheme) != 0 && credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]) != null) + if ((supportedSchemes & authScheme) != 0 && credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]!) != null) { return authScheme; } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCertificateHelper.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCertificateHelper.cs index da4baadb35903..472116113faca 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCertificateHelper.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCertificateHelper.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Net.Security; using System.Runtime.InteropServices; using System.Security.Cryptography; @@ -20,7 +21,6 @@ public static void BuildChain( out X509Chain chain, out SslPolicyErrors sslPolicyErrors) { - chain = null; sslPolicyErrors = SslPolicyErrors.None; // Build the chain. @@ -69,6 +69,8 @@ public static void BuildChain( Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG; + Debug.Assert(chain.SafeHandle != null); + Interop.Crypt32.CERT_CHAIN_POLICY_STATUS status = default; status.cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_STATUS); if (Interop.Crypt32.CertVerifyCertificateChainPolicy( diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpChannelBinding.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpChannelBinding.cs index 5e862724d0e7f..d011279e0ce54 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpChannelBinding.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpChannelBinding.cs @@ -13,7 +13,7 @@ namespace System.Net.Http internal sealed class WinHttpChannelBinding : ChannelBinding { private int _size; - private string _cachedToString; + private string? _cachedToString; internal WinHttpChannelBinding(SafeWinHttpHandle requestHandle) { @@ -55,7 +55,7 @@ public override int Size } } - public override string ToString() + public override string? ToString() { if (_cachedToString == null && !IsInvalid) { diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs index ff0ac8798aeed..739995f5e732c 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs @@ -15,17 +15,21 @@ internal static class WinHttpCookieContainerAdapter public static void AddResponseCookiesToContainer(WinHttpRequestState state) { - HttpRequestMessage request = state.RequestMessage; - SafeWinHttpHandle requestHandle = state.RequestHandle; - CookieContainer cookieContainer = state.Handler.CookieContainer; + HttpRequestMessage? request = state.RequestMessage; + SafeWinHttpHandle? requestHandle = state.RequestHandle; + Debug.Assert(state.Handler != null); + CookieContainer? cookieContainer = state.Handler.CookieContainer; Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer); + Debug.Assert(request != null); + Debug.Assert(requestHandle != null); Debug.Assert(cookieContainer != null); + Debug.Assert(request.RequestUri != null); // Get 'Set-Cookie' headers from response. - char[] buffer = null; + char[]? buffer = null; uint index = 0; - string cookieHeader; + string? cookieHeader; while (WinHttpResponseParser.GetResponseHeader( requestHandle, Interop.WinHttp.WINHTTP_QUERY_SET_COOKIE, ref buffer, ref index, out cookieHeader)) { @@ -44,9 +48,12 @@ public static void AddResponseCookiesToContainer(WinHttpRequestState state) public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redirectUri) { - SafeWinHttpHandle requestHandle = state.RequestHandle; + SafeWinHttpHandle? requestHandle = state.RequestHandle; + Debug.Assert(state.Handler != null); Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer); + Debug.Assert(state.Handler.CookieContainer != null); + Debug.Assert(requestHandle != null); // Clear cookies. if (!Interop.WinHttp.WinHttpAddRequestHeaders( @@ -64,7 +71,7 @@ public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redi // Re-add cookies. The GetCookieHeader() method will return the correct set of // cookies based on the redirectUri. - string cookieHeader = GetCookieHeader(redirectUri, state.Handler.CookieContainer); + string? cookieHeader = GetCookieHeader(redirectUri, state.Handler.CookieContainer); if (!string.IsNullOrEmpty(cookieHeader)) { if (!Interop.WinHttp.WinHttpAddRequestHeaders( @@ -78,9 +85,9 @@ public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redi } } - public static string GetCookieHeader(Uri uri, CookieContainer cookies) + public static string? GetCookieHeader(Uri uri, CookieContainer cookies) { - string cookieHeader = null; + string? cookieHeader = null; Debug.Assert(cookies != null); diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs index 63bd0aaf92f36..9ee9ef6110907 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs @@ -46,16 +46,16 @@ public class WinHttpHandler : HttpMessageHandler private static readonly StringWithQualityHeaderValue s_deflateHeaderValue = new StringWithQualityHeaderValue("deflate"); [ThreadStatic] - private static StringBuilder t_requestHeadersBuilder; + private static StringBuilder? t_requestHeadersBuilder; private readonly object _lockObject = new object(); private bool _doManualDecompressionCheck; - private WinInetProxyHelper _proxyHelper; + private WinInetProxyHelper? _proxyHelper; private bool _automaticRedirection = HttpHandlerDefaults.DefaultAutomaticRedirection; private int _maxAutomaticRedirections = HttpHandlerDefaults.DefaultMaxAutomaticRedirections; private DecompressionMethods _automaticDecompression = HttpHandlerDefaults.DefaultAutomaticDecompression; private CookieUsePolicy _cookieUsePolicy = CookieUsePolicy.UseInternalCookieStoreOnly; - private CookieContainer _cookieContainer; + private CookieContainer? _cookieContainer; private bool _enableMultipleHttp2Connections; private SslProtocols _sslProtocols = SslProtocols.None; // Use most secure protocols available. @@ -64,15 +64,15 @@ private Func< X509Certificate2, X509Chain, SslPolicyErrors, - bool> _serverCertificateValidationCallback; + bool>? _serverCertificateValidationCallback; private bool _checkCertificateRevocationList; private ClientCertificateOption _clientCertificateOption = ClientCertificateOption.Manual; - private X509Certificate2Collection _clientCertificates; // Only create collection when required. - private ICredentials _serverCredentials; + private X509Certificate2Collection? _clientCertificates; // Only create collection when required. + private ICredentials? _serverCredentials; private bool _preAuthenticate; private WindowsProxyUsePolicy _windowsProxyUsePolicy = WindowsProxyUsePolicy.UseWinHttpProxy; - private ICredentials _defaultProxyCredentials; - private IWebProxy _proxy; + private ICredentials? _defaultProxyCredentials; + private IWebProxy? _proxy; private int _maxConnectionsPerServer = int.MaxValue; private TimeSpan _sendTimeout = TimeSpan.FromSeconds(30); private TimeSpan _receiveHeadersTimeout = TimeSpan.FromSeconds(30); @@ -86,10 +86,10 @@ private Func< private int _maxResponseHeadersLength = HttpHandlerDefaults.DefaultMaxResponseHeadersLength; private int _maxResponseDrainSize = 64 * 1024; - private IDictionary _properties; // Only create dictionary when required. + private IDictionary? _properties; // Only create dictionary when required. private volatile bool _operationStarted; private volatile bool _disposed; - private SafeWinHttpHandle _sessionHandle; + private SafeWinHttpHandle? _sessionHandle; private readonly WinHttpAuthHelper _authHelper = new WinHttpAuthHelper(); public WinHttpHandler() @@ -617,8 +617,8 @@ protected override Task SendAsync( Task.Factory.StartNew(s => { - var whrs = (WinHttpRequestState)s; - _ = whrs.Handler.StartRequestAsync(whrs); + var whrs = (WinHttpRequestState)s!; + _ = whrs.Handler!.StartRequestAsync(whrs); }, state, CancellationToken.None, @@ -638,7 +638,7 @@ private static WinHttpChunkMode GetChunkedModeForSend(HttpRequestMessage request chunkedMode = WinHttpChunkMode.Manual; } - HttpContent requestContent = requestMessage.Content; + HttpContent? requestContent = requestMessage.Content; if (requestContent != null) { if (requestContent.Headers.ContentLength.HasValue) @@ -686,12 +686,14 @@ private static WinHttpChunkMode GetChunkedModeForSend(HttpRequestMessage request private static void AddRequestHeaders( SafeWinHttpHandle requestHandle, HttpRequestMessage requestMessage, - CookieContainer cookies, + CookieContainer? cookies, DecompressionMethods manuallyProcessedDecompressionMethods) { + Debug.Assert(requestMessage.RequestUri != null); + // Get a StringBuilder to use for creating the request headers. // We cache one in TLS to avoid creating a new one for each request. - StringBuilder requestHeadersBuffer = t_requestHeadersBuilder; + StringBuilder? requestHeadersBuffer = t_requestHeadersBuilder; if (requestHeadersBuffer != null) { requestHeadersBuffer.Clear(); @@ -724,7 +726,7 @@ private static void AddRequestHeaders( // Manually add cookies. if (cookies != null && cookies.Count > 0) { - string cookieHeader = WinHttpCookieContainerAdapter.GetCookieHeader(requestMessage.RequestUri, cookies); + string? cookieHeader = WinHttpCookieContainerAdapter.GetCookieHeader(requestMessage.RequestUri, cookies); if (!string.IsNullOrEmpty(cookieHeader)) { requestHeadersBuffer.AppendLine(cookieHeader); @@ -778,6 +780,8 @@ private void EnsureSessionHandleExists(WinHttpRequestState state) if (state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy) { Debug.Assert(state.Proxy != null); + Debug.Assert(state.RequestMessage != null); + Debug.Assert(state.RequestMessage.RequestUri != null); try { state.Proxy.GetProxy(state.RequestMessage.RequestUri); @@ -867,6 +871,11 @@ private void EnsureSessionHandleExists(WinHttpRequestState state) private async Task StartRequestAsync(WinHttpRequestState state) { + Debug.Assert(state.RequestMessage != null); + Debug.Assert(state.RequestMessage.RequestUri != null); + Debug.Assert(state.Handler != null); + Debug.Assert(state.Tcs != null); + if (state.CancellationToken.IsCancellationRequested) { state.Tcs.TrySetCanceled(state.CancellationToken); @@ -874,11 +883,12 @@ private async Task StartRequestAsync(WinHttpRequestState state) return; } - Task sendRequestBodyTask = null; - SafeWinHttpHandle connectHandle = null; + Task? sendRequestBodyTask = null; + SafeWinHttpHandle? connectHandle = null; try { EnsureSessionHandleExists(state); + Debug.Assert(_sessionHandle != null); SetEnableHttp2PlusClientCertificate(state.RequestMessage.RequestUri, state.RequestMessage.Version); @@ -893,7 +903,7 @@ private async Task StartRequestAsync(WinHttpRequestState state) // Try to use the requested version if a known/supported version was explicitly requested. // Otherwise, we simply use winhttp's default. - string httpVersion = null; + string? httpVersion = null; if (state.RequestMessage.Version == HttpVersion.Version10) { httpVersion = "HTTP/1.0"; @@ -929,7 +939,7 @@ private async Task StartRequestAsync(WinHttpRequestState state) // will have the side-effect of WinHTTP cancelling any pending I/O and accelerating its callbacks // on the handle and thus releasing the awaiting tasks in the loop below. This helps to provide // a more timely, cooperative, cancellation pattern. - using (state.CancellationToken.Register(s => ((WinHttpRequestState)s).RequestHandle.Dispose(), state)) + using (state.CancellationToken.Register(s => ((WinHttpRequestState)s!).RequestHandle!.Dispose(), state)) { do { @@ -1031,8 +1041,10 @@ private async Task StartRequestAsync(WinHttpRequestState state) } } - private void OpenRequestHandle(WinHttpRequestState state, SafeWinHttpHandle connectHandle, string httpVersion, out WinHttpChunkMode chunkedModeForSend, out SafeWinHttpHandle requestHandle) + private void OpenRequestHandle(WinHttpRequestState state, SafeWinHttpHandle connectHandle, string? httpVersion, out WinHttpChunkMode chunkedModeForSend, out SafeWinHttpHandle requestHandle) { + Debug.Assert(state.RequestMessage != null); + Debug.Assert(state.RequestMessage.RequestUri != null); chunkedModeForSend = GetChunkedModeForSend(state.RequestMessage); // Create an HTTP request handle. @@ -1079,7 +1091,7 @@ static uint GetRequestFlags(WinHttpRequestState state, WinHttpChunkMode chunkedM // .NET Framework behavior. System.Uri establishes the baseline rules for percent-encoding // of reserved characters. uint flags = Interop.WinHttp.WINHTTP_FLAG_ESCAPE_DISABLE; - if (state.RequestMessage.RequestUri.Scheme == UriScheme.Https) + if (state.RequestMessage!.RequestUri!.Scheme == UriScheme.Https) { flags |= Interop.WinHttp.WINHTTP_FLAG_SECURE; } @@ -1193,6 +1205,10 @@ private void SetSessionHandleTimeoutOptions(SafeWinHttpHandle sessionHandle) private void SetRequestHandleOptions(WinHttpRequestState state) { + Debug.Assert(state.RequestHandle != null); + Debug.Assert(state.RequestMessage != null); + Debug.Assert(state.RequestMessage.RequestUri != null); + SetRequestHandleProxyOptions(state); SetRequestHandleDecompressionOptions(state.RequestHandle); SetRequestHandleRedirectionOptions(state.RequestHandle); @@ -1206,6 +1222,10 @@ private void SetRequestHandleOptions(WinHttpRequestState state) private void SetRequestHandleProxyOptions(WinHttpRequestState state) { + Debug.Assert(state.RequestMessage != null); + Debug.Assert(state.RequestMessage.RequestUri != null); + Debug.Assert(state.RequestHandle != null); + // We've already set the proxy on the session handle if we're using no proxy or default proxy settings. // We only need to change it on the request handle if we have a specific IWebProxy or need to manually // implement Wininet-style auto proxy detection. @@ -1222,14 +1242,15 @@ private void SetRequestHandleProxyOptions(WinHttpRequestState state) { Debug.Assert(state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy); updateProxySettings = true; - if (state.Proxy.IsBypassed(uri)) + + Uri? proxyUri = state.Proxy.IsBypassed(uri) ? null : state.Proxy.GetProxy(uri); + if (proxyUri == null) { proxyInfo.AccessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY; } else { proxyInfo.AccessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NAMED_PROXY; - Uri proxyUri = state.Proxy.GetProxy(uri); string proxyString = proxyUri.Scheme + "://" + proxyUri.Authority; proxyInfo.Proxy = Marshal.StringToHGlobalUni(proxyString); } @@ -1362,7 +1383,7 @@ private void SetRequestHandleClientCertificateOptions(SafeWinHttpHandle requestH return; } - X509Certificate2 clientCertificate = null; + X509Certificate2? clientCertificate = null; if (_clientCertificateOption == ClientCertificateOption.Manual) { clientCertificate = CertificateHelper.GetEligibleClientCertificate(ClientCertificates); @@ -1388,6 +1409,8 @@ private void SetRequestHandleClientCertificateOptions(SafeWinHttpHandle requestH private void SetEnableHttp2PlusClientCertificate(Uri requestUri, Version requestVersion) { + Debug.Assert(_sessionHandle != null); + if (requestUri.Scheme != UriScheme.Https || requestVersion != HttpVersion20) { return; @@ -1436,6 +1459,7 @@ internal static void SetNoClientCertificate(SafeWinHttpHandle requestHandle) private void SetRequestHandleCredentialsOptions(WinHttpRequestState state) { + Debug.Assert(state.RequestHandle != null); // By default, WinHTTP sets the default credentials policy such that it automatically sends default credentials // (current user's logged on Windows credentials) to a proxy when needed (407 response). It only sends // default credentials to a server (401 response) if the server is considered to be on the Intranet. @@ -1506,6 +1530,7 @@ private static void SetWinHttpOption( private void HandleAsyncException(WinHttpRequestState state, Exception ex) { + Debug.Assert(state.Tcs != null); if (state.CancellationToken.IsCancellationRequested) { // If the exception was due to the cancellation token being canceled, throw cancellation exception. @@ -1597,6 +1622,8 @@ private RendezvousAwaitable InternalSendRequestAsync(WinHttpRequestState st { lock (state.Lock) { + Debug.Assert(state.RequestHandle != null); + state.Pin(); if (!Interop.WinHttp.WinHttpSendRequest( state.RequestHandle, @@ -1622,6 +1649,9 @@ private RendezvousAwaitable InternalSendRequestAsync(WinHttpRequestState st private async Task InternalSendRequestBodyAsync(WinHttpRequestState state, WinHttpChunkMode chunkedModeForSend) { + Debug.Assert(state.RequestMessage != null); + Debug.Assert(state.RequestMessage.Content != null); + using (var requestStream = new WinHttpRequestStream(state, chunkedModeForSend)) { await state.RequestMessage.Content.CopyToAsync(requestStream, state.TransportContext).ConfigureAwait(false); @@ -1633,6 +1663,8 @@ private RendezvousAwaitable InternalReceiveResponseHeadersAsync(WinHttpRequ { lock (state.Lock) { + Debug.Assert(state.RequestHandle != null); + if (!Interop.WinHttp.WinHttpReceiveResponse(state.RequestHandle, IntPtr.Zero)) { throw WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReceiveResponse)); diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs index 3b2212ec42aa7..f4a8f6eef82ec 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs @@ -40,7 +40,7 @@ public static void WinHttpCallback( return; } - WinHttpRequestState state = WinHttpRequestState.FromIntPtr(context); + WinHttpRequestState? state = WinHttpRequestState.FromIntPtr(context); Debug.Assert(state != null, "WinHttpCallback must have a non-null state object"); RequestCallback(handle, state, internetStatus, statusInformation, statusInformationLength); @@ -84,8 +84,7 @@ private static void RequestCallback( return; case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REDIRECT: - string redirectUriString = Marshal.PtrToStringUni(statusInformation); - var redirectUri = new Uri(redirectUriString); + var redirectUri = new Uri(Marshal.PtrToStringUni(statusInformation)!); OnRequestRedirect(state, redirectUri); return; @@ -192,6 +191,8 @@ private static void OnRequestReceiveResponseHeadersComplete(WinHttpRequestState private static void OnRequestRedirect(WinHttpRequestState state, Uri redirectUri) { Debug.Assert(state != null, "OnRequestRedirect: state is null"); + Debug.Assert(state.Handler != null, "OnRequestRedirect: state.Handler is null"); + Debug.Assert(state.RequestMessage != null, "OnRequestRedirect: state.RequestMessage is null"); Debug.Assert(redirectUri != null, "OnRequestRedirect: redirectUri is null"); // If we're manually handling cookies, we need to reset them based on the new URI. @@ -234,6 +235,8 @@ private static void OnRequestSendingRequest(WinHttpRequestState state) { Debug.Assert(state != null, "OnRequestSendingRequest: state is null"); Debug.Assert(state.RequestHandle != null, "OnRequestSendingRequest: state.RequestHandle is null"); + Debug.Assert(state.RequestMessage != null, "OnRequestSendingRequest: state.RequestMessage is null"); + Debug.Assert(state.RequestMessage.RequestUri != null, "OnRequestSendingRequest: state.RequestMessage.RequestUri is null"); if (state.RequestMessage.RequestUri.Scheme != UriScheme.Https) { @@ -280,7 +283,7 @@ private static void OnRequestSendingRequest(WinHttpRequestState state) var serverCertificate = new X509Certificate2(certHandle); Interop.Crypt32.CertFreeCertificateContext(certHandle); - X509Chain chain = null; + X509Chain? chain = null; SslPolicyErrors sslPolicyErrors; bool result = false; @@ -391,6 +394,7 @@ private static void OnRequestError(WinHttpRequestState state, Interop.WinHttp.WI break; case Interop.WinHttp.API_WRITE_DATA: + Debug.Assert(state.TcsInternalWriteDataToRequestStream != null); if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(state, "API_WRITE_DATA - ERROR_WINHTTP_OPERATION_CANCELLED"); @@ -414,7 +418,8 @@ private static void OnRequestError(WinHttpRequestState state, Interop.WinHttp.WI private static void ResetAuthRequestHeaders(WinHttpRequestState state) { const string AuthHeaderNameWithColon = "Authorization:"; - SafeWinHttpHandle requestHandle = state.RequestHandle; + SafeWinHttpHandle? requestHandle = state.RequestHandle; + Debug.Assert(requestHandle != null); // Clear auth headers. if (!Interop.WinHttp.WinHttpAddRequestHeaders( diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestState.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestState.cs index 93595b1d12af6..fca5fa8097770 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestState.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestState.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Net.Security; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; @@ -28,7 +29,7 @@ internal sealed class WinHttpRequestState : IDisposable // A GCHandle for this operation object. // This is owned by the callback and will be deallocated when the sessionHandle has been closed. private GCHandle _operationHandle; - private WinHttpTransportContext _transportContext; + private WinHttpTransportContext? _transportContext; private volatile bool _disposed; // To detect redundant calls. public WinHttpRequestState() @@ -49,10 +50,10 @@ public void Pin() } } - public static WinHttpRequestState FromIntPtr(IntPtr gcHandle) + public static WinHttpRequestState? FromIntPtr(IntPtr gcHandle) { GCHandle stateHandle = GCHandle.FromIntPtr(gcHandle); - return (WinHttpRequestState)stateHandle.Target; + return (WinHttpRequestState?)stateHandle.Target; } public IntPtr ToIntPtr() @@ -92,16 +93,16 @@ public void ClearSendRequestState() } } - public TaskCompletionSource Tcs { get; set; } + public TaskCompletionSource? Tcs { get; set; } public CancellationToken CancellationToken { get; set; } - public HttpRequestMessage RequestMessage { get; set; } + public HttpRequestMessage? RequestMessage { get; set; } - public WinHttpHandler Handler { get; set; } + public WinHttpHandler? Handler { get; set; } - private SafeWinHttpHandle _requestHandle; - public SafeWinHttpHandle RequestHandle + private SafeWinHttpHandle? _requestHandle; + public SafeWinHttpHandle? RequestHandle { get { @@ -120,12 +121,13 @@ public SafeWinHttpHandle RequestHandle } } - public Exception SavedException { get; set; } + public Exception? SavedException { get; set; } public bool CheckCertificateRevocationList { get; set; } - public Func ServerCertificateValidationCallback { get; set; } + public Func? ServerCertificateValidationCallback { get; set; } + [AllowNull] public WinHttpTransportContext TransportContext { get { return _transportContext ?? (_transportContext = new WinHttpTransportContext()); } @@ -134,11 +136,11 @@ public WinHttpTransportContext TransportContext public WindowsProxyUsePolicy WindowsProxyUsePolicy { get; set; } - public IWebProxy Proxy { get; set; } + public IWebProxy? Proxy { get; set; } - public ICredentials ServerCredentials { get; set; } + public ICredentials? ServerCredentials { get; set; } - public ICredentials DefaultProxyCredentials { get; set; } + public ICredentials? DefaultProxyCredentials { get; set; } public bool PreAuthenticate { get; set; } @@ -147,7 +149,7 @@ public WinHttpTransportContext TransportContext public bool RetryRequest { get; set; } public RendezvousAwaitable LifecycleAwaitable { get; set; } = new RendezvousAwaitable(); - public TaskCompletionSource TcsInternalWriteDataToRequestStream { get; set; } + public TaskCompletionSource? TcsInternalWriteDataToRequestStream { get; set; } public bool AsyncReadInProgress { get; set; } // WinHttpResponseStream state. diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs index 301e5a6a21fc8..5e79072f44ba8 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs @@ -33,6 +33,7 @@ internal WinHttpRequestStream(WinHttpRequestState state, WinHttpChunkMode chunke // Take copy of handle from state. // The state's request handle will be set to null once the response stream starts. + Debug.Assert(_state.RequestHandle != null); _requestHandle = _state.RequestHandle; } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseHeaderReader.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseHeaderReader.cs index 02ce3184f8fe4..f2e3292321ced 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseHeaderReader.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseHeaderReader.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http { @@ -28,7 +29,7 @@ public WinHttpResponseHeaderReader(char[] buffer, int startIndex, int length) /// Empty header lines are skipped, as are malformed header lines that are missing a colon character. /// /// true if the next header was read successfully, or false if all characters have been read. - public bool ReadHeader(out string name, out string value) + public bool ReadHeader([NotNullWhen(true)] out string? name, [NotNullWhen(true)] out string? value) { int startIndex; int length; diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs index 9f324ada27a0f..053091aadbbf8 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Compression; using System.Net.Http.Headers; @@ -21,8 +22,11 @@ public static HttpResponseMessage CreateResponseMessage( WinHttpRequestState state, DecompressionMethods manuallyProcessedDecompressionMethods) { - HttpRequestMessage request = state.RequestMessage; - SafeWinHttpHandle requestHandle = state.RequestHandle; + HttpRequestMessage? request = state.RequestMessage; + SafeWinHttpHandle? requestHandle = state.RequestHandle; + Debug.Assert(request != null); + Debug.Assert(requestHandle != null); + var response = new HttpResponseMessage(); bool stripEncodingHeaders = false; @@ -133,9 +137,9 @@ public static uint GetResponseHeaderNumberInfo(SafeWinHttpHandle requestHandle, public static unsafe bool GetResponseHeader( SafeWinHttpHandle requestHandle, uint infoLevel, - ref char[] buffer, + ref char[]? buffer, ref uint index, - out string headerValue) + [NotNullWhen(true)] out string? headerValue) { const int StackLimit = 128; @@ -286,7 +290,7 @@ private static string GetReasonPhrase(HttpStatusCode statusCode, char[] buffer, // If it's a known reason phrase, use the known reason phrase instead of allocating a new string. - string knownReasonPhrase = HttpStatusDescription.Get(statusCode); + string? knownReasonPhrase = HttpStatusDescription.Get(statusCode); return (knownReasonPhrase != null && knownReasonPhrase.AsSpan().SequenceEqual(buffer.AsSpan(0, bufferLength))) ? knownReasonPhrase : @@ -313,7 +317,7 @@ private static void ParseResponseHeaders( reader.ReadLine(); // Parse the array of headers and split them between Content headers and Response headers. - while (reader.ReadHeader(out string headerName, out string headerValue)) + while (reader.ReadHeader(out string? headerName, out string? headerValue)) { if (!responseHeaders.TryAddWithoutValidation(headerName, headerValue)) { @@ -350,7 +354,7 @@ public static void ParseResponseTrailers( var reader = new WinHttpResponseHeaderReader(buffer, 0, bufferLength); // Parse the array of headers and split them between Content headers and Response headers. - while (reader.ReadHeader(out string headerName, out string headerValue)) + while (reader.ReadHeader(out string? headerName, out string? headerValue)) { responseTrailers.TryAddWithoutValidation(headerName, headerValue); } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs index d7432541b94b9..74f0abbbb8050 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs @@ -113,7 +113,7 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio private async Task CopyToAsyncCore(Stream destination, byte[] buffer, CancellationToken cancellationToken) { _state.PinReceiveBuffer(buffer); - CancellationTokenRegistration ctr = cancellationToken.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this); + CancellationTokenRegistration ctr = cancellationToken.Register(s => ((WinHttpResponseStream)s!).CancelPendingResponseStreamReadOperation(), this); _state.AsyncReadInProgress = true; try { @@ -223,7 +223,7 @@ private async Task ReadAsyncCore(byte[] buffer, int offset, int count, Canc } _state.PinReceiveBuffer(buffer); - var ctr = token.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this); + var ctr = token.Register(s => ((WinHttpResponseStream)s!).CancelPendingResponseStreamReadOperation(), this); _state.AsyncReadInProgress = true; try { @@ -330,7 +330,7 @@ protected override void Dispose(bool disposing) if (_requestHandle != null) { _requestHandle.Dispose(); - _requestHandle = null; + _requestHandle = null!; } } } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs index 104808b472a9f..2210d16138dea 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs @@ -9,7 +9,7 @@ namespace System.Net.Http { internal static class WinHttpTraceHelper { - public static void TraceCallbackStatus(object thisOrContextObject, IntPtr handle, IntPtr context, uint status, [CallerMemberName] string memberName = null) + public static void TraceCallbackStatus(object? thisOrContextObject, IntPtr handle, IntPtr context, uint status, [CallerMemberName] string? memberName = null) { Debug.Assert(NetEventSource.Log.IsEnabled()); @@ -19,7 +19,7 @@ public static void TraceCallbackStatus(object thisOrContextObject, IntPtr handle memberName); } - public static void TraceAsyncError(object thisOrContextObject, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult, [CallerMemberName] string memberName = null) + public static void TraceAsyncError(object thisOrContextObject, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult, [CallerMemberName] string? memberName = null) { Debug.Assert(NetEventSource.Log.IsEnabled()); diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTransportContext.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTransportContext.cs index 1c3d5eea71799..ab8ee83c1a3e2 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTransportContext.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTransportContext.cs @@ -10,13 +10,13 @@ namespace System.Net.Http { internal sealed class WinHttpTransportContext : TransportContext { - private WinHttpChannelBinding _channelBinding; + private WinHttpChannelBinding? _channelBinding; internal WinHttpTransportContext() { } - public override ChannelBinding GetChannelBinding(ChannelBindingKind kind) + public override ChannelBinding? GetChannelBinding(ChannelBindingKind kind) { // WinHTTP only supports retrieval of ChannelBindingKind.Endpoint for CBT. if (kind == ChannelBindingKind.Endpoint)