diff --git a/src/System.Net.Http/CFContentStream.cs b/src/System.Net.Http/CFContentStream.cs index 4e4985cac8dc..b2acefdbcd9b 100644 --- a/src/System.Net.Http/CFContentStream.cs +++ b/src/System.Net.Http/CFContentStream.cs @@ -35,22 +35,21 @@ using CFNetwork; using CoreFoundation; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace System.Net.Http { class BufferData { - public byte [] Buffer; + public required byte [] Buffer; public int Length; } class CFContentStream : HttpContent { readonly CFHTTPStream http_stream; - BufferData data; + BufferData? data; Mutex data_mutex; AutoResetEvent data_event; AutoResetEvent data_read_event; - ExceptionDispatchInfo http_exception; + ExceptionDispatchInfo? http_exception; // The requirements are: // * We must read at least one byte from the stream every time @@ -83,13 +82,18 @@ public CFContentStream (CFHTTPStream stream) data_mutex = new Mutex (); } - void HandleErrorEvent (object sender, CFStream.StreamEventArgs e) + void HandleErrorEvent (object? sender, CFStream.StreamEventArgs e) { + if (sender is null) + return; var gotMutex = data_mutex.WaitOne (); if (gotMutex) { var stream = (CFHTTPStream) sender; - if (e.EventType == CFStreamEventType.ErrorOccurred) - Volatile.Write (ref http_exception, ExceptionDispatchInfo.Capture (stream.GetError ())); + if (e.EventType == CFStreamEventType.ErrorOccurred) { + var error = stream.GetError (); + if (error is not null) + Volatile.Write (ref http_exception, ExceptionDispatchInfo.Capture (error)); + } data_mutex.ReleaseMutex (); } } @@ -99,7 +103,8 @@ public void ReadStreamData () data_read_event.WaitOne (); // make sure there's no pending data. data_mutex.WaitOne (); - data.Length = (int) http_stream.Read (data.Buffer, 0, data.Buffer.Length); + if (data is not null) + data.Length = (int) http_stream.Read (data.Buffer, 0, data.Buffer.Length); data_mutex.ReleaseMutex (); data_event.Set (); @@ -117,7 +122,7 @@ public void Close () data_event.Set (); } - protected override async Task SerializeToStreamAsync (Stream stream, TransportContext context) + protected override async Task SerializeToStreamAsync (Stream stream, TransportContext? context) { while (data_event.WaitOne ()) { data_mutex.WaitOne (); diff --git a/src/System.Net.Http/CFNetworkHandler.cs b/src/System.Net.Http/CFNetworkHandler.cs index fbe5115091ce..ca3c03af3bda 100644 --- a/src/System.Net.Http/CFNetworkHandler.cs +++ b/src/System.Net.Http/CFNetworkHandler.cs @@ -37,8 +37,7 @@ using CoreFoundation; using CF = CoreFoundation; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace System.Net.Http { /// To be added. @@ -53,10 +52,10 @@ namespace System.Net.Http { [ObsoletedOSPlatform ("tvos", "Use 'NSUrlSessionHandler' instead.")] public class CFNetworkHandler : HttpMessageHandler { class StreamBucket { - public TaskCompletionSource Response; - public HttpRequestMessage Request; + public required TaskCompletionSource Response; + public required HttpRequestMessage Request; public CancellationTokenRegistration CancellationTokenRegistration; - public CFContentStream ContentStream; + public CFContentStream? ContentStream; public bool StreamCanBeDisposed; public void Close () @@ -92,7 +91,7 @@ public void Close () bool allowAutoRedirect; bool sentRequest; bool useSystemProxy; - CookieContainer cookies; + CookieContainer? cookies; Dictionary streamBuckets; @@ -165,7 +164,8 @@ protected override void Dispose (bool disposing) CFHTTPMessage CreateWebRequestAsync (HttpRequestMessage request) { - var req = CFHTTPMessage.CreateRequest (request.RequestUri, request.Method.Method, request.Version); + var requestUri = request.RequestUri ?? throw new InvalidOperationException ("The request URI must not be null."); + var req = CFHTTPMessage.CreateRequest (requestUri, request.Method.Method, request.Version); // TODO: /* @@ -186,7 +186,7 @@ CFHTTPMessage CreateWebRequestAsync (HttpRequestMessage request) } */ if (cookies is not null) { - string cookieHeader = cookies.GetCookieHeader (request.RequestUri); + string cookieHeader = cookies.GetCookieHeader (requestUri); if (cookieHeader != "") req.SetHeaderFieldValue ("Cookie", cookieHeader); } @@ -234,7 +234,7 @@ internal async Task SendAsync (HttpRequestMessage request, if (useSystemProxy) { var proxies = CF.CFNetwork.GetSystemProxySettings (); - if (proxies.HTTPEnable) { + if (proxies is not null && proxies.HTTPEnable) { stream.SetProxy (proxies); } } @@ -268,8 +268,7 @@ internal async Task SendAsync (HttpRequestMessage request, stream.Open (); bucket.CancellationTokenRegistration = cancellationToken.Register (() => { - StreamBucket bucket2; - if (!streamBuckets.TryGetValue (stream.Handle, out bucket2)) + if (!streamBuckets.TryGetValue (stream.Handle, out var bucket2)) return; bucket2.Response.TrySetCanceled (); @@ -305,21 +304,27 @@ static bool IsRedirect (HttpStatusCode status) status == HttpStatusCode.RedirectKeepVerb; // 307 } - void HandleErrorEvent (object sender, CFStream.StreamEventArgs e) + void HandleErrorEvent (object? sender, CFStream.StreamEventArgs e) { + if (sender is null) + return; var stream = (CFHTTPStream) sender; - StreamBucket bucket; - if (!streamBuckets.TryGetValue (stream.Handle, out bucket)) + if (!streamBuckets.TryGetValue (stream.Handle, out var bucket)) return; var ex = stream.GetError (); - bucket.Response.TrySetException (new HttpRequestException (ex.FailureReason, ex)); + if (ex is not null) + bucket.Response.TrySetException (new HttpRequestException (ex.FailureReason, ex)); + else + bucket.Response.TrySetException (new HttpRequestException ("Unknown error")); CloseStream (stream); } - void HandleClosedEvent (object sender, CFStream.StreamEventArgs e) + void HandleClosedEvent (object? sender, CFStream.StreamEventArgs e) { + if (sender is null) + return; var stream = (CFHTTPStream) sender; // might not have been called (e.g. no data) but initialize critical data HandleHasBytesAvailableEvent (sender, e); @@ -339,21 +344,25 @@ void CloseStream (CFHTTPStream stream) stream.Close (); } - void HandleHasBytesAvailableEvent (object sender, CFStream.StreamEventArgs e) + void HandleHasBytesAvailableEvent (object? sender, CFStream.StreamEventArgs e) { + if (sender is null) + return; var stream = (CFHTTPStream) sender; - StreamBucket bucket; - if (!streamBuckets.TryGetValue (stream.Handle, out bucket)) + if (!streamBuckets.TryGetValue (stream.Handle, out var bucket)) return; if (bucket.Response.Task.IsCompleted) { - bucket.ContentStream.ReadStreamData (); + bucket.ContentStream?.ReadStreamData (); return; } var header = stream.GetResponseHeader (); + if (header is null) + throw new InvalidOperationException ("Failed to get response header."); + // Is this possible? if (!header.IsHeaderComplete) throw new NotImplementedException (); @@ -372,14 +381,16 @@ void HandleHasBytesAvailableEvent (object sender, CFStream.StreamEventArgs e) continue; var key = entry.Key.ToString (); - var value = entry.Value is null ? string.Empty : entry.Value.ToString (); + if (key is null) + continue; + var value = entry.Value is null ? string.Empty : entry.Value.ToString () ?? string.Empty; HttpHeaders item_headers; if (IsContentHeader (key)) { item_headers = response_msg.Content.Headers; } else { item_headers = response_msg.Headers; - if (cookies is not null && (key == "Set-Cookie" || key == "Set-Cookie2")) + if (cookies is not null && (key == "Set-Cookie" || key == "Set-Cookie2") && bucket.Request.RequestUri is not null) AddCookie (value, bucket.Request.RequestUri, key); } @@ -391,14 +402,14 @@ void HandleHasBytesAvailableEvent (object sender, CFStream.StreamEventArgs e) if (!bucket.Response.Task.IsCanceled) { bucket.Response.TrySetResult (response_msg); - bucket.ContentStream.ReadStreamData (); + bucket.ContentStream?.ReadStreamData (); } } void AddCookie (string value, Uri uri, string header) { try { - cookies.SetCookies (uri, value); + cookies?.SetCookies (uri, value); } catch { } } diff --git a/tests/cecil-tests/ObsoleteTest.cs b/tests/cecil-tests/ObsoleteTest.cs index a562ec57c284..6f77488294aa 100644 --- a/tests/cecil-tests/ObsoleteTest.cs +++ b/tests/cecil-tests/ObsoleteTest.cs @@ -44,6 +44,10 @@ public void GetAllObsoletedThings (AssemblyInfo info) bool FilterMember (ICustomAttributeProvider provider) { + // We don't care about APIs that aren't public + if (provider is MemberReference mr && !mr.IsPubliclyVisible ()) + return false; + // If an API isn't obsolete, it's not under scrutiny from this test. if (!provider.IsObsolete ()) return false;