From 0093d4e843ba266157bd7d166f679a34f75ac4b6 Mon Sep 17 00:00:00 2001 From: Geovanni Perez <1775792+geoperez@users.noreply.github.com> Date: Sun, 6 Oct 2019 11:44:37 -0500 Subject: [PATCH] Upgrade to C# 8 (#388) * Update netcore.yml * Update appveyor.yml * Update Targets * Update appveyor.yml * Change to VS 2019 VM * Add Nullable Context * Add Nullable context * Revert to NetStandard2.0 and add nullable context * Add nullable context * Revert to Net standard 2.0 * Revert file TestRequest * [UPD] to using var * [ADD] new null checks feature to Embedio project * [ADD] new null checks feature to Embedio Test project * [ADD] new null checks feature to Embedio Unit Test project * [UPD] Remove Samples from CI Build * [FIX] Revert EndpointListener * [FIX] Restore with a fix * [UPD] Missing null checks * [UPD] Missing null checks v2 * [UPD] Missing null checks v3 * Update netcore.yml Include windows to matrix * Update netcore.yml Revert adding windows to the matrix * [UPD] Swan including new null checks --- .github/workflows/netcore.yml | 4 +- appveyor.yml | 14 +- src/EmbedIO.Samples/EmbedIO.Samples.csproj | 5 +- src/EmbedIO.Testing/EmbedIO.Testing.csproj | 5 +- .../HttpResponseMessageExtensions.cs | 10 +- src/EmbedIO.Testing/Internal/TestContext.cs | 4 +- .../Internal/TestMessageHandler.cs | 71 ++++----- src/EmbedIO.Testing/Internal/TestRequest.cs | 10 +- src/EmbedIO.Testing/Internal/TestResponse.cs | 8 +- src/EmbedIO.Testing/MockFileProvider.cs | 30 ++-- src/EmbedIO.Testing/StockResource.cs | 62 ++++---- src/EmbedIO.Testing/TestWebServer.cs | 16 +- src/EmbedIO/Actions/RedirectModule.cs | 6 +- .../BasicAuthenticationModule.cs | 2 +- .../BasicAuthenticationModuleBase.cs | 2 +- src/EmbedIO/EmbedIO.csproj | 5 +- src/EmbedIO/ExceptionHandler.cs | 1 - src/EmbedIO/Files/FileCache.Section.cs | 4 +- src/EmbedIO/Files/FileCache.cs | 10 +- src/EmbedIO/Files/FileModule.cs | 58 ++++--- src/EmbedIO/Files/FileSystemProvider.cs | 6 +- src/EmbedIO/Files/IFileProvider.cs | 2 +- src/EmbedIO/Files/Internal/FileCacheItem.cs | 18 +-- .../Files/Internal/HtmlDirectoryLister.cs | 54 +++---- src/EmbedIO/Files/MappedResourceInfo.cs | 4 +- src/EmbedIO/Files/ResourceFileProvider.cs | 12 +- src/EmbedIO/Files/ZipFileProvider.cs | 4 +- src/EmbedIO/HttpContextExtensions-Requests.cs | 26 ++- .../HttpContextExtensions-ResponseStream.cs | 19 +-- .../HttpContextExtensions-Responses.cs | 6 +- src/EmbedIO/HttpException-Shortcuts.cs | 12 +- src/EmbedIO/HttpException.cs | 14 +- src/EmbedIO/HttpNotAcceptableException.cs | 4 +- src/EmbedIO/IHttpContextImpl.cs | 4 +- src/EmbedIO/IHttpResponse.cs | 2 +- src/EmbedIO/Internal/CompressionUtility.cs | 20 +-- src/EmbedIO/Internal/UriUtility.cs | 2 +- src/EmbedIO/Net/CookieList.cs | 6 +- src/EmbedIO/Net/HttpListener.cs | 4 +- src/EmbedIO/Net/Internal/EndPointListener.cs | 24 +-- src/EmbedIO/Net/Internal/HttpConnection.cs | 28 ++-- .../Net/Internal/HttpListenerContext.cs | 16 +- .../Net/Internal/HttpListenerRequest.cs | 35 ++-- .../Net/Internal/HttpListenerResponse.cs | 13 +- .../Internal/HttpListenerResponseHelper.cs | 149 ++++++------------ src/EmbedIO/Net/Internal/ListenerPrefix.cs | 2 +- src/EmbedIO/Net/Internal/ResponseStream.cs | 4 +- src/EmbedIO/Net/Internal/SystemHttpContext.cs | 6 +- src/EmbedIO/RequestHandler.cs | 12 +- src/EmbedIO/ResponseSerializer.cs | 6 +- src/EmbedIO/ResponseSerializerCallback.cs | 2 +- src/EmbedIO/Routing/Route.cs | 25 +-- src/EmbedIO/Routing/RouteMatch.cs | 8 +- src/EmbedIO/Routing/RouteMatcher.cs | 12 +- src/EmbedIO/Routing/RouteResolverBase`1.cs | 2 +- .../Routing/RouteVerbResolverCollection.cs | 27 ++-- src/EmbedIO/Sessions/ISession.cs | 1 - src/EmbedIO/Sessions/LocalSessionManager.cs | 2 +- src/EmbedIO/Sessions/SessionProxy.cs | 2 +- .../NameValueCollectionExtensions.cs | 18 +-- src/EmbedIO/Utilities/QValueList.cs | 4 +- src/EmbedIO/Utilities/QValueListExtensions.cs | 2 +- src/EmbedIO/Utilities/UrlEncodedDataParser.cs | 2 +- src/EmbedIO/Utilities/UrlPath.cs | 6 +- src/EmbedIO/Utilities/Validate.cs | 4 +- src/EmbedIO/WebApi/FormFieldAttribute.cs | 8 +- src/EmbedIO/WebApi/IRequestDataAttribute`1.cs | 2 +- src/EmbedIO/WebApi/QueryFieldAttribute.cs | 8 +- src/EmbedIO/WebApi/WebApiController.cs | 2 +- src/EmbedIO/WebApi/WebApiModuleBase.cs | 22 ++- src/EmbedIO/WebModuleBase.cs | 12 +- .../WebModuleContainerExtensions-Files.cs | 25 ++- .../WebModuleContainerExtensions-Routing.cs | 3 +- .../WebModuleContainerExtensions-WebApi.cs | 5 +- src/EmbedIO/WebModuleContainerExtensions.cs | 8 +- src/EmbedIO/WebServer.cs | 16 +- src/EmbedIO/WebServerBase`1.cs | 9 +- .../WebServerExtensions-SessionManager.cs | 2 +- src/EmbedIO/WebServerOptions.cs | 54 +++---- src/EmbedIO/WebSockets/IWebSocket.cs | 2 +- .../WebSockets/Internal/PayloadData.cs | 4 +- .../WebSockets/Internal/StreamExtensions.cs | 32 ++-- .../WebSockets/Internal/SystemWebSocket.cs | 36 ++--- src/EmbedIO/WebSockets/Internal/WebSocket.cs | 36 ++--- .../WebSockets/Internal/WebSocketFrame.cs | 54 +++---- .../Internal/WebSocketFrameStream.cs | 2 +- src/EmbedIO/WebSockets/WebSocketException.cs | 44 ++---- src/EmbedIO/WebSockets/WebSocketModule.cs | 4 +- test/EmbedIO.Tests/ActionModuleTest.cs | 80 ++++------ .../BasicAuthenticationModuleTest.cs | 2 +- test/EmbedIO.Tests/EmbedIO.Tests.csproj | 5 +- test/EmbedIO.Tests/FluentTest.cs | 2 +- test/EmbedIO.Tests/HttpsTest.cs | 20 +-- test/EmbedIO.Tests/IPv6Test.cs | 12 +- test/EmbedIO.Tests/IWebServerTest.cs | 52 +++--- .../Issues/Issue318_StartupDeadlock.cs | 12 +- ...ssue352_FileSystemProviderEscapedString.cs | 8 +- .../Issues/Issue355_ContentResponseLength.cs | 52 +++--- test/EmbedIO.Tests/LocalSessionManagerTest.cs | 18 +-- .../EmbedIO.Tests/ResourceFileProviderTest.cs | 2 +- test/EmbedIO.Tests/StaticFilesModuleTest.cs | 108 ++++++------- test/EmbedIO.Tests/WebServerTest.cs | 120 +++++++------- test/EmbedIO.Tests/WebSocketModuleTest.cs | 20 ++- 103 files changed, 795 insertions(+), 1066 deletions(-) diff --git a/.github/workflows/netcore.yml b/.github/workflows/netcore.yml index 104e1237b..dfe410dc8 100644 --- a/.github/workflows/netcore.yml +++ b/.github/workflows/netcore.yml @@ -15,6 +15,6 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 2.2.108 - - name: Build with dotnet + dotnet-version: 3.0.100 + - name: Test with dotnet run: dotnet test ./test/EmbedIO.Tests/EmbedIO.Tests.csproj -c Release diff --git a/appveyor.yml b/appveyor.yml index 6cbd974f8..c0df7c401 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ version: '3.0.{build}' image: -- Visual Studio 2017 +- Visual Studio 2019 - Ubuntu notifications: - provider: Slack @@ -36,12 +36,12 @@ before_build: $command | netsh build_script: - cmd: msbuild /verbosity:quiet /p:Configuration=Release EmbedIO.sln -- cmd: | - cd src/EmbedIO.Forms.Sample/ - msbuild /t:restore EmbedIO.Forms.Sample.sln - msbuild /verbosity:quiet /p:Configuration=Release EmbedIO.Forms.Sample.sln - cd .. - cd .. +# - cmd: | +# cd src/EmbedIO.Forms.Sample/ +# msbuild /t:restore EmbedIO.Forms.Sample.sln +# msbuild /verbosity:quiet /p:Configuration=Release EmbedIO.Forms.Sample.sln +# cd .. +# cd .. - cmd: InspectCode --swea -o=inspectcode.xml -s=Error --verbosity=ERROR EmbedIO.sln - ps: | [xml]$xml = Get-Content inspectcode.xml diff --git a/src/EmbedIO.Samples/EmbedIO.Samples.csproj b/src/EmbedIO.Samples/EmbedIO.Samples.csproj index f88d570c2..55b73200f 100644 --- a/src/EmbedIO.Samples/EmbedIO.Samples.csproj +++ b/src/EmbedIO.Samples/EmbedIO.Samples.csproj @@ -1,11 +1,12 @@  - netcoreapp2.2 + netcoreapp3.0 EmbedIO.Samples Exe false - 7.3 + 8.0 + enable ..\..\StyleCop.Analyzers.ruleset diff --git a/src/EmbedIO.Testing/EmbedIO.Testing.csproj b/src/EmbedIO.Testing/EmbedIO.Testing.csproj index 1e0952674..cda852ca1 100644 --- a/src/EmbedIO.Testing/EmbedIO.Testing.csproj +++ b/src/EmbedIO.Testing/EmbedIO.Testing.csproj @@ -1,11 +1,12 @@  - 3.0.8 + 3.1.0 EmbedIO Web Server Testing netstandard2.0 - 7.3 + 8.0 true + enable diff --git a/src/EmbedIO.Testing/HttpResponseMessageExtensions.cs b/src/EmbedIO.Testing/HttpResponseMessageExtensions.cs index c80de3a63..769b7df43 100644 --- a/src/EmbedIO.Testing/HttpResponseMessageExtensions.cs +++ b/src/EmbedIO.Testing/HttpResponseMessageExtensions.cs @@ -14,13 +14,11 @@ public static class HttpResponseMessageExtensions /// /// The that will return the response. /// A whose result will be the response body as a string. - public static async Task ReceiveStringAsync(this Task @this) + public static async Task ReceiveStringAsync(this Task @this) { - using (var response = await @this.ConfigureAwait(false)) - { - if (response == null) return null; - return await response.Content.ReadAsStringAsync().ConfigureAwait(false); - } + using var response = await @this.ConfigureAwait(false); + if (response == null) return null; + return await response.Content.ReadAsStringAsync().ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/EmbedIO.Testing/Internal/TestContext.cs b/src/EmbedIO.Testing/Internal/TestContext.cs index 2c591607e..2c5bedc38 100644 --- a/src/EmbedIO.Testing/Internal/TestContext.cs +++ b/src/EmbedIO.Testing/Internal/TestContext.cs @@ -45,13 +45,13 @@ internal TestContext(IHttpRequest request) public RouteMatch Route { get; set; } - public string RequestedPath => Route.SubPath; + public string? RequestedPath => Route?.SubPath; public IHttpResponse Response => TestResponse; internal TestResponse TestResponse { get; } - public IPrincipal User { get; } + public IPrincipal? User { get; } public ISessionProxy Session { get; set; } diff --git a/src/EmbedIO.Testing/Internal/TestMessageHandler.cs b/src/EmbedIO.Testing/Internal/TestMessageHandler.cs index 16eed9a68..2aac22dbc 100644 --- a/src/EmbedIO.Testing/Internal/TestMessageHandler.cs +++ b/src/EmbedIO.Testing/Internal/TestMessageHandler.cs @@ -26,16 +26,21 @@ protected override async Task SendAsync(HttpRequestMessage if (!string.IsNullOrEmpty(cookiesFromContainer)) serverRequest.Headers.Add(HttpHeaderNames.Cookie, cookiesFromContainer); - var context = new TestContext(serverRequest); - context.CancellationToken = cancellationToken; - context.Route = RouteMatch.UnsafeFromRoot(UrlPath.Normalize(serverRequest.Url.AbsolutePath, false)); + var context = new TestContext(serverRequest) + { + CancellationToken = cancellationToken, + Route = RouteMatch.UnsafeFromRoot(UrlPath.Normalize(serverRequest.Url.AbsolutePath, false)) + + }; + await _handler.HandleContextAsync(context).ConfigureAwait(false); var serverResponse = context.TestResponse; var responseCookies = serverResponse.Headers.Get(HttpHeaderNames.SetCookie); if (!string.IsNullOrEmpty(responseCookies)) CookieContainer.SetCookies(serverRequest.Url, responseCookies); - var response = new HttpResponseMessage((HttpStatusCode) serverResponse.StatusCode) { + var response = new HttpResponseMessage((HttpStatusCode)serverResponse.StatusCode) + { RequestMessage = request, Version = serverResponse.ProtocolVersion, ReasonPhrase = serverResponse.StatusDescription, @@ -57,39 +62,29 @@ protected override async Task SendAsync(HttpRequestMessage return response; } - private static ResponseHeaderType GetResponseHeaderType(string name) - { - // Not all headers are created equal in System.Net.Http. - // If a header is a "content" header, adding it to a HttpResponseMessage directly - // will cause an InvalidOperationException. - // The list of known headers with their respective "header types" - // is conveniently hidden in an internal class of System.Net.Http, - // because nobody outside the .NET team will ever need them, right? - // https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs - // Here are the "content" headers, extracted on 2019-07-06: - switch (name) - { - // Content-Length is set automatically and shall not be touched - case HttpHeaderNames.ContentLength: - return ResponseHeaderType.None; - - // These headers belong to Content - case HttpHeaderNames.Allow: - case HttpHeaderNames.ContentDisposition: - case HttpHeaderNames.ContentEncoding: - case HttpHeaderNames.ContentLanguage: - case HttpHeaderNames.ContentLocation: - case HttpHeaderNames.ContentMD5: - case HttpHeaderNames.ContentRange: - case HttpHeaderNames.ContentType: - case HttpHeaderNames.Expires: - case HttpHeaderNames.LastModified: - return ResponseHeaderType.Content; - - // All other headers belong to the response - default: - return ResponseHeaderType.Response; - } - } + // Not all headers are created equal in System.Net.Http. + // If a header is a "content" header, adding it to a HttpResponseMessage directly + // will cause an InvalidOperationException. + // The list of known headers with their respective "header types" + // is conveniently hidden in an internal class of System.Net.Http, + // because nobody outside the .NET team will ever need them, right? + // https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs + // Here are the "content" headers, extracted on 2019-07-06: + private static ResponseHeaderType GetResponseHeaderType(string name) => name switch { + // Content-Length is set automatically and shall not be touched + HttpHeaderNames.ContentLength => ResponseHeaderType.None, + // These headers belong to Content + HttpHeaderNames.Allow => ResponseHeaderType.Content, + HttpHeaderNames.ContentDisposition => ResponseHeaderType.Content, + HttpHeaderNames.ContentEncoding => ResponseHeaderType.Content, + HttpHeaderNames.ContentLanguage => ResponseHeaderType.Content, + HttpHeaderNames.ContentLocation => ResponseHeaderType.Content, + HttpHeaderNames.ContentMD5 => ResponseHeaderType.Content, + HttpHeaderNames.ContentRange => ResponseHeaderType.Content, + HttpHeaderNames.ContentType => ResponseHeaderType.Content, + HttpHeaderNames.Expires => ResponseHeaderType.Content, + HttpHeaderNames.LastModified => ResponseHeaderType.Content, + _ => ResponseHeaderType.Response + }; } } \ No newline at end of file diff --git a/src/EmbedIO.Testing/Internal/TestRequest.cs b/src/EmbedIO.Testing/Internal/TestRequest.cs index ee14d7d38..1a66a2272 100644 --- a/src/EmbedIO.Testing/Internal/TestRequest.cs +++ b/src/EmbedIO.Testing/Internal/TestRequest.cs @@ -85,7 +85,7 @@ public TestRequest(HttpRequestMessage clientRequest) public bool HasEntityBody { get; } - public Stream InputStream => _content?.ReadAsStreamAsync().Await(); + public Stream? InputStream => _content?.ReadAsStreamAsync().Await(); public Encoding ContentEncoding { get; } @@ -95,19 +95,19 @@ public TestRequest(HttpRequestMessage clientRequest) public bool IsSecureConnection => false; - public string UserAgent { get; } + public string? UserAgent { get; } public bool IsWebSocketRequest => false; public IPEndPoint LocalEndPoint { get; } - public string ContentType { get; } + public string? ContentType { get; } public long ContentLength64 => 0; public bool IsAuthenticated => false; - public Uri UrlReferrer => null; + public Uri? UrlReferrer => null; private static HttpVerbs HttpMethodToVerb(HttpMethod method) { @@ -135,4 +135,4 @@ private static HttpVerbs HttpMethodToVerb(HttpMethod method) return HttpVerbs.Any; } } -} \ No newline at end of file +} diff --git a/src/EmbedIO.Testing/Internal/TestResponse.cs b/src/EmbedIO.Testing/Internal/TestResponse.cs index 65fb425af..e35ce4366 100644 --- a/src/EmbedIO.Testing/Internal/TestResponse.cs +++ b/src/EmbedIO.Testing/Internal/TestResponse.cs @@ -18,7 +18,7 @@ internal sealed class TestResponse : IHttpResponse, IDisposable public long ContentLength64 { get; set; } - public string ContentType { get; set; } + public string? ContentType { get; set; } public Stream OutputStream { get; } = new MemoryStream(); @@ -32,9 +32,9 @@ internal sealed class TestResponse : IHttpResponse, IDisposable public Version ProtocolVersion { get; } = HttpVersion.Version11; - public byte[] Body { get; private set; } + public byte[]? Body { get; private set; } - public string StatusDescription { get; set; } + public string? StatusDescription { get; set; } internal bool IsClosed { get; private set; } @@ -54,7 +54,7 @@ public void Dispose() GC.SuppressFinalize(this); } - public string GetBodyAsString() + public string? GetBodyAsString() { if (!(OutputStream is MemoryStream ms)) return null; diff --git a/src/EmbedIO.Testing/MockFileProvider.cs b/src/EmbedIO.Testing/MockFileProvider.cs index 2e8b43009..d2f4105a0 100644 --- a/src/EmbedIO.Testing/MockFileProvider.cs +++ b/src/EmbedIO.Testing/MockFileProvider.cs @@ -85,7 +85,7 @@ public void Start(CancellationToken cancellationToken) } /// - public MappedResourceInfo MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) + public MappedResourceInfo? MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) { if (string.IsNullOrEmpty(urlPath)) return null; @@ -99,9 +99,9 @@ public MappedResourceInfo MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeP } /// - public Stream OpenFile(string path) + public Stream? OpenFile(string path) { - var (name, entry) = FindEntry(path); + var (_, entry) = FindEntry(path); return entry is MockFile file ? new MemoryStream(file.Data, false) : null; } @@ -189,24 +189,12 @@ private byte[] CreateRandomData(int length) return default; } - private MappedResourceInfo GetResourceInfo(string path, string name, MockDirectoryEntry entry, IMimeTypeProvider mimeTypeProvider) - { - switch (entry) - { - case MockFile file: - return MappedResourceInfo.ForFile( - path, - name, - file.LastModifiedUtc, - file.Data.Length, - mimeTypeProvider.GetMimeType(Path.GetExtension(name))); - case MockDirectory directory: - return MappedResourceInfo.ForDirectory(string.Empty, name, _root.LastModifiedUtc); - default: - return null; - } - } - + private MappedResourceInfo? GetResourceInfo(string path, string name, MockDirectoryEntry entry, IMimeTypeProvider mimeTypeProvider) => entry switch { + MockFile file => MappedResourceInfo.ForFile(path, name, file.LastModifiedUtc, file.Data.Length, mimeTypeProvider.GetMimeType(Path.GetExtension(name))), + MockDirectory _ => MappedResourceInfo.ForDirectory(string.Empty, name, _root.LastModifiedUtc), + _ => null + }; + private static string AppendNameToPath(string path, string name) => string.IsNullOrEmpty(path) ? name : $"{path}/{name}"; } diff --git a/src/EmbedIO.Testing/StockResource.cs b/src/EmbedIO.Testing/StockResource.cs index a569c82a6..9f9fd14b4 100644 --- a/src/EmbedIO.Testing/StockResource.cs +++ b/src/EmbedIO.Testing/StockResource.cs @@ -59,7 +59,7 @@ public static bool Exists(string path) /// This parameter is passed uninitialized. /// if the specified resource /// has been loaded; otherwise, . - public static bool TryOpen(string path, out Stream stream) + public static bool TryOpen(string path, out Stream? stream) { stream = null; if (string.IsNullOrEmpty(path)) @@ -98,10 +98,8 @@ public static Stream Open(string path) /// is an empty string. public static long GetLength(string path) { - using (var stream = Open(path)) - { - return stream.Length; - } + using var stream = Open(path); + return stream.Length; } /// @@ -114,16 +112,14 @@ public static long GetLength(string path) /// is an empty string. public static byte[] GetBytes(string path) { - using (var stream = Open(path)) - { - var length = (int)stream.Length; - if (length == 0) - return Array.Empty(); - - var buffer = new byte[length]; - stream.Read(buffer, 0, length); - return buffer; - } + using var stream = Open(path); + var length = (int)stream.Length; + if (length == 0) + return Array.Empty(); + + var buffer = new byte[length]; + stream.Read(buffer, 0, length); + return buffer; } /// @@ -141,20 +137,18 @@ public static byte[] GetBytes(string path) /// is . /// is an empty string. /// is an empty string. - public static byte[] GetByteRange(string path, int start, int upperBound) + public static byte[]? GetByteRange(string path, int start, int upperBound) { - using (var stream = Open(path)) - { - var length = (int) stream.Length; - if (start >= length || upperBound < start || upperBound >= length) - return null; - - var rangeLength = upperBound - start + 1; - var buffer = new byte[rangeLength]; - stream.Position = start; - stream.Read(buffer, 0, rangeLength); - return buffer; - } + using var stream = Open(path); + var length = (int) stream.Length; + if (start >= length || upperBound < start || upperBound >= length) + return null; + + var rangeLength = upperBound - start + 1; + var buffer = new byte[rangeLength]; + stream.Position = start; + stream.Read(buffer, 0, rangeLength); + return buffer; } /// @@ -168,16 +162,14 @@ public static byte[] GetByteRange(string path, int start, int upperBound) /// is . /// is an empty string. /// is an empty string. - public static string GetText(string path, Encoding encoding = null) + public static string GetText(string path, Encoding? encoding = null) { - using (var stream = Open(path)) - using (var reader = new StreamReader(stream, encoding ?? Encoding.UTF8, false, WebServer.StreamCopyBufferSize, true)) - { - return reader.ReadToEnd(); - } + using var stream = Open(path); + using var reader = new StreamReader(stream, encoding ?? Encoding.UTF8, false, WebServer.StreamCopyBufferSize, true); + return reader.ReadToEnd(); } - private static string ConvertPath(string path) + private static string? ConvertPath(string path) { if (string.IsNullOrEmpty(path)) return null; diff --git a/src/EmbedIO.Testing/TestWebServer.cs b/src/EmbedIO.Testing/TestWebServer.cs index 45d2efb3f..ee3156df1 100644 --- a/src/EmbedIO.Testing/TestWebServer.cs +++ b/src/EmbedIO.Testing/TestWebServer.cs @@ -61,16 +61,12 @@ public static async Task UseAsync(Action configure, Func diff --git a/src/EmbedIO/Actions/RedirectModule.cs b/src/EmbedIO/Actions/RedirectModule.cs index 8e3caf6e3..5b2913fb4 100644 --- a/src/EmbedIO/Actions/RedirectModule.cs +++ b/src/EmbedIO/Actions/RedirectModule.cs @@ -11,7 +11,7 @@ namespace EmbedIO.Actions /// public class RedirectModule : WebModuleBase { - private readonly Func _shouldRedirect; + private readonly Func? _shouldRedirect; /// /// Initializes a new instance of the class @@ -53,12 +53,12 @@ public RedirectModule(string baseRoute, string redirectUrl, HttpStatusCode statu /// is not a redirection (3xx) status code. /// /// - public RedirectModule(string baseRoute, string redirectUrl, Func shouldRedirect, HttpStatusCode statusCode = HttpStatusCode.Found) + public RedirectModule(string baseRoute, string redirectUrl, Func? shouldRedirect, HttpStatusCode statusCode = HttpStatusCode.Found) : this(baseRoute, redirectUrl, shouldRedirect, statusCode, true) { } - private RedirectModule(string baseRoute, string redirectUrl, Func shouldRedirect, HttpStatusCode statusCode, bool useCallback) + private RedirectModule(string baseRoute, string redirectUrl, Func? shouldRedirect, HttpStatusCode statusCode, bool useCallback) : base(baseRoute) { RedirectUrl = Validate.Url(nameof(redirectUrl), redirectUrl); diff --git a/src/EmbedIO/Authentication/BasicAuthenticationModule.cs b/src/EmbedIO/Authentication/BasicAuthenticationModule.cs index 2e025c341..bf22b9868 100644 --- a/src/EmbedIO/Authentication/BasicAuthenticationModule.cs +++ b/src/EmbedIO/Authentication/BasicAuthenticationModule.cs @@ -21,7 +21,7 @@ public class BasicAuthenticationModule : BasicAuthenticationModuleBase /// the Realm property will be set equal to /// BaseRoute. /// - public BasicAuthenticationModule(string baseRoute, string realm = null) + public BasicAuthenticationModule(string baseRoute, string? realm = null) : base(baseRoute, realm) { } diff --git a/src/EmbedIO/Authentication/BasicAuthenticationModuleBase.cs b/src/EmbedIO/Authentication/BasicAuthenticationModuleBase.cs index 60f489aac..21b8bb60f 100644 --- a/src/EmbedIO/Authentication/BasicAuthenticationModuleBase.cs +++ b/src/EmbedIO/Authentication/BasicAuthenticationModuleBase.cs @@ -22,7 +22,7 @@ public abstract class BasicAuthenticationModuleBase : WebModuleBase /// the property will be set equal to /// BaseRoute. /// - protected BasicAuthenticationModuleBase(string baseRoute, string realm) + protected BasicAuthenticationModuleBase(string baseRoute, string? realm) : base(baseRoute) { Realm = string.IsNullOrEmpty(realm) ? BaseRoute : realm; diff --git a/src/EmbedIO/EmbedIO.csproj b/src/EmbedIO/EmbedIO.csproj index 02f04abd7..e17f9a857 100644 --- a/src/EmbedIO/EmbedIO.csproj +++ b/src/EmbedIO/EmbedIO.csproj @@ -10,7 +10,7 @@ EmbedIO EmbedIO ..\..\StyleCop.Analyzers.ruleset - 3.0.8 + 3.1.0 EmbedIO Unosquare LICENSE @@ -19,7 +19,8 @@ https://github.com/unosquare/embedio/ git webserver websocket webapi http - 7.3 + 8.0 + enable diff --git a/src/EmbedIO/ExceptionHandler.cs b/src/EmbedIO/ExceptionHandler.cs index ea10dd479..96de713cb 100644 --- a/src/EmbedIO/ExceptionHandler.cs +++ b/src/EmbedIO/ExceptionHandler.cs @@ -3,7 +3,6 @@ using System.Runtime.ExceptionServices; using System.Threading.Tasks; using System.Web; -using Swan; using Swan.Logging; namespace EmbedIO diff --git a/src/EmbedIO/Files/FileCache.Section.cs b/src/EmbedIO/Files/FileCache.Section.cs index 66497548a..b679a72e5 100644 --- a/src/EmbedIO/Files/FileCache.Section.cs +++ b/src/EmbedIO/Files/FileCache.Section.cs @@ -11,8 +11,8 @@ internal class Section private readonly object _syncRoot = new object(); private readonly Dictionary _items = new Dictionary(StringComparer.Ordinal); private long _totalSize; - private string _oldestKey; - private string _newestKey; + private string? _oldestKey; + private string? _newestKey; public void Clear() { diff --git a/src/EmbedIO/Files/FileCache.cs b/src/EmbedIO/Files/FileCache.cs index 1cfbf78d8..accf545e2 100644 --- a/src/EmbedIO/Files/FileCache.cs +++ b/src/EmbedIO/Files/FileCache.cs @@ -31,13 +31,13 @@ public sealed partial class FileCache private static readonly Stopwatch TimeBase = Stopwatch.StartNew(); private static readonly object DefaultSyncRoot = new object(); - private static FileCache _defaultInstance; + private static FileCache? _defaultInstance; private readonly ConcurrentDictionary _sections = new ConcurrentDictionary(StringComparer.Ordinal); private int _sectionCount; // Because ConcurrentDictionary<,>.Count is locking. private int _maxSizeKb = DefaultMaxSizeKb; private int _maxFileSizeKb = DefaultMaxFileSizeKb; - private PeriodicTask _cleaner; + private PeriodicTask? _cleaner; /// /// Gets the default instance used by . @@ -106,7 +106,7 @@ internal void RemoveSection(string name) if (Interlocked.Decrement(ref _sectionCount) == 0) { - _cleaner.Dispose(); + _cleaner?.Dispose(); _cleaner = null; } } @@ -156,9 +156,9 @@ private async Task CheckMaxSize(CancellationToken cancellationToken) private long ComputeTotalSize() => _sections.Sum(pair => pair.Value.GetTotalSize()); - private Section GetSectionWithLeastRecentItem() + private Section? GetSectionWithLeastRecentItem() { - Section result = null; + Section? result = null; var earliestTime = long.MaxValue; foreach (var pair in _sections) { diff --git a/src/EmbedIO/Files/FileModule.cs b/src/EmbedIO/Files/FileModule.cs index 4c9d371ab..58dc575e6 100644 --- a/src/EmbedIO/Files/FileModule.cs +++ b/src/EmbedIO/Files/FileModule.cs @@ -23,18 +23,18 @@ public class FileModule : WebModuleBase, IDisposable, IMimeTypeCustomizer private readonly string _cacheSectionName = UniqueIdGenerator.GetNext(); private readonly MimeTypeCustomizer _mimeTypeCustomizer = new MimeTypeCustomizer(); - private readonly ConcurrentDictionary _mappingCache; + private readonly ConcurrentDictionary? _mappingCache; private FileCache _cache = FileCache.Default; private bool _contentCaching = true; - private string _defaultDocument = DefaultDocumentName; - private string _defaultExtension; - private IDirectoryLister _directoryLister; + private string? _defaultDocument = DefaultDocumentName; + private string? _defaultExtension; + private IDirectoryLister? _directoryLister; private FileRequestHandlerCallback _onMappingFailed = FileRequestHandler.ThrowNotFound; private FileRequestHandlerCallback _onDirectoryNotListable = FileRequestHandler.ThrowUnauthorized; private FileRequestHandlerCallback _onMethodNotAllowed = FileRequestHandler.ThrowMethodNotAllowed; - private FileCache.Section _cacheSection; + private FileCache.Section? _cacheSection; /// /// Initializes a new instance of the class, @@ -110,7 +110,7 @@ public bool ContentCaching /// The default value for this property is the constant. /// /// The module's configuration is locked. - public string DefaultDocument + public string? DefaultDocument { get => _defaultDocument; set @@ -127,7 +127,7 @@ public string DefaultDocument /// The module's configuration is locked. /// This property is being set to a non-, /// non-empty string that does not start with a period (.). - public string DefaultExtension + public string? DefaultExtension { get => _defaultExtension; set @@ -156,7 +156,7 @@ public string DefaultExtension /// of directory listings. /// /// The module's configuration is locked. - public IDirectoryLister DirectoryLister + public IDirectoryLister? DirectoryLister { get => _directoryLister; set @@ -293,7 +293,7 @@ protected override void OnStart(CancellationToken cancellationToken) /// protected override async Task OnRequestAsync(IHttpContext context) { - MappedResourceInfo info; + MappedResourceInfo? info; var path = context.RequestedPath; @@ -371,7 +371,7 @@ private static void PreparePositiveResponse(IHttpResponse response, MappedResour // handling DefaultDocument and DefaultExtension. // Returns null if not found. // Directories mus be returned regardless of directory listing being enabled. - private MappedResourceInfo MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) + private MappedResourceInfo? MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) { var result = Provider.MapUrlPath(urlPath, mimeTypeProvider); @@ -532,8 +532,8 @@ private async Task HandleResource(IHttpContext context, MappedResourceInfo info, using (var memoryStream = new MemoryStream()) { using (var compressor = new CompressionStream(memoryStream, compressionMethod)) - using (var source = Provider.OpenFile(info.Path)) { + using var source = Provider.OpenFile(info.Path); await source.CopyToAsync(compressor, WebServer.StreamCopyBufferSize, context.CancellationToken) .ConfigureAwait(false); } @@ -610,11 +610,9 @@ await context.Response.OutputStream.WriteAsync(buffer, 0, read, context.Cancella } else { - using (var compressor = new CompressionStream(context.Response.OutputStream, compressionMethod)) - { - await source.CopyToAsync(compressor, WebServer.StreamCopyBufferSize, context.CancellationToken) - .ConfigureAwait(false); - } + using var compressor = new CompressionStream(context.Response.OutputStream, compressionMethod); + await source.CopyToAsync(compressor, WebServer.StreamCopyBufferSize, context.CancellationToken) + .ConfigureAwait(false); } } } @@ -627,23 +625,21 @@ await source.CopyToAsync(compressor, WebServer.StreamCopyBufferSize, context.Can MappedResourceInfo info, CompressionMethod compressionMethod) { - using (var memoryStream = new MemoryStream()) + using var memoryStream = new MemoryStream(); + long uncompressedLength; + using (var stream = new CompressionStream(memoryStream, compressionMethod)) { - long uncompressedLength; - using (var stream = new CompressionStream(memoryStream, compressionMethod)) - { - await DirectoryLister.ListDirectoryAsync( - info, - context.Request.Url.AbsolutePath, - Provider.GetDirectoryEntries(info.Path, context), - stream, - context.CancellationToken).ConfigureAwait(false); - - uncompressedLength = stream.UncompressedLength; - } - - return (memoryStream.ToArray(), uncompressedLength); + await DirectoryLister.ListDirectoryAsync( + info, + context.Request.Url.AbsolutePath, + Provider.GetDirectoryEntries(info.Path, context), + stream, + context.CancellationToken).ConfigureAwait(false); + + uncompressedLength = stream.UncompressedLength; } + + return (memoryStream.ToArray(), uncompressedLength); } } } \ No newline at end of file diff --git a/src/EmbedIO/Files/FileSystemProvider.cs b/src/EmbedIO/Files/FileSystemProvider.cs index d078100e6..2f221492d 100644 --- a/src/EmbedIO/Files/FileSystemProvider.cs +++ b/src/EmbedIO/Files/FileSystemProvider.cs @@ -13,7 +13,7 @@ namespace EmbedIO.Files /// public class FileSystemProvider : IDisposable, IFileProvider { - private readonly FileSystemWatcher _watcher; + private readonly FileSystemWatcher? _watcher; /// /// Initializes a new instance of the class. @@ -43,7 +43,7 @@ public FileSystemProvider(string fileSystemPath, bool isImmutable) } /// - public event Action ResourceChanged; + public event Action? ResourceChanged; /// /// Gets the file system path from which files are retrieved. @@ -73,7 +73,7 @@ public void Start(CancellationToken cancellationToken) } /// - public MappedResourceInfo MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) + public MappedResourceInfo? MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) { urlPath = urlPath.Substring(1); // Drop the initial slash string localPath; diff --git a/src/EmbedIO/Files/IFileProvider.cs b/src/EmbedIO/Files/IFileProvider.cs index 9ed5abdf8..048265cf8 100644 --- a/src/EmbedIO/Files/IFileProvider.cs +++ b/src/EmbedIO/Files/IFileProvider.cs @@ -37,7 +37,7 @@ public interface IFileProvider /// A provider-specific path identifying a file or directory, /// or if this instance cannot provide a resource associated /// to . - MappedResourceInfo MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider); + MappedResourceInfo? MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider); /// /// Opens a file for reading. diff --git a/src/EmbedIO/Files/Internal/FileCacheItem.cs b/src/EmbedIO/Files/Internal/FileCacheItem.cs index e416c4dd6..9ab06de00 100644 --- a/src/EmbedIO/Files/Internal/FileCacheItem.cs +++ b/src/EmbedIO/Files/Internal/FileCacheItem.cs @@ -10,8 +10,8 @@ internal sealed class FileCacheItem // inside the cache's dictionary. // Their purpose is to keep track of items // in order from least to most recently used. - internal string PreviousKey; - internal string NextKey; + internal string? PreviousKey; + internal string? NextKey; internal long LastUsedAt; #pragma warning restore SA1401 @@ -50,9 +50,9 @@ internal sealed class FileCacheItem // There are only 3 possible compression methods, // hence a dictionary (or two dictionaries) would be overkill. - private byte[] _uncompressedContent; - private byte[] _gzippedContent; - private byte[] _deflatedContent; + private byte[]? _uncompressedContent; + private byte[]? _gzippedContent; + private byte[]? _deflatedContent; internal FileCacheItem(FileCache.Section section, DateTime lastModifiedUtc, long length) { @@ -78,7 +78,7 @@ internal FileCacheItem(FileCache.Section section, DateTime lastModifiedUtc, long // It is NOT the length of the cache resource! public long SizeInCache { get; private set; } - public byte[] GetContent(CompressionMethod compressionMethod) + public byte[]? GetContent(CompressionMethod compressionMethod) { // If there are both entity tag and content, use them. switch (compressionMethod) @@ -95,7 +95,7 @@ public byte[] GetContent(CompressionMethod compressionMethod) } // Try to convert existing content, if any. - byte[] content; + byte[]? content; if (_uncompressedContent != null) { content = CompressionUtility.ConvertCompression(_uncompressedContent, CompressionMethod.None, compressionMethod); @@ -117,11 +117,11 @@ public byte[] GetContent(CompressionMethod compressionMethod) return SetContent(compressionMethod, content); } - public byte[] SetContent(CompressionMethod compressionMethod, byte[] content) + public byte[]? SetContent(CompressionMethod compressionMethod, byte[]? content) { // This is the bare minimum locking we need // to ensure we don't mess sizes up. - byte[] oldContent; + byte[]? oldContent; lock (this) { switch (compressionMethod) diff --git a/src/EmbedIO/Files/Internal/HtmlDirectoryLister.cs b/src/EmbedIO/Files/Internal/HtmlDirectoryLister.cs index 6d0262e1f..c7772b7df 100644 --- a/src/EmbedIO/Files/Internal/HtmlDirectoryLister.cs +++ b/src/EmbedIO/Files/Internal/HtmlDirectoryLister.cs @@ -37,39 +37,37 @@ public async Task ListDirectoryAsync( SelfCheck.Assert(info.IsDirectory, $"{nameof(HtmlDirectoryLister)}.{nameof(ListDirectoryAsync)} invoked with a file, not a directory."); var encodedPath = WebUtility.HtmlEncode(absoluteUrlPath); - using (var text = new StreamWriter(stream, Encoding.UTF8)) - { - text.Write("Index of "); - text.Write(encodedPath); - text.Write("

Index of "); - text.Write(encodedPath); - text.Write("


");
-
-                if (encodedPath.Length > 1)
-                    text.Write("../\n");
+            using var text = new StreamWriter(stream, Encoding.UTF8);
+            text.Write("Index of ");
+            text.Write(encodedPath);
+            text.Write("

Index of "); + text.Write(encodedPath); + text.Write("


");
 
-                entries = entries.ToArray();
+            if (encodedPath.Length > 1)
+                text.Write("../\n");
 
-                foreach (var directory in entries.Where(m => m.IsDirectory).OrderBy(e => e.Name))
-                {
-                    text.Write($"{WebUtility.HtmlEncode(directory.Name)}");
-                    text.Write(new string(' ', Math.Max(1, MaxEntryLength - directory.Name.Length + 1)));
-                    text.Write(HttpDate.Format(directory.LastModifiedUtc));
-                    text.Write('\n');
-                    await Task.Yield();
-                }
+            entries = entries.ToArray();
 
-                foreach (var file in entries.Where(m => m.IsFile).OrderBy(e => e.Name))
-                {
-                    text.Write($"{WebUtility.HtmlEncode(file.Name)}");
-                    text.Write(new string(' ', Math.Max(1, MaxEntryLength - file.Name.Length + 1)));
-                    text.Write(HttpDate.Format(file.LastModifiedUtc));
-                    text.Write($" {file.Length.ToString("#,###", CultureInfo.InvariantCulture),SizeIndent}\n");
-                    await Task.Yield();
-                }
+            foreach (var directory in entries.Where(m => m.IsDirectory).OrderBy(e => e.Name))
+            {
+                text.Write($"{WebUtility.HtmlEncode(directory.Name)}");
+                text.Write(new string(' ', Math.Max(1, MaxEntryLength - directory.Name.Length + 1)));
+                text.Write(HttpDate.Format(directory.LastModifiedUtc));
+                text.Write('\n');
+                await Task.Yield();
+            }
 
-                text.Write("

"); + foreach (var file in entries.Where(m => m.IsFile).OrderBy(e => e.Name)) + { + text.Write($"{WebUtility.HtmlEncode(file.Name)}"); + text.Write(new string(' ', Math.Max(1, MaxEntryLength - file.Name.Length + 1))); + text.Write(HttpDate.Format(file.LastModifiedUtc)); + text.Write($" {file.Length.ToString("#,###", CultureInfo.InvariantCulture),SizeIndent}\n"); + await Task.Yield(); } + + text.Write("

"); } } } \ No newline at end of file diff --git a/src/EmbedIO/Files/MappedResourceInfo.cs b/src/EmbedIO/Files/MappedResourceInfo.cs index 6ce57c3ee..267c845cb 100644 --- a/src/EmbedIO/Files/MappedResourceInfo.cs +++ b/src/EmbedIO/Files/MappedResourceInfo.cs @@ -7,7 +7,7 @@ namespace EmbedIO.Files ///
public sealed class MappedResourceInfo { - private MappedResourceInfo(string path, string name, DateTime lastModifiedUtc, long length, string contentType) + private MappedResourceInfo(string path, string name, DateTime lastModifiedUtc, long length, string? contentType) { Path = path; Name = name; @@ -51,7 +51,7 @@ private MappedResourceInfo(string path, string name, DateTime lastModifiedUtc, l /// If is , gets a MIME type describing the kind of contents of the file. /// If is , this property is always . ///
- public string ContentType { get; } + public string? ContentType { get; } /// /// Creates and returns a new instance of the class, diff --git a/src/EmbedIO/Files/ResourceFileProvider.cs b/src/EmbedIO/Files/ResourceFileProvider.cs index 8a4aab31b..21e850a03 100644 --- a/src/EmbedIO/Files/ResourceFileProvider.cs +++ b/src/EmbedIO/Files/ResourceFileProvider.cs @@ -55,20 +55,18 @@ public void Start(CancellationToken cancellationToken) } /// - public MappedResourceInfo MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) + public MappedResourceInfo? MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) { var resourceName = PathPrefix + urlPath.Replace('/', '.'); long size; try { - using (var stream = Assembly.GetManifestResourceStream(resourceName)) - { - if (stream == null || stream == Stream.Null) - return null; + using var stream = Assembly.GetManifestResourceStream(resourceName); + if (stream == null || stream == Stream.Null) + return null; - size = stream.Length; - } + size = stream.Length; } catch (FileNotFoundException) { diff --git a/src/EmbedIO/Files/ZipFileProvider.cs b/src/EmbedIO/Files/ZipFileProvider.cs index 759c9331d..d8a637039 100644 --- a/src/EmbedIO/Files/ZipFileProvider.cs +++ b/src/EmbedIO/Files/ZipFileProvider.cs @@ -67,7 +67,7 @@ public void Start(CancellationToken cancellationToken) } /// - public MappedResourceInfo MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) + public MappedResourceInfo? MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeProvider) { if (urlPath.Length == 1) return null; @@ -85,7 +85,7 @@ public MappedResourceInfo MapUrlPath(string urlPath, IMimeTypeProvider mimeTypeP } /// - public Stream OpenFile(string path) + public Stream? OpenFile(string path) => _zipArchive.GetEntry(path)?.Open(); /// diff --git a/src/EmbedIO/HttpContextExtensions-Requests.cs b/src/EmbedIO/HttpContextExtensions-Requests.cs index cce795a0f..3aabf7e3d 100644 --- a/src/EmbedIO/HttpContextExtensions-Requests.cs +++ b/src/EmbedIO/HttpContextExtensions-Requests.cs @@ -22,12 +22,10 @@ partial class HttpContextExtensions /// is . public static async Task GetRequestBodyAsByteArrayAsync(this IHttpContext @this) { - using (var buffer = new MemoryStream()) - using (var stream = @this.OpenRequestStream()) - { - await stream.CopyToAsync(buffer, WebServer.StreamCopyBufferSize, @this.CancellationToken).ConfigureAwait(false); - return buffer.ToArray(); - } + using var buffer = new MemoryStream(); + using var stream = @this.OpenRequestStream(); + await stream.CopyToAsync(buffer, WebServer.StreamCopyBufferSize, @this.CancellationToken).ConfigureAwait(false); + return buffer.ToArray(); } /// @@ -51,10 +49,8 @@ await GetRequestBodyAsByteArrayAsync(@this).ConfigureAwait(false), /// is . public static async Task GetRequestBodyAsStringAsync(this IHttpContext @this) { - using (var reader = @this.OpenRequestText()) - { - return await reader.ReadToEndAsync().ConfigureAwait(false); - } + using var reader = @this.OpenRequestText(); + return await reader.ReadToEndAsync().ConfigureAwait(false); } /// @@ -94,17 +90,15 @@ public static Task GetRequestDataAsync(this IHttpContext @this,Req /// This method may safely be called more than once for the same : /// it will return the same collection instead of trying to parse the request body again. /// - public static async Task GetRequestFormDataAsync(this IHttpContext @this) + public static async Task GetRequestFormDataAsync(this IHttpContext @this) { if (!@this.Items.TryGetValue(FormDataKey, out var previousResult)) { NameValueCollection result; try { - using (var reader = @this.OpenRequestText()) - { - result = UrlEncodedDataParser.Parse(await reader.ReadToEndAsync().ConfigureAwait(false), false); - } + using var reader = @this.OpenRequestText(); + result = UrlEncodedDataParser.Parse(await reader.ReadToEndAsync().ConfigureAwait(false), false); } catch (Exception e) { @@ -147,7 +141,7 @@ public static async Task GetRequestFormDataAsync(this IHttp /// This method may safely be called more than once for the same : /// it will return the same collection instead of trying to parse the request body again. /// - public static NameValueCollection GetRequestQueryData(this IHttpContext @this) + public static NameValueCollection? GetRequestQueryData(this IHttpContext @this) { if (!@this.Items.TryGetValue(QueryDataKey, out var previousResult)) { diff --git a/src/EmbedIO/HttpContextExtensions-ResponseStream.cs b/src/EmbedIO/HttpContextExtensions-ResponseStream.cs index efc244665..43b137719 100644 --- a/src/EmbedIO/HttpContextExtensions-ResponseStream.cs +++ b/src/EmbedIO/HttpContextExtensions-ResponseStream.cs @@ -28,15 +28,12 @@ public static Stream OpenResponseStream(this IHttpContext @this, bool buffered = @this.Request.TryNegotiateContentEncoding(preferCompression, out var compressionMethod, out var prepareResponse); prepareResponse(@this.Response); // The callback will throw HttpNotAcceptableException if negotiationSuccess is false. var stream = buffered ? new BufferingResponseStream(@this.Response) : @this.Response.OutputStream; - switch (compressionMethod) - { - case CompressionMethod.Gzip: - return new GZipStream(stream, CompressionMode.Compress); - case CompressionMethod.Deflate: - return new DeflateStream(stream, CompressionMode.Compress); - default: - return stream; - } + + return compressionMethod switch { + CompressionMethod.Gzip => new GZipStream(stream, CompressionMode.Compress), + CompressionMethod.Deflate => new DeflateStream(stream, CompressionMode.Compress), + _ => stream + }; } /// @@ -59,9 +56,9 @@ public static Stream OpenResponseStream(this IHttpContext @this, bool buffered = /// This writer MUST be disposed when finished writing. /// /// - public static TextWriter OpenResponseText(this IHttpContext @this, Encoding encoding = null, bool buffered = false, bool preferCompression = true) + public static TextWriter OpenResponseText(this IHttpContext @this, Encoding? encoding = null, bool buffered = false, bool preferCompression = true) { - encoding = encoding ?? Encoding.UTF8; + encoding ??= Encoding.UTF8; @this.Response.ContentEncoding = encoding; return new StreamWriter(OpenResponseStream(@this, buffered, preferCompression), encoding); } diff --git a/src/EmbedIO/HttpContextExtensions-Responses.cs b/src/EmbedIO/HttpContextExtensions-Responses.cs index e1079431a..aba3a7d3c 100644 --- a/src/EmbedIO/HttpContextExtensions-Responses.cs +++ b/src/EmbedIO/HttpContextExtensions-Responses.cs @@ -65,8 +65,8 @@ public static async Task SendStringAsync( @this.Response.ContentEncoding = encoding; } - using (var text = @this.OpenResponseText(encoding)) - await text.WriteAsync(content).ConfigureAwait(false); + using var text = @this.OpenResponseText(encoding); + await text.WriteAsync(content).ConfigureAwait(false); } /// @@ -96,7 +96,7 @@ public static Task SendStandardHtmlAsync(this IHttpContext @this, int statusCode public static Task SendStandardHtmlAsync( this IHttpContext @this, int statusCode, - Action writeAdditionalHtml) + Action? writeAdditionalHtml) { if (!HttpStatusDescription.TryGet(statusCode, out var statusDescription)) throw new ArgumentException("Status code has no standard description.", nameof(statusCode)); diff --git a/src/EmbedIO/HttpException-Shortcuts.cs b/src/EmbedIO/HttpException-Shortcuts.cs index 6d7853cdf..7c8c50b9b 100644 --- a/src/EmbedIO/HttpException-Shortcuts.cs +++ b/src/EmbedIO/HttpException-Shortcuts.cs @@ -15,7 +15,7 @@ partial class HttpException /// /// A newly-created . /// - public static HttpException InternalServerError(string message = null, object data = null) + public static HttpException InternalServerError(string? message = null, object? data = null) => new HttpException(HttpStatusCode.InternalServerError, message, data); /// @@ -28,7 +28,7 @@ public static HttpException InternalServerError(string message = null, object da /// /// A newly-created . /// - public static HttpException Unauthorized(string message = null, object data = null) + public static HttpException Unauthorized(string? message = null, object? data = null) => new HttpException(HttpStatusCode.Unauthorized, message, data); /// @@ -39,7 +39,7 @@ public static HttpException Unauthorized(string message = null, object data = nu /// A message to include in the response. /// The data object to include in the response. /// A newly-created . - public static HttpException Forbidden(string message = null, object data = null) + public static HttpException Forbidden(string? message = null, object? data = null) => new HttpException(HttpStatusCode.Forbidden, message, data); /// @@ -50,7 +50,7 @@ public static HttpException Forbidden(string message = null, object data = null) /// A message to include in the response. /// The data object to include in the response. /// A newly-created . - public static HttpException BadRequest(string message = null, object data = null) + public static HttpException BadRequest(string? message = null, object? data = null) => new HttpException(HttpStatusCode.BadRequest, message, data); /// @@ -61,7 +61,7 @@ public static HttpException BadRequest(string message = null, object data = null /// A message to include in the response. /// The data object to include in the response. /// A newly-created . - public static HttpException NotFound(string message = null, object data = null) + public static HttpException NotFound(string? message = null, object? data = null) => new HttpException(HttpStatusCode.NotFound, message, data); /// @@ -72,7 +72,7 @@ public static HttpException NotFound(string message = null, object data = null) /// A message to include in the response. /// The data object to include in the response. /// A newly-created . - public static HttpException MethodNotAllowed(string message = null, object data = null) + public static HttpException MethodNotAllowed(string? message = null, object? data = null) => new HttpException(HttpStatusCode.MethodNotAllowed, message, data); /// diff --git a/src/EmbedIO/HttpException.cs b/src/EmbedIO/HttpException.cs index c10bb2eb1..be3e635ad 100644 --- a/src/EmbedIO/HttpException.cs +++ b/src/EmbedIO/HttpException.cs @@ -37,7 +37,7 @@ public HttpException(HttpStatusCode statusCode) /// /// The status code to set on the response. /// A message to include in the response as plain text. - public HttpException(int statusCode, string message) + public HttpException(int statusCode, string? message) : base(message) { StatusCode = statusCode; @@ -50,7 +50,7 @@ public HttpException(int statusCode, string message) /// /// The status code to set on the response. /// A message to include in the response as plain text. - public HttpException(HttpStatusCode statusCode, string message) + public HttpException(HttpStatusCode statusCode, string? message) : this((int)statusCode, message) { } @@ -62,7 +62,7 @@ public HttpException(HttpStatusCode statusCode, string message) /// The status code to set on the response. /// A message to include in the response as plain text. /// The data object to include in the response. - public HttpException(int statusCode, string message, object data) + public HttpException(int statusCode, string? message, object? data) : this(statusCode, message) { DataObject = data; @@ -75,7 +75,7 @@ public HttpException(int statusCode, string message, object data) /// The status code to set on the response. /// A message to include in the response as plain text. /// The data object to include in the response. - public HttpException(HttpStatusCode statusCode, string message, object data) + public HttpException(HttpStatusCode statusCode, string? message, object? data) : this((int)statusCode, message, data) { } @@ -84,14 +84,14 @@ public HttpException(HttpStatusCode statusCode, string message, object data) public int StatusCode { get; } /// - public object DataObject { get; } + public object? DataObject { get; } /// - string IHttpException.Message => HttpExceptionMessage; + string? IHttpException.Message => HttpExceptionMessage; // This property is necessary because when an exception with a null Message is thrown // the CLR provides a standard message. We want null to remain null in IHttpException. - private string HttpExceptionMessage { get; } + private string? HttpExceptionMessage { get; } /// /// diff --git a/src/EmbedIO/HttpNotAcceptableException.cs b/src/EmbedIO/HttpNotAcceptableException.cs index 117bfb944..f84f47e46 100644 --- a/src/EmbedIO/HttpNotAcceptableException.cs +++ b/src/EmbedIO/HttpNotAcceptableException.cs @@ -29,7 +29,7 @@ public HttpNotAcceptableException() /// If this parameter is or the empty string, the response's Vary header /// is not set. /// - public HttpNotAcceptableException(string vary) + public HttpNotAcceptableException(string? vary) : base((int)HttpStatusCode.NotAcceptable) { Vary = string.IsNullOrEmpty(vary) ? null : vary; @@ -43,7 +43,7 @@ public HttpNotAcceptableException(string vary) /// If the empty string has been passed to the /// constructor, the value of this property is . /// - public string Vary { get; } + public string? Vary { get; } /// public override void PrepareResponse(IHttpContext context) diff --git a/src/EmbedIO/IHttpContextImpl.cs b/src/EmbedIO/IHttpContextImpl.cs index d6e347b9a..a883bb901 100644 --- a/src/EmbedIO/IHttpContextImpl.cs +++ b/src/EmbedIO/IHttpContextImpl.cs @@ -25,7 +25,7 @@ public interface IHttpContextImpl : IHttpContext /// /// Gets or sets the route matched by the requested URL path. /// - RouteMatch Route { get; set; } + new RouteMatch Route { get; set; } /// /// Gets or sets the session proxy associated with this context. @@ -71,7 +71,7 @@ public interface IHttpContextImpl : IHttpContext /// Task AcceptWebSocketAsync( IEnumerable requestedProtocols, - string acceptedProtocol, + string? acceptedProtocol, int receiveBufferSize, TimeSpan keepAliveInterval, CancellationToken cancellationToken); diff --git a/src/EmbedIO/IHttpResponse.cs b/src/EmbedIO/IHttpResponse.cs index 7d75cf5ff..48d8b2127 100644 --- a/src/EmbedIO/IHttpResponse.cs +++ b/src/EmbedIO/IHttpResponse.cs @@ -38,7 +38,7 @@ public interface IHttpResponse : IHttpMessage /// /// Gets or sets the content encoding. /// - Encoding ContentEncoding { get; set; } + Encoding? ContentEncoding { get; set; } /// /// Gets or sets a value indicating whether [keep alive]. diff --git a/src/EmbedIO/Internal/CompressionUtility.cs b/src/EmbedIO/Internal/CompressionUtility.cs index 47d11a3cf..58fe4ab95 100644 --- a/src/EmbedIO/Internal/CompressionUtility.cs +++ b/src/EmbedIO/Internal/CompressionUtility.cs @@ -5,7 +5,7 @@ namespace EmbedIO.Internal { internal static class CompressionUtility { - public static byte[] ConvertCompression(byte[] source, CompressionMethod sourceMethod, CompressionMethod targetMethod) + public static byte[]? ConvertCompression(byte[] source, CompressionMethod sourceMethod, CompressionMethod targetMethod) { if (source == null) return null; @@ -17,13 +17,13 @@ public static byte[] ConvertCompression(byte[] source, CompressionMethod sourceM { case CompressionMethod.Deflate: using (var sourceStream = new MemoryStream(source, false)) - using (var decompressionStream = new DeflateStream(sourceStream, CompressionMode.Decompress, true)) - using (var targetStream = new MemoryStream()) { + using var decompressionStream = new DeflateStream(sourceStream, CompressionMode.Decompress, true); + using var targetStream = new MemoryStream(); if (targetMethod == CompressionMethod.Gzip) { - using (var compressionStream = new GZipStream(targetStream, CompressionMode.Compress, true)) - decompressionStream.CopyTo(compressionStream); + using var compressionStream = new GZipStream(targetStream, CompressionMode.Compress, true); + decompressionStream.CopyTo(compressionStream); } else { @@ -35,13 +35,13 @@ public static byte[] ConvertCompression(byte[] source, CompressionMethod sourceM case CompressionMethod.Gzip: using (var sourceStream = new MemoryStream(source, false)) - using (var decompressionStream = new GZipStream(sourceStream, CompressionMode.Decompress, true)) - using (var targetStream = new MemoryStream()) { + using var decompressionStream = new GZipStream(sourceStream, CompressionMode.Decompress, true); + using var targetStream = new MemoryStream(); if (targetMethod == CompressionMethod.Deflate) { - using (var compressionStream = new DeflateStream(targetStream, CompressionMode.Compress, true)) - decompressionStream.CopyToAsync(compressionStream); + using var compressionStream = new DeflateStream(targetStream, CompressionMode.Compress, true); + decompressionStream.CopyToAsync(compressionStream); } else { @@ -53,8 +53,8 @@ public static byte[] ConvertCompression(byte[] source, CompressionMethod sourceM default: using (var sourceStream = new MemoryStream(source, false)) - using (var targetStream = new MemoryStream()) { + using var targetStream = new MemoryStream(); switch (targetMethod) { case CompressionMethod.Deflate: diff --git a/src/EmbedIO/Internal/UriUtility.cs b/src/EmbedIO/Internal/UriUtility.cs index 1f1aeeb56..d394cbccb 100644 --- a/src/EmbedIO/Internal/UriUtility.cs +++ b/src/EmbedIO/Internal/UriUtility.cs @@ -53,7 +53,7 @@ public static Uri StringToUri(string str) return result; } - public static Uri StringToAbsoluteUri(string str) + public static Uri? StringToAbsoluteUri(string str) { if (!CanBeAbsoluteUrl(str)) return null; diff --git a/src/EmbedIO/Net/CookieList.cs b/src/EmbedIO/Net/CookieList.cs index 769905175..75bf4a41d 100644 --- a/src/EmbedIO/Net/CookieList.cs +++ b/src/EmbedIO/Net/CookieList.cs @@ -24,7 +24,7 @@ public sealed class CookieList : List, ICookieCollection public bool IsSynchronized => false; /// - public Cookie this[string name] + public Cookie? this[string name] { get { @@ -51,7 +51,7 @@ public static CookieList Parse(string headerValue) { var cookies = new CookieList(); - Cookie cookie = null; + Cookie? cookie = null; var pairs = SplitCookieHeaderValue(headerValue); for (var i = 0; i < pairs.Length; i++) @@ -174,7 +174,7 @@ public void CopyTo(Array array, int index) ((IList) this).CopyTo(array, index); } - private static string GetValue(string nameAndValue, bool unquote = false) + private static string? GetValue(string nameAndValue, bool unquote = false) { var idx = nameAndValue.IndexOf('='); diff --git a/src/EmbedIO/Net/HttpListener.cs b/src/EmbedIO/Net/HttpListener.cs index 4089114ff..0fd0257fa 100644 --- a/src/EmbedIO/Net/HttpListener.cs +++ b/src/EmbedIO/Net/HttpListener.cs @@ -27,7 +27,7 @@ public sealed class HttpListener : IHttpListener /// Initializes a new instance of the class. /// /// The certificate. - public HttpListener(X509Certificate certificate =null) + public HttpListener(X509Certificate? certificate = null) { Certificate = certificate; @@ -54,7 +54,7 @@ public HttpListener(X509Certificate certificate =null) /// /// The certificate. /// - internal X509Certificate Certificate { get; } + internal X509Certificate? Certificate { get; } /// public void Start() diff --git a/src/EmbedIO/Net/Internal/EndPointListener.cs b/src/EmbedIO/Net/Internal/EndPointListener.cs index 8601d8b49..4f4bbec8d 100644 --- a/src/EmbedIO/Net/Internal/EndPointListener.cs +++ b/src/EmbedIO/Net/Internal/EndPointListener.cs @@ -13,8 +13,8 @@ internal sealed class EndPointListener private readonly IPEndPoint _endpoint; private readonly Socket _sock; private Dictionary _prefixes; - private List _unhandled; // unhandled; host = '*' - private List _all; // all; host = '+ + private List? _unhandled; // unhandled; host = '*' + private List? _all; // all; host = '+ public EndPointListener(HttpListener listener, IPAddress address, int port, bool secure) { @@ -30,7 +30,7 @@ public EndPointListener(HttpListener listener, IPAddress address, int port, bool _sock.Listen(500); var args = new SocketAsyncEventArgs { UserToken = this }; args.Completed += OnAccept; - Socket dummy = null; + Socket? dummy = null; Accept(_sock, args, ref dummy); _prefixes = new Dictionary(); _unregistered = new Dictionary(); @@ -79,7 +79,7 @@ public void Close() public void AddPrefix(ListenerPrefix prefix, HttpListener listener) { - List current; + List? current; List future; if (prefix.Host == "*") @@ -132,7 +132,7 @@ public void AddPrefix(ListenerPrefix prefix, HttpListener listener) public void RemovePrefix(ListenerPrefix prefix, HttpListener listener) { - List current; + List? current; List future; if (prefix.Host == "*") @@ -189,7 +189,7 @@ internal void RemoveConnection(HttpConnection conn) } } - private static void Accept(Socket socket, SocketAsyncEventArgs e, ref Socket accepted) + private static void Accept(Socket socket, SocketAsyncEventArgs e, ref Socket? accepted) { e.AcceptSocket = null; bool asyn; @@ -222,7 +222,7 @@ private static void Accept(Socket socket, SocketAsyncEventArgs e, ref Socket acc private static void ProcessAccept(SocketAsyncEventArgs args) { - Socket accepted = null; + Socket? accepted = null; if (args.SocketError == SocketError.Success) accepted = args.AcceptSocket; @@ -253,18 +253,18 @@ private static void ProcessAccept(SocketAsyncEventArgs args) epl._unregistered[conn] = conn; } - var waitTask = conn.BeginReadRequest(); + _ = conn.BeginReadRequest(); } private static void OnAccept(object sender, SocketAsyncEventArgs e) => ProcessAccept(e); - private static HttpListener MatchFromList(string path, List list, out ListenerPrefix prefix) + private static HttpListener? MatchFromList(string path, List? list, out ListenerPrefix? prefix) { prefix = null; if (list == null) return null; - HttpListener bestMatch = null; + HttpListener? bestMatch = null; var bestLength = -1; foreach (var p in list) @@ -309,7 +309,7 @@ private static bool RemoveSpecial(IList coll, ListenerPrefix pre return false; } - private HttpListener SearchListener(Uri uri, out ListenerPrefix prefix) + private HttpListener? SearchListener(Uri uri, out ListenerPrefix? prefix) { prefix = null; if (uri == null) @@ -320,7 +320,7 @@ private HttpListener SearchListener(Uri uri, out ListenerPrefix prefix) var path = WebUtility.UrlDecode(uri.AbsolutePath); var pathSlash = path[path.Length - 1] == '/' ? path : path + "/"; - HttpListener bestMatch = null; + HttpListener? bestMatch = null; var bestLength = -1; if (!string.IsNullOrEmpty(host)) diff --git a/src/EmbedIO/Net/Internal/HttpConnection.cs b/src/EmbedIO/Net/Internal/HttpConnection.cs index 2ca1e00cf..acc277907 100644 --- a/src/EmbedIO/Net/Internal/HttpConnection.cs +++ b/src/EmbedIO/Net/Internal/HttpConnection.cs @@ -16,16 +16,16 @@ internal sealed partial class HttpConnection : IDisposable private readonly Timer _timer; private readonly EndPointListener _epl; - private Socket _sock; - private MemoryStream _ms; - private byte[] _buffer; - private HttpListenerContext _context; - private StringBuilder _currentLine; - private RequestStream _iStream; - private ResponseStream _oStream; + private Socket? _sock; + private MemoryStream? _ms; + private byte[]? _buffer; + private HttpListenerContext? _context; + private StringBuilder? _currentLine; + private RequestStream? _iStream; + private ResponseStream? _oStream; private bool _contextBound; private int _sTimeout = 90000; // 90k ms for first request, 15k ms from then on - private HttpListener _lastListener; + private HttpListener? _lastListener; private InputState _inputState = InputState.RequestLine; private LineState _lineState = LineState.None; private int _position; @@ -77,9 +77,9 @@ public HttpConnection(Socket sock, EndPointListener epl, X509Certificate cert) public bool IsSecure { get; } - public ListenerPrefix Prefix { get; set; } + public ListenerPrefix? Prefix { get; set; } - internal X509Certificate2 ClientCertificate { get; } + internal X509Certificate2? ClientCertificate { get; } public void Dispose() { @@ -122,9 +122,7 @@ public RequestStream GetRequestStream(long contentLength) return _iStream; } - public ResponseStream GetResponseStream() => _oStream ?? - (_oStream = - new ResponseStream(Stream, _context.HttpListenerResponse, _context.Listener?.IgnoreWriteExceptions ?? true)); + public ResponseStream GetResponseStream() => _oStream ??= new ResponseStream(Stream, _context.HttpListenerResponse, _context.Listener?.IgnoreWriteExceptions ?? true); internal void ForceClose() => Close(true); @@ -277,7 +275,7 @@ private bool ProcessInput(MemoryStream ms) if (_position >= len) break; - string line; + string? line; try { line = ReadLine(buffer, _position, len - _position, out used); @@ -329,7 +327,7 @@ private bool ProcessInput(MemoryStream ms) return false; } - private string ReadLine(byte[] buffer, int offset, int len, out int used) + private string? ReadLine(byte[] buffer, int offset, int len, out int used) { if (_currentLine == null) _currentLine = new StringBuilder(128); diff --git a/src/EmbedIO/Net/Internal/HttpListenerContext.cs b/src/EmbedIO/Net/Internal/HttpListenerContext.cs index ee37a2fde..c5165e288 100644 --- a/src/EmbedIO/Net/Internal/HttpListenerContext.cs +++ b/src/EmbedIO/Net/Internal/HttpListenerContext.cs @@ -50,15 +50,15 @@ internal HttpListenerContext(HttpConnection cnc) public IHttpRequest Request { get; } - public RouteMatch Route { get; set; } + public RouteMatch? Route { get; set; } - public string RequestedPath => Route.SubPath; + public string? RequestedPath => Route?.SubPath; public IHttpResponse Response { get; } - public IPrincipal User { get; } + public IPrincipal? User { get; } - public ISessionProxy Session { get; set; } + public ISessionProxy? Session { get; set; } public bool SupportCompressedRequests { get; set; } @@ -68,13 +68,13 @@ internal HttpListenerContext(HttpConnection cnc) public MimeTypeProviderStack MimeTypeProviders { get; } = new MimeTypeProviderStack(); - internal HttpListenerRequest HttpListenerRequest => Request as HttpListenerRequest; + internal HttpListenerRequest? HttpListenerRequest => Request as HttpListenerRequest; - internal HttpListenerResponse HttpListenerResponse => Response as HttpListenerResponse; + internal HttpListenerResponse? HttpListenerResponse => Response as HttpListenerResponse; - internal HttpListener Listener { get; set; } + internal HttpListener? Listener { get; set; } - internal string ErrorMessage { get; set; } + internal string? ErrorMessage { get; set; } internal bool HaveError => ErrorMessage != null; diff --git a/src/EmbedIO/Net/Internal/HttpListenerRequest.cs b/src/EmbedIO/Net/Internal/HttpListenerRequest.cs index cae3fd9d8..c3fd9bdd8 100644 --- a/src/EmbedIO/Net/Internal/HttpListenerRequest.cs +++ b/src/EmbedIO/Net/Internal/HttpListenerRequest.cs @@ -20,14 +20,14 @@ internal sealed partial class HttpListenerRequest : IHttpRequest private static readonly char[] Separators = { ' ' }; private readonly HttpListenerContext _context; - private Encoding _contentEncoding; - private CookieList _cookies; - private Stream _inputStream; - private Uri _url; + private Encoding? _contentEncoding; + private CookieList? _cookies; + private Stream? _inputStream; + private Uri? _url; private bool _kaSet; private bool _keepAlive; - private GccDelegate _gccDelegate; + private GccDelegate? _gccDelegate; internal HttpListenerRequest(HttpListenerContext context) { @@ -42,7 +42,7 @@ internal HttpListenerRequest(HttpListenerContext context) /// /// The accept types. /// - public string[] AcceptTypes { get; private set; } + public string[]? AcceptTypes { get; private set; } /// public Encoding ContentEncoding @@ -90,7 +90,7 @@ public Encoding ContentEncoding public string ContentType => Headers[HttpHeaderNames.ContentType]; /// - public ICookieCollection Cookies => _cookies ?? (_cookies = new CookieList()); + public ICookieCollection Cookies => _cookies ??= new CookieList(); /// public bool HasEntityBody => ContentLength64 > 0; @@ -99,15 +99,13 @@ public Encoding ContentEncoding public NameValueCollection Headers { get; } /// - public string HttpMethod { get; private set; } + public string? HttpMethod { get; private set; } /// public HttpVerbs HttpVerb { get; private set; } /// - public Stream InputStream => _inputStream ?? - (_inputStream = - ContentLength64 > 0 ? _context.Connection.GetRequestStream(ContentLength64) : Stream.Null); + public Stream InputStream => _inputStream ??= ContentLength64 > 0 ? _context.Connection.GetRequestStream(ContentLength64) : Stream.Null; /// public bool IsAuthenticated => false; @@ -159,7 +157,7 @@ public bool KeepAlive public Version ProtocolVersion { get; private set; } /// - public NameValueCollection QueryString { get; private set; } + public NameValueCollection? QueryString { get; private set; } /// public string RawUrl { get; private set; } @@ -168,7 +166,7 @@ public bool KeepAlive public IPEndPoint RemoteEndPoint => _context.Connection.RemoteEndPoint; /// - public Uri Url => _url; + public Uri? Url => _url; /// public Uri UrlReferrer { get; private set; } @@ -195,11 +193,12 @@ public bool IsWebSocketRequest /// The request callback. /// The state. /// An async result. - public IAsyncResult BeginGetClientCertificate(AsyncCallback requestCallback, object state) + public IAsyncResult? BeginGetClientCertificate(AsyncCallback requestCallback, object state) { if (_gccDelegate == null) _gccDelegate = GetClientCertificate; - return _gccDelegate.BeginInvoke(requestCallback, state); + + return _gccDelegate?.BeginInvoke(requestCallback, state); } /// @@ -224,7 +223,7 @@ public X509Certificate2 EndGetClientCertificate(IAsyncResult asyncResult) /// Gets the client certificate. /// /// The client certificate. - public X509Certificate2 GetClientCertificate() => _context.Connection.ClientCertificate; + public X509Certificate2? GetClientCertificate() => _context.Connection.ClientCertificate; internal void SetRequestLine(string req) { @@ -400,7 +399,7 @@ private static Encoding GetEncoding(string contentType) => contentType .Select(part => Encoding.GetEncoding(GetValue(part))) .FirstOrDefault(); - private static string GetValue(string nameAndValue) + private static string? GetValue(string nameAndValue) { var idx = nameAndValue.IndexOf('='); @@ -414,7 +413,7 @@ private void ParseCookies(string val) var cookieStrings = val.SplitByAny(';', ',') .Where(x => !string.IsNullOrEmpty(x)); - Cookie current = null; + Cookie? current = null; var version = 0; foreach (var str in cookieStrings) diff --git a/src/EmbedIO/Net/Internal/HttpListenerResponse.cs b/src/EmbedIO/Net/Internal/HttpListenerResponse.cs index 6a8f10683..5d61977c1 100644 --- a/src/EmbedIO/Net/Internal/HttpListenerResponse.cs +++ b/src/EmbedIO/Net/Internal/HttpListenerResponse.cs @@ -17,10 +17,10 @@ internal sealed class HttpListenerResponse : IHttpResponse, IDisposable private const string CannotChangeHeaderWarning = "Cannot be changed after headers are sent."; private readonly HttpListenerContext _context; private bool _disposed; - private string _contentType; - private CookieList _cookies; + private string? _contentType; + private CookieList? _cookies; private bool _keepAlive = true; - private ResponseStream _outputStream; + private ResponseStream? _outputStream; private int _statusCode = 200; private bool _chunked; @@ -53,7 +53,7 @@ public long ContentLength64 } /// - public string ContentType + public string? ContentType { get => _contentType; @@ -93,8 +93,7 @@ public bool KeepAlive } /// - public Stream OutputStream => - _outputStream ?? (_outputStream = _context.Connection.GetResponseStream()); + public Stream OutputStream => _outputStream ??= _context.Connection.GetResponseStream(); /// public Version ProtocolVersion { get; } = HttpVersion.Version11; @@ -152,7 +151,7 @@ public int StatusCode internal CookieList CookieCollection { - get => _cookies ?? (_cookies = new CookieList()); + get => _cookies ??= new CookieList(); set => _cookies = value; } diff --git a/src/EmbedIO/Net/Internal/HttpListenerResponseHelper.cs b/src/EmbedIO/Net/Internal/HttpListenerResponseHelper.cs index 06953f4e5..944a1b6c4 100644 --- a/src/EmbedIO/Net/Internal/HttpListenerResponseHelper.cs +++ b/src/EmbedIO/Net/Internal/HttpListenerResponseHelper.cs @@ -2,105 +2,54 @@ { internal static class HttpListenerResponseHelper { - internal static string GetStatusDescription(int code) - { - switch (code) - { - case 100: - return "Continue"; - case 101: - return "Switching Protocols"; - case 102: - return "Processing"; - case 200: - return "OK"; - case 201: - return "Created"; - case 202: - return "Accepted"; - case 203: - return "Non-Authoritative Information"; - case 204: - return "No Content"; - case 205: - return "Reset Content"; - case 206: - return "Partial Content"; - case 207: - return "Multi-Status"; - case 300: - return "Multiple Choices"; - case 301: - return "Moved Permanently"; - case 302: - return "Found"; - case 303: - return "See Other"; - case 304: - return "Not Modified"; - case 305: - return "Use Proxy"; - case 307: - return "Temporary Redirect"; - case 400: - return "Bad Request"; - case 401: - return "Unauthorized"; - case 402: - return "Payment Required"; - case 403: - return "Forbidden"; - case 404: - return "Not Found"; - case 405: - return "Method Not Allowed"; - case 406: - return "Not Acceptable"; - case 407: - return "Proxy Authentication Required"; - case 408: - return "Request Timeout"; - case 409: - return "Conflict"; - case 410: - return "Gone"; - case 411: - return "Length Required"; - case 412: - return "Precondition Failed"; - case 413: - return "Request Entity Too Large"; - case 414: - return "Request-Uri Too Long"; - case 415: - return "Unsupported Media Type"; - case 416: - return "Requested Range Not Satisfiable"; - case 417: - return "Expectation Failed"; - case 422: - return "Unprocessable Entity"; - case 423: - return "Locked"; - case 424: - return "Failed Dependency"; - case 500: - return "Internal Server Error"; - case 501: - return "Not Implemented"; - case 502: - return "Bad Gateway"; - case 503: - return "Service Unavailable"; - case 504: - return "Gateway Timeout"; - case 505: - return "Http Version Not Supported"; - case 507: - return "Insufficient Storage"; - default: - return string.Empty; - } - } + internal static string GetStatusDescription(int code) => code switch { + 100 => "Continue", + 101 => "Switching Protocols", + 102 => "Processing", + 200 => "OK", + 201 => "Created", + 202 => "Accepted", + 203 => "Non-Authoritative Information", + 204 => "No Content", + 205 => "Reset Content", + 206 => "Partial Content", + 207 => "Multi-Status", + 300 => "Multiple Choices", + 301 => "Moved Permanently", + 302 => "Found", + 303 => "See Other", + 304 => "Not Modified", + 305 => "Use Proxy", + 307 => "Temporary Redirect", + 400 => "Bad Request", + 401 => "Unauthorized", + 402 => "Payment Required", + 403 => "Forbidden", + 404 => "Not Found", + 405 => "Method Not Allowed", + 406 => "Not Acceptable", + 407 => "Proxy Authentication Required", + 408 => "Request Timeout", + 409 => "Conflict", + 410 => "Gone", + 411 => "Length Required", + 412 => "Precondition Failed", + 413 => "Request Entity Too Large", + 414 => "Request-Uri Too Long", + 415 => "Unsupported Media Type", + 416 => "Requested Range Not Satisfiable", + 417 => "Expectation Failed", + 422 => "Unprocessable Entity", + 423 => "Locked", + 424 => "Failed Dependency", + 500 => "Internal Server Error", + 501 => "Not Implemented", + 502 => "Bad Gateway", + 503 => "Service Unavailable", + 504 => "Gateway Timeout", + 505 => "Http Version Not Supported", + 507 => "Insufficient Storage", + _ => string.Empty + }; } } \ No newline at end of file diff --git a/src/EmbedIO/Net/Internal/ListenerPrefix.cs b/src/EmbedIO/Net/Internal/ListenerPrefix.cs index 21e14014c..960603dd0 100644 --- a/src/EmbedIO/Net/Internal/ListenerPrefix.cs +++ b/src/EmbedIO/Net/Internal/ListenerPrefix.cs @@ -43,7 +43,7 @@ public ListenerPrefix(string uri) Path = Path.Substring(0, Path.Length - 1); } - public HttpListener Listener { get; set; } + public HttpListener? Listener { get; set; } public bool Secure { get; } diff --git a/src/EmbedIO/Net/Internal/ResponseStream.cs b/src/EmbedIO/Net/Internal/ResponseStream.cs index d8e368656..487271e64 100644 --- a/src/EmbedIO/Net/Internal/ResponseStream.cs +++ b/src/EmbedIO/Net/Internal/ResponseStream.cs @@ -123,7 +123,7 @@ protected override void Dispose(bool disposing) if (!disposing) return; - var ms = GetHeaders(); + using var ms = GetHeaders(); var chunked = _response.SendChunked; if (_stream.CanWrite) @@ -166,7 +166,7 @@ protected override void Dispose(bool disposing) private static byte[] GetChunkSizeBytes(int size, bool final) => Encoding.UTF8.GetBytes($"{size:x}\r\n{(final ? "\r\n" : string.Empty)}"); - private MemoryStream GetHeaders(bool closing = true) + private MemoryStream? GetHeaders(bool closing = true) { lock (_response.HeadersLock) return _response.HeadersSent ? null : _response.SendHeaders(closing); diff --git a/src/EmbedIO/Net/Internal/SystemHttpContext.cs b/src/EmbedIO/Net/Internal/SystemHttpContext.cs index 4fde4cedf..8c7195e13 100644 --- a/src/EmbedIO/Net/Internal/SystemHttpContext.cs +++ b/src/EmbedIO/Net/Internal/SystemHttpContext.cs @@ -49,15 +49,15 @@ public SystemHttpContext(System.Net.HttpListenerContext context) public IHttpRequest Request { get; } - public RouteMatch Route { get; set; } + public RouteMatch? Route { get; set; } - public string RequestedPath => Route.SubPath; + public string? RequestedPath => Route?.SubPath; public IHttpResponse Response { get; } public IPrincipal User { get; } - public ISessionProxy Session { get; set; } + public ISessionProxy? Session { get; set; } public bool SupportCompressedRequests { get; set; } diff --git a/src/EmbedIO/RequestHandler.cs b/src/EmbedIO/RequestHandler.cs index 0fd1bcd8e..4258b5336 100644 --- a/src/EmbedIO/RequestHandler.cs +++ b/src/EmbedIO/RequestHandler.cs @@ -23,7 +23,7 @@ public static class RequestHandler /// /// A message to include in the response. /// A . - public static RequestHandlerCallback ThrowUnauthorized(string message = null) + public static RequestHandlerCallback ThrowUnauthorized(string? message = null) => _ => throw HttpException.Unauthorized(message); /// @@ -31,7 +31,7 @@ public static RequestHandlerCallback ThrowUnauthorized(string message = null) /// /// A message to include in the response. /// A . - public static RequestHandlerCallback ThrowForbidden(string message = null) + public static RequestHandlerCallback ThrowForbidden(string? message = null) => _ => throw HttpException.Forbidden(message); /// @@ -39,7 +39,7 @@ public static RequestHandlerCallback ThrowForbidden(string message = null) /// /// A message to include in the response. /// A . - public static RequestHandlerCallback ThrowBadRequest(string message = null) + public static RequestHandlerCallback ThrowBadRequest(string? message = null) => _ => throw HttpException.BadRequest(message); /// @@ -47,7 +47,7 @@ public static RequestHandlerCallback ThrowBadRequest(string message = null) /// /// A message to include in the response. /// A . - public static RequestHandlerCallback ThrowNotFound(string message = null) + public static RequestHandlerCallback ThrowNotFound(string? message = null) => _ => throw HttpException.NotFound(message); /// @@ -55,7 +55,7 @@ public static RequestHandlerCallback ThrowNotFound(string message = null) /// /// A message to include in the response. /// A . - public static RequestHandlerCallback ThrowMethodNotAllowed(string message = null) - => _ => throw HttpException.MethodNotAllowed(); + public static RequestHandlerCallback ThrowMethodNotAllowed(string? message = null) + => _ => throw HttpException.MethodNotAllowed(message); } } \ No newline at end of file diff --git a/src/EmbedIO/ResponseSerializer.cs b/src/EmbedIO/ResponseSerializer.cs index 99d26db31..a494fc337 100644 --- a/src/EmbedIO/ResponseSerializer.cs +++ b/src/EmbedIO/ResponseSerializer.cs @@ -25,10 +25,8 @@ public static class ResponseSerializer public static async Task Json(IHttpContext context, object data) { context.Response.ContentType = MimeType.Json; - using (var text = context.OpenResponseText(Encoding.UTF8)) - { - await text.WriteAsync(Swan.Formatters.Json.Serialize(data)).ConfigureAwait(false); - } + using var text = context.OpenResponseText(Encoding.UTF8); + await text.WriteAsync(Swan.Formatters.Json.Serialize(data)).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/EmbedIO/ResponseSerializerCallback.cs b/src/EmbedIO/ResponseSerializerCallback.cs index 0d8277a66..f84cca1ff 100644 --- a/src/EmbedIO/ResponseSerializerCallback.cs +++ b/src/EmbedIO/ResponseSerializerCallback.cs @@ -8,5 +8,5 @@ namespace EmbedIO /// The HTTP context of the request. /// The data to serialize. /// A representing the ongoing operation. - public delegate Task ResponseSerializerCallback(IHttpContext context, object data); + public delegate Task ResponseSerializerCallback(IHttpContext context, object? data); } \ No newline at end of file diff --git a/src/EmbedIO/Routing/Route.cs b/src/EmbedIO/Routing/Route.cs index 9c229f301..51e156348 100644 --- a/src/EmbedIO/Routing/Route.cs +++ b/src/EmbedIO/Routing/Route.cs @@ -74,28 +74,17 @@ public static bool IsValidParameterName(string value) // Check the validity of a route by parsing it without storing the results. // Returns: ArgumentNullException, ArgumentException, null if OK - internal static Exception ValidateInternal(string argumentName, string value, bool isBaseRoute) - { - switch (ParseInternal(value, isBaseRoute, null)) - { - case ArgumentNullException _: - return new ArgumentNullException(argumentName); - - case FormatException formatException: - return new ArgumentException(formatException.Message, argumentName); - - case Exception exception: - return exception; - - default: - return null; // Unreachable, but the compiler doesn't know. - } - } + internal static Exception? ValidateInternal(string argumentName, string value, bool isBaseRoute) => ParseInternal(value, isBaseRoute, null) switch { + ArgumentNullException _ => new ArgumentNullException(argumentName), + FormatException formatException => new ArgumentException(formatException.Message, argumentName), + Exception exception => exception, + _ => null + }; // Validate and parse a route, constructing a Regex pattern. // setResult will be called at the end with the isBaseRoute flag, parameter names and the constructed pattern. // Returns: ArgumentNullException, FormatException, null if OK - internal static Exception ParseInternal(string route, bool isBaseRoute, Action, string> setResult) + internal static Exception? ParseInternal(string route, bool isBaseRoute, Action, string>? setResult) { if (route == null) return new ArgumentNullException(nameof(route)); diff --git a/src/EmbedIO/Routing/RouteMatch.cs b/src/EmbedIO/Routing/RouteMatch.cs index bd9fb6787..38b1f3de2 100644 --- a/src/EmbedIO/Routing/RouteMatch.cs +++ b/src/EmbedIO/Routing/RouteMatch.cs @@ -24,7 +24,7 @@ public sealed class RouteMatch : IReadOnlyList, IReadOnlyDictionary _values; - internal RouteMatch(string path, IReadOnlyList names, IReadOnlyList values, string subPath) + internal RouteMatch(string path, IReadOnlyList names, IReadOnlyList values, string? subPath) { Path = path; Names = names; @@ -41,7 +41,7 @@ internal RouteMatch(string path, IReadOnlyList names, IReadOnlyListFor a base route, gets the part of that follows the matched route; /// for a non-base route, this property is always . /// - public string SubPath { get; } + public string? SubPath { get; } /// /// Gets a list of the names of the route's parameters. @@ -119,7 +119,7 @@ public static RouteMatch UnsafeFromRoot(string urlPath) /// calling this method, using either /// or . /// - public static RouteMatch UnsafeFromBasePath(string baseUrlPath, string urlPath) + public static RouteMatch? UnsafeFromBasePath(string baseUrlPath, string urlPath) { var subPath = UrlPath.UnsafeStripPrefix(urlPath, baseUrlPath); return subPath == null ? null : new RouteMatch(urlPath, EmptyStringList, EmptyStringList, "/" + subPath); @@ -129,7 +129,7 @@ public static RouteMatch UnsafeFromBasePath(string baseUrlPath, string urlPath) public bool ContainsKey(string key) => Names.Any(n => n == key); /// - public bool TryGetValue(string key, out string value) + public bool TryGetValue(string key, out string? value) { var count = Names.Count; for (var i = 0; i < count; i++) diff --git a/src/EmbedIO/Routing/RouteMatcher.cs b/src/EmbedIO/Routing/RouteMatcher.cs index d6fec6634..96aa4008e 100644 --- a/src/EmbedIO/Routing/RouteMatcher.cs +++ b/src/EmbedIO/Routing/RouteMatcher.cs @@ -17,7 +17,7 @@ public sealed class RouteMatcher private readonly Regex _regex; - private RouteMatcher(bool isBaseRoute, string route, string pattern, IReadOnlyList parameterNames) + private RouteMatcher(bool isBaseRoute, string route, string? pattern, IReadOnlyList parameterNames) { IsBaseRoute = isBaseRoute; Route = route; @@ -55,7 +55,7 @@ private RouteMatcher(bool isBaseRoute, string route, string pattern, IReadOnlyLi /// is not a valid route. /// /// - public static RouteMatcher Parse(string route, bool isBaseRoute) + public static RouteMatcher? Parse(string route, bool isBaseRoute) { var exception = TryParseInternal(route, isBaseRoute, out var result); if (exception != null) @@ -78,7 +78,7 @@ public static RouteMatcher Parse(string route, bool isBaseRoute) /// if parsing was successful; otherwise, . /// /// - public static bool TryParse(string route, bool isBaseRoute, out RouteMatcher result) + public static bool TryParse(string route, bool isBaseRoute, out RouteMatcher? result) => TryParseInternal(route, isBaseRoute, out result) == null; /// @@ -101,7 +101,7 @@ public static void ClearCache() /// The URL path to match. /// If the match is successful, a object; /// otherwise, . - public RouteMatch Match(string path) + public RouteMatch? Match(string path) { if (path == null) return null; @@ -127,11 +127,11 @@ public RouteMatch Match(string path) IsBaseRoute ? "/" + path.Substring(match.Groups[0].Length) : null); } - private static Exception TryParseInternal(string route, bool isBaseRoute, out RouteMatcher result) + private static Exception? TryParseInternal(string route, bool isBaseRoute, out RouteMatcher? result) { lock (SyncRoot) { - string pattern = null; + string? pattern = null; var parameterNames = new List(); var exception = Routing.Route.ParseInternal(route, isBaseRoute, (_, n, p) => { parameterNames.AddRange(n); diff --git a/src/EmbedIO/Routing/RouteResolverBase`1.cs b/src/EmbedIO/Routing/RouteResolverBase`1.cs index 7c4d8c6df..1b88470a8 100644 --- a/src/EmbedIO/Routing/RouteResolverBase`1.cs +++ b/src/EmbedIO/Routing/RouteResolverBase`1.cs @@ -16,7 +16,7 @@ namespace EmbedIO.Routing /// public abstract class RouteResolverBase : ConfiguredObject { - private readonly RouteMatcher _matcher; + private readonly RouteMatcher? _matcher; private readonly List<(TData data, RouteHandlerCallback handler)> _dataHandlerPairs = new List<(TData data, RouteHandlerCallback handler)>(); diff --git a/src/EmbedIO/Routing/RouteVerbResolverCollection.cs b/src/EmbedIO/Routing/RouteVerbResolverCollection.cs index fafe734bc..802a85552 100644 --- a/src/EmbedIO/Routing/RouteVerbResolverCollection.cs +++ b/src/EmbedIO/Routing/RouteVerbResolverCollection.cs @@ -63,22 +63,13 @@ internal RouteVerbResolverCollection(string logSource) /// will count as one for each attribute. /// /// is . - public int AddFrom(object target) - { - switch (Validate.NotNull(nameof(target), target)) - { - case Type type: - return AddFrom(null, type); - case Assembly assembly: - return assembly.GetExportedTypes().Sum(t => AddFrom(null, t)); - case MethodInfo method: - return method.IsStatic ? Add(null, method) : 0; - case Delegate callback: - return Add(callback.Target, callback.Method); - default: - return AddFrom(target, target.GetType()); - } - } + public int AddFrom(object target) => Validate.NotNull(nameof(target), target) switch { + Type type => AddFrom(null, type), + Assembly assembly => assembly.GetExportedTypes().Sum(t => AddFrom(null, t)), + MethodInfo method => method.IsStatic ? Add(null, method) : 0, + Delegate callback => Add(callback.Target, callback.Method), + _ => AddFrom(target, target.GetType()) + }; /// protected override RouteVerbResolver CreateResolver(string route) => new RouteVerbResolver(route); @@ -107,7 +98,7 @@ private static bool IsHandlerCompatibleMethod(MethodInfo method, out bool isSync } // Call Add with all suitable methods of a Type, return sum of results. - private int AddFrom(object target, Type type) + private int AddFrom(object? target, Type type) => type.GetMethods(target == null ? BindingFlags.Public | BindingFlags.Static : BindingFlags.Public | BindingFlags.Instance) @@ -116,7 +107,7 @@ private int AddFrom(object target, Type type) && !method.ContainsGenericParameters) .Sum(m => Add(target, m)); - private int Add(object target, MethodInfo method) + private int Add(object? target, MethodInfo method) { if (!IsHandlerCompatibleMethod(method, out var isSynchronous)) return 0; diff --git a/src/EmbedIO/Sessions/ISession.cs b/src/EmbedIO/Sessions/ISession.cs index eb27cefb1..52226870f 100644 --- a/src/EmbedIO/Sessions/ISession.cs +++ b/src/EmbedIO/Sessions/ISession.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Swan.Collections; namespace EmbedIO.Sessions { diff --git a/src/EmbedIO/Sessions/LocalSessionManager.cs b/src/EmbedIO/Sessions/LocalSessionManager.cs index fc66ea44c..e420bb355 100644 --- a/src/EmbedIO/Sessions/LocalSessionManager.cs +++ b/src/EmbedIO/Sessions/LocalSessionManager.cs @@ -265,7 +265,7 @@ private bool IsSessionCookie(Cookie cookie) => cookie.Name.Equals(CookieName, StringComparison.OrdinalIgnoreCase) && !cookie.Expired; - private Cookie BuildSessionCookie(string id) + private Cookie BuildSessionCookie(string? id) { var cookie = new Cookie(CookieName, id, CookiePath) { diff --git a/src/EmbedIO/Sessions/SessionProxy.cs b/src/EmbedIO/Sessions/SessionProxy.cs index dcbe3f6e6..ed73799c2 100644 --- a/src/EmbedIO/Sessions/SessionProxy.cs +++ b/src/EmbedIO/Sessions/SessionProxy.cs @@ -17,7 +17,7 @@ public sealed class SessionProxy : ISessionProxy private readonly IHttpContext _context; private readonly ISessionManager _sessionManager; - private ISession _session; + private ISession? _session; private bool _onCloseRegistered; internal SessionProxy(IHttpContext context, ISessionManager sessionManager) diff --git a/src/EmbedIO/Utilities/NameValueCollectionExtensions.cs b/src/EmbedIO/Utilities/NameValueCollectionExtensions.cs index c309ac4b5..7596b88ba 100644 --- a/src/EmbedIO/Utilities/NameValueCollectionExtensions.cs +++ b/src/EmbedIO/Utilities/NameValueCollectionExtensions.cs @@ -19,21 +19,17 @@ public static class NameValueCollectionExtensions /// A associating the collection's keys /// with their values. /// is . - public static Dictionary ToDictionary(this NameValueCollection @this) + public static Dictionary ToDictionary(this NameValueCollection @this) => @this.Keys.Cast().ToDictionary(key => key, key => { var values = @this.GetValues(key); if (values == null) return null; - switch (values.Length) - { - case 0: - return null; - case 1: - return (object)values[0]; - default: - return (object)values; - } + return values.Length switch { + 0 => null, + 1 => (object) values[0], + _ => (object) values + }; }); /// @@ -104,7 +100,7 @@ public static bool Contains(this NameValueCollection @this, string name, string /// is . /// White space is trimmed from the start and end of each value before comparison. /// - public static bool Contains(this NameValueCollection @this, string name, string value, StringComparison comparisonType) + public static bool Contains(this NameValueCollection @this, string name, string? value, StringComparison comparisonType) { value = value?.Trim(); return @this[name]?.SplitByComma() diff --git a/src/EmbedIO/Utilities/QValueList.cs b/src/EmbedIO/Utilities/QValueList.cs index c19aaebe8..c6fc87544 100644 --- a/src/EmbedIO/Utilities/QValueList.cs +++ b/src/EmbedIO/Utilities/QValueList.cs @@ -133,7 +133,7 @@ public bool TryGetWeight(string value, out int weight) /// The values. /// The value preferred by the client, or /// if none of the provided is accepted. - public string FindPreferred(IEnumerable values) + public string? FindPreferred(IEnumerable values) => FindPreferredCore(values, out var result) >= 0 ? result : null; /// @@ -227,7 +227,7 @@ private static void ParseCore(string text, IDictionary values, out string result) + private int FindPreferredCore(IEnumerable values, out string? result) { values = Validate.NotNull(nameof(values), values); diff --git a/src/EmbedIO/Utilities/QValueListExtensions.cs b/src/EmbedIO/Utilities/QValueListExtensions.cs index 4b989428b..fb19cbebf 100644 --- a/src/EmbedIO/Utilities/QValueListExtensions.cs +++ b/src/EmbedIO/Utilities/QValueListExtensions.cs @@ -27,7 +27,7 @@ public static bool TryNegotiateContentEncoding( this QValueList @this, bool preferCompression, out CompressionMethod compressionMethod, - out string compressionMethodName) + out string? compressionMethodName) { if (@this.QValues.Count < 1) { diff --git a/src/EmbedIO/Utilities/UrlEncodedDataParser.cs b/src/EmbedIO/Utilities/UrlEncodedDataParser.cs index b6c962662..1963cca4d 100644 --- a/src/EmbedIO/Utilities/UrlEncodedDataParser.cs +++ b/src/EmbedIO/Utilities/UrlEncodedDataParser.cs @@ -44,7 +44,7 @@ public static NameValueCollection Parse(string source, bool groupFlags, bool mut return result; } - void AddKeyValuePair(string key, string value) + void AddKeyValuePair(string? key, string value) { if (key != null) { diff --git a/src/EmbedIO/Utilities/UrlPath.cs b/src/EmbedIO/Utilities/UrlPath.cs index 7dbcf583f..82d6905a9 100644 --- a/src/EmbedIO/Utilities/UrlPath.cs +++ b/src/EmbedIO/Utilities/UrlPath.cs @@ -201,7 +201,7 @@ public static bool UnsafeHasPrefix(string urlPath, string baseUrlPath) /// /// /// - public static string StripPrefix(string urlPath, string baseUrlPath) + public static string? StripPrefix(string urlPath, string baseUrlPath) => UnsafeStripPrefix( Validate.UrlPath(nameof(urlPath), urlPath, false), Validate.UrlPath(nameof(baseUrlPath), baseUrlPath, true)); @@ -230,7 +230,7 @@ public static string StripPrefix(string urlPath, string baseUrlPath) /// /// /// - public static string UnsafeStripPrefix(string urlPath, string baseUrlPath) + public static string? UnsafeStripPrefix(string urlPath, string baseUrlPath) { if (!UnsafeHasPrefix(urlPath, baseUrlPath)) return null; @@ -298,7 +298,7 @@ public static IEnumerable UnsafeSplit(string urlPath) } } - internal static Exception ValidateInternal(string argumentName, string value) + internal static Exception? ValidateInternal(string argumentName, string value) { if (value == null) return new ArgumentNullException(argumentName); diff --git a/src/EmbedIO/Utilities/Validate.cs b/src/EmbedIO/Utilities/Validate.cs index 01d0f1403..8fb57d71f 100644 --- a/src/EmbedIO/Utilities/Validate.cs +++ b/src/EmbedIO/Utilities/Validate.cs @@ -15,7 +15,7 @@ public static partial class Validate /// The value to validate. /// if not . /// is . - public static T NotNull(string argumentName, T value) + public static T NotNull(string argumentName, T? value) where T : class => value ?? throw new ArgumentNullException(argumentName); @@ -27,7 +27,7 @@ public static T NotNull(string argumentName, T value) /// if neither nor the empty string. /// is . /// is the empty string. - public static string NotNullOrEmpty(string argumentName, string value) + public static string NotNullOrEmpty(string argumentName, string? value) { if (value == null) throw new ArgumentNullException(argumentName); diff --git a/src/EmbedIO/WebApi/FormFieldAttribute.cs b/src/EmbedIO/WebApi/FormFieldAttribute.cs index 4f49928b6..09bf398bd 100644 --- a/src/EmbedIO/WebApi/FormFieldAttribute.cs +++ b/src/EmbedIO/WebApi/FormFieldAttribute.cs @@ -82,7 +82,7 @@ public FormFieldAttribute(string fieldName, bool badRequestIfMissing) { } - private FormFieldAttribute(bool badRequestIfMissing, string fieldName) + private FormFieldAttribute(bool badRequestIfMissing, string? fieldName) { BadRequestIfMissing = badRequestIfMissing; FieldName = fieldName; @@ -93,7 +93,7 @@ private FormFieldAttribute(bool badRequestIfMissing, string fieldName) /// or if the name of the parameter carrying this /// attribute is to be used as field name. /// - public string FieldName { get; } + public string? FieldName { get; } /// /// Gets or sets a value indicating whether to send a 400 Bad Request response @@ -108,7 +108,7 @@ private FormFieldAttribute(bool badRequestIfMissing, string fieldName) /// public bool BadRequestIfMissing { get; } - async Task IRequestDataAttribute.GetRequestDataAsync( + async Task IRequestDataAttribute.GetRequestDataAsync( WebApiController controller, string parameterName) { @@ -136,7 +136,7 @@ async Task IRequestDataAttribute.GetReques return data.GetValues(fieldName) ?? Array.Empty(); } - async Task IRequestDataAttribute.GetRequestDataAsync( + async Task IRequestDataAttribute.GetRequestDataAsync( WebApiController controller, Type type, string parameterName) diff --git a/src/EmbedIO/WebApi/IRequestDataAttribute`1.cs b/src/EmbedIO/WebApi/IRequestDataAttribute`1.cs index 9bc60e1fc..369e3fe9b 100644 --- a/src/EmbedIO/WebApi/IRequestDataAttribute`1.cs +++ b/src/EmbedIO/WebApi/IRequestDataAttribute`1.cs @@ -20,6 +20,6 @@ public interface IRequestDataAttribute /// The name of the parameter that has to receive the data. /// a whose result will be the data /// to pass as a parameter to a controller method. - Task GetRequestDataAsync(TController controller, Type type, string parameterName); + Task GetRequestDataAsync(TController controller, Type type, string parameterName); } } \ No newline at end of file diff --git a/src/EmbedIO/WebApi/QueryFieldAttribute.cs b/src/EmbedIO/WebApi/QueryFieldAttribute.cs index 670866805..efbd1cff4 100644 --- a/src/EmbedIO/WebApi/QueryFieldAttribute.cs +++ b/src/EmbedIO/WebApi/QueryFieldAttribute.cs @@ -82,7 +82,7 @@ public QueryFieldAttribute(string fieldName, bool badRequestIfMissing) { } - private QueryFieldAttribute(bool badRequestIfMissing, string fieldName) + private QueryFieldAttribute(bool badRequestIfMissing, string? fieldName) { BadRequestIfMissing = badRequestIfMissing; FieldName = fieldName; @@ -93,7 +93,7 @@ private QueryFieldAttribute(bool badRequestIfMissing, string fieldName) /// or if the name of the parameter carrying this /// attribute is to be used as field name. /// - public string FieldName { get; } + public string? FieldName { get; } /// /// Gets or sets a value indicating whether to send a 400 Bad Request response @@ -108,7 +108,7 @@ private QueryFieldAttribute(bool badRequestIfMissing, string fieldName) /// public bool BadRequestIfMissing { get; } - Task IRequestDataAttribute.GetRequestDataAsync( + Task IRequestDataAttribute.GetRequestDataAsync( WebApiController controller, string parameterName) { @@ -134,7 +134,7 @@ Task IRequestDataAttribute.GetRequestDataA return Task.FromResult(data.GetValues(fieldName) ?? Array.Empty()); } - Task IRequestDataAttribute.GetRequestDataAsync( + Task IRequestDataAttribute.GetRequestDataAsync( WebApiController controller, Type type, string parameterName) diff --git a/src/EmbedIO/WebApi/WebApiController.cs b/src/EmbedIO/WebApi/WebApiController.cs index 35eeb9231..309ffe316 100644 --- a/src/EmbedIO/WebApi/WebApiController.cs +++ b/src/EmbedIO/WebApi/WebApiController.cs @@ -28,7 +28,7 @@ protected WebApiController() /// Gets the resolved route. /// This property is automatically initialized upon controller creation. /// - public RouteMatch Route { get; internal set; } + public RouteMatch? Route { get; internal set; } /// /// Gets the used to cancel processing of the request. diff --git a/src/EmbedIO/WebApi/WebApiModuleBase.cs b/src/EmbedIO/WebApi/WebApiModuleBase.cs index d5b32ec5c..fa2dc7854 100644 --- a/src/EmbedIO/WebApi/WebApiModuleBase.cs +++ b/src/EmbedIO/WebApi/WebApiModuleBase.cs @@ -265,7 +265,7 @@ protected void RegisterControllerType(Type controllerType, Func(string parameterName, Task task) { var result = task.ConfigureAwait(false).GetAwaiter().GetResult(); - switch (result) - { - case null when typeof(T).IsValueType && Nullable.GetUnderlyingType(typeof(T)) == null: - throw new InvalidCastException($"Cannot cast null to {typeof(T).FullName} for parameter \"{parameterName}\"."); - case null: - return default; - case T castResult: - return castResult; - default: - throw new InvalidCastException($"Cannot cast {result.GetType().FullName} to {typeof(T).FullName} for parameter \"{parameterName}\"."); - } + + return result switch { + null when typeof(T).IsValueType && Nullable.GetUnderlyingType(typeof(T)) == null => throw new InvalidCastException($"Cannot cast null to {typeof(T).FullName} for parameter \"{parameterName}\"."), + null => default, + T castResult => castResult, + _ => throw new InvalidCastException($"Cannot cast {result.GetType().FullName} to {typeof(T).FullName} for parameter \"{parameterName}\".") + }; } private async Task SerializeResultAsync(IHttpContext context, Task task) @@ -590,7 +586,7 @@ private bool TryRegisterControllerTypeCore(Type controllerType, Expression facto return true; } - private static bool IsGenericTaskType(Type type, out Type resultType) + private static bool IsGenericTaskType(Type type, out Type? resultType) { resultType = null; diff --git a/src/EmbedIO/WebModuleBase.cs b/src/EmbedIO/WebModuleBase.cs index 1223f100a..41ae60e0f 100644 --- a/src/EmbedIO/WebModuleBase.cs +++ b/src/EmbedIO/WebModuleBase.cs @@ -26,9 +26,9 @@ namespace EmbedIO /// public abstract class WebModuleBase : ConfiguredObject, IWebModule { - private ExceptionHandlerCallback _onUnhandledException; - private HttpExceptionHandlerCallback _onHttpException; - private RouteMatcher _routeMatcher; + private ExceptionHandlerCallback? _onUnhandledException; + private HttpExceptionHandlerCallback? _onHttpException; + private RouteMatcher? _routeMatcher; /// /// Initializes a new instance of the class. @@ -50,7 +50,7 @@ protected WebModuleBase(string baseRoute) /// /// The module's configuration is locked. - public ExceptionHandlerCallback OnUnhandledException + public ExceptionHandlerCallback? OnUnhandledException { get => _onUnhandledException; set @@ -62,7 +62,7 @@ public ExceptionHandlerCallback OnUnhandledException /// /// The module's configuration is locked. - public HttpExceptionHandlerCallback OnHttpException + public HttpExceptionHandlerCallback? OnHttpException { get => _onHttpException; set @@ -86,7 +86,7 @@ public void Start(CancellationToken cancellationToken) } /// - public RouteMatch MatchUrlPath(string urlPath) => _routeMatcher.Match(urlPath); + public RouteMatch? MatchUrlPath(string urlPath) => _routeMatcher?.Match(urlPath); /// public async Task HandleRequestAsync(IHttpContext context) diff --git a/src/EmbedIO/WebModuleContainerExtensions-Files.cs b/src/EmbedIO/WebModuleContainerExtensions-Files.cs index a807f7bc4..c07ae1bab 100644 --- a/src/EmbedIO/WebModuleContainerExtensions-Files.cs +++ b/src/EmbedIO/WebModuleContainerExtensions-Files.cs @@ -2,7 +2,6 @@ using System.IO; using System.Reflection; using EmbedIO.Files; -using Swan; using Swan.Collections; namespace EmbedIO @@ -34,7 +33,7 @@ public static TContainer WithStaticFolder( string baseRoute, string fileSystemPath, bool isImmutable, - Action configure = null) + Action? configure = null) where TContainer : class, IWebModuleContainer => WithStaticFolder(@this, null, baseRoute, fileSystemPath, isImmutable, configure); @@ -62,11 +61,11 @@ public static TContainer WithStaticFolder( /// public static TContainer WithStaticFolder( this TContainer @this, - string name, + string? name, string baseRoute, string fileSystemPath, bool isImmutable, - Action configure = null) + Action? configure = null) where TContainer : class, IWebModuleContainer { var module = new FileModule(baseRoute, new FileSystemProvider(fileSystemPath, isImmutable)); @@ -96,7 +95,7 @@ public static TContainer WithEmbeddedResources( string baseRoute, Assembly assembly, string pathPrefix, - Action configure = null) + Action? configure = null) where TContainer : class, IWebModuleContainer => WithEmbeddedResources(@this, null, baseRoute, assembly, pathPrefix, configure); @@ -122,11 +121,11 @@ public static TContainer WithEmbeddedResources( /// public static TContainer WithEmbeddedResources( this TContainer @this, - string name, + string? name, string baseRoute, Assembly assembly, string pathPrefix, - Action configure = null) + Action? configure = null) where TContainer : class, IWebModuleContainer { var module = new FileModule(baseRoute, new ResourceFileProvider(assembly, pathPrefix)); @@ -152,7 +151,7 @@ public static TContainer WithZipFile( this TContainer @this, string baseRoute, string zipFilePath, - Action configure = null) + Action? configure = null) where TContainer : class, IWebModuleContainer => WithZipFile(@this, null, baseRoute, zipFilePath, configure); @@ -175,10 +174,10 @@ public static TContainer WithZipFile( /// public static TContainer WithZipFile( this TContainer @this, - string name, + string? name, string baseRoute, string zipFilePath, - Action configure = null) + Action? configure = null) where TContainer : class, IWebModuleContainer { var module = new FileModule(baseRoute, new ZipFileProvider(zipFilePath)); @@ -204,7 +203,7 @@ public static TContainer WithZipFileStream( this TContainer @this, string baseRoute, Stream zipFileStream, - Action configure = null) + Action? configure = null) where TContainer : class, IWebModuleContainer => WithZipFileStream(@this, null, baseRoute, zipFileStream, configure); @@ -227,10 +226,10 @@ public static TContainer WithZipFileStream( /// public static TContainer WithZipFileStream( this TContainer @this, - string name, + string? name, string baseRoute, Stream zipFileStream, - Action configure = null) + Action? configure = null) where TContainer : class, IWebModuleContainer { var module = new FileModule(baseRoute, new ZipFileProvider(zipFileStream)); diff --git a/src/EmbedIO/WebModuleContainerExtensions-Routing.cs b/src/EmbedIO/WebModuleContainerExtensions-Routing.cs index ec50c8732..2977b78ed 100644 --- a/src/EmbedIO/WebModuleContainerExtensions-Routing.cs +++ b/src/EmbedIO/WebModuleContainerExtensions-Routing.cs @@ -1,6 +1,5 @@ using EmbedIO.Routing; using EmbedIO.Utilities; -using Swan; using Swan.Collections; using System; @@ -42,7 +41,7 @@ public static TContainer WithRouting(this TContainer @this, string b /// /// /// - public static TContainer WithRouting(this TContainer @this, string name, string baseRoute, Action configure) + public static TContainer WithRouting(this TContainer @this, string? name, string baseRoute, Action configure) where TContainer : class, IWebModuleContainer { configure = Validate.NotNull(nameof(configure), configure); diff --git a/src/EmbedIO/WebModuleContainerExtensions-WebApi.cs b/src/EmbedIO/WebModuleContainerExtensions-WebApi.cs index 2fa346d08..3fb3f130a 100644 --- a/src/EmbedIO/WebModuleContainerExtensions-WebApi.cs +++ b/src/EmbedIO/WebModuleContainerExtensions-WebApi.cs @@ -3,7 +3,6 @@ using EmbedIO.Routing; using EmbedIO.Utilities; using EmbedIO.WebApi; -using Swan; using Swan.Collections; namespace EmbedIO @@ -78,7 +77,7 @@ public static TContainer WithWebApi( /// public static TContainer WithWebApi( this TContainer @this, - string name, + string? name, string baseRoute, Action configure) where TContainer : class, IWebModuleContainer @@ -114,7 +113,7 @@ public static TContainer WithWebApi( /// public static TContainer WithWebApi( this TContainer @this, - string name, + string? name, string baseRoute, ResponseSerializerCallback serializer, Action configure) diff --git a/src/EmbedIO/WebModuleContainerExtensions.cs b/src/EmbedIO/WebModuleContainerExtensions.cs index c6c8659c2..603182892 100644 --- a/src/EmbedIO/WebModuleContainerExtensions.cs +++ b/src/EmbedIO/WebModuleContainerExtensions.cs @@ -1,5 +1,5 @@ using System; -using EmbedIO.Utilities; +using Swan.Collections; namespace EmbedIO { @@ -34,7 +34,7 @@ public static TContainer WithModule(this TContainer @this, IWebModul /// is . /// /// - public static TContainer WithModule(this TContainer @this, string name, IWebModule module) + public static TContainer WithModule(this TContainer @this, string? name, IWebModule module) where TContainer : class, IWebModuleContainer { @this.Modules.Add(name, module); @@ -53,7 +53,7 @@ public static TContainer WithModule(this TContainer @this, string na /// is . /// /// - public static TContainer WithModule(this TContainer @this, TWebModule module, Action configure) + public static TContainer WithModule(this TContainer @this, TWebModule module, Action? configure) where TContainer : class, IWebModuleContainer where TWebModule : IWebModule => WithModule(@this, null, module, configure); @@ -72,7 +72,7 @@ public static TContainer WithModule(this TContainer @thi /// is . /// /// - public static TContainer WithModule(this TContainer @this, string name, TWebModule module, Action configure) + public static TContainer WithModule(this TContainer @this, string? name, TWebModule module, Action? configure) where TContainer : class, IWebModuleContainer where TWebModule : IWebModule { diff --git a/src/EmbedIO/WebServer.cs b/src/EmbedIO/WebServer.cs index 0df98d302..6bc23fdee 100644 --- a/src/EmbedIO/WebServer.cs +++ b/src/EmbedIO/WebServer.cs @@ -164,18 +164,10 @@ protected override async Task ProcessRequestsAsync(CancellationToken cancellatio private IHttpListener CreateHttpListener() { - IHttpListener DoCreate() - { - switch (Options.Mode) - { - case HttpListenerMode.Microsoft: - return System.Net.HttpListener.IsSupported - ? new SystemHttpListener(new System.Net.HttpListener()) as IHttpListener - : new Net.HttpListener(Options.Certificate); - default: // case HttpListenerMode.EmbedIO - return new Net.HttpListener(Options.Certificate); - } - } + IHttpListener DoCreate() => Options.Mode switch { + HttpListenerMode.Microsoft => (System.Net.HttpListener.IsSupported ? new SystemHttpListener(new System.Net.HttpListener()) as IHttpListener : new Net.HttpListener(Options.Certificate)), + _ => new Net.HttpListener(Options.Certificate) + }; var listener = DoCreate(); $"Running HTTPListener: {listener.Name}".Info(LogSource); diff --git a/src/EmbedIO/WebServerBase`1.cs b/src/EmbedIO/WebServerBase`1.cs index f3464c8c2..6aea79b07 100644 --- a/src/EmbedIO/WebServerBase`1.cs +++ b/src/EmbedIO/WebServerBase`1.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using EmbedIO.Internal; -using EmbedIO.Routing; using EmbedIO.Sessions; using EmbedIO.Utilities; using Swan.Collections; @@ -31,7 +30,7 @@ public abstract class WebServerBase : ConfiguredObject, IWebServer, IH private WebServerState _state = WebServerState.Created; - private ISessionManager _sessionManager; + private ISessionManager? _sessionManager; /// /// Initializes a new instance of the class. @@ -63,7 +62,7 @@ protected WebServerBase(Action configure) { } - private WebServerBase(TOptions options, Action configure) + private WebServerBase(TOptions options, Action? configure) { Options = options; LogSource = GetType().Name; @@ -82,7 +81,7 @@ private WebServerBase(TOptions options, Action configure) } /// - public event WebServerStateChangedEventHandler StateChanged; + public event WebServerStateChangedEventHandler? StateChanged; /// public IComponentCollection Modules => _modules; @@ -127,7 +126,7 @@ public HttpExceptionHandlerCallback OnHttpException } /// - public ISessionManager SessionManager + public ISessionManager? SessionManager { get => _sessionManager; set diff --git a/src/EmbedIO/WebServerExtensions-SessionManager.cs b/src/EmbedIO/WebServerExtensions-SessionManager.cs index b5e59d0c5..894103826 100644 --- a/src/EmbedIO/WebServerExtensions-SessionManager.cs +++ b/src/EmbedIO/WebServerExtensions-SessionManager.cs @@ -31,7 +31,7 @@ public static TWebServer WithSessionManager(this TWebServer @this, I /// with the session manager set. /// is . /// The web server has already been started. - public static TWebServer WithLocalSessionManager(this TWebServer @this, Action configure = null) + public static TWebServer WithLocalSessionManager(this TWebServer @this, Action? configure = null) where TWebServer : IWebServer { var sessionManager = new LocalSessionManager(); diff --git a/src/EmbedIO/WebServerOptions.cs b/src/EmbedIO/WebServerOptions.cs index a198ccc0e..c8968adbe 100644 --- a/src/EmbedIO/WebServerOptions.cs +++ b/src/EmbedIO/WebServerOptions.cs @@ -23,9 +23,9 @@ public sealed class WebServerOptions : WebServerOptionsBase private HttpListenerMode _mode = HttpListenerMode.EmbedIO; - private X509Certificate2 _certificate; + private X509Certificate2? _certificate; - private string _certificateThumbprint; + private string? _certificateThumbprint; private bool _autoLoadCertificate; @@ -68,7 +68,7 @@ public HttpListenerMode Mode /// /// This property is being set, /// and this instance's configuration is locked. - public X509Certificate2 Certificate + public X509Certificate2? Certificate { get { @@ -89,7 +89,7 @@ public X509Certificate2 Certificate /// /// This property is being set, /// and this instance's configuration is locked. - public string CertificateThumbprint + public string? CertificateThumbprint { get => _certificateThumbprint; set @@ -198,16 +198,16 @@ public void AddUrlPrefix(string urlPrefix) _urlPrefixes.Add(urlPrefix); } - private X509Certificate2 LoadCertificate() + private X509Certificate2? LoadCertificate() { if (SwanRuntime.OS != Swan.OperatingSystem.Windows) return null; if (!string.IsNullOrWhiteSpace(_certificateThumbprint)) return GetCertificate(_certificateThumbprint); - var netsh = GetNetsh("show"); + using var netsh = GetNetsh("show"); - string thumbprint = null; + string? thumbprint = null; netsh.ErrorDataReceived += (s, e) => { @@ -240,33 +240,29 @@ private X509Certificate2 LoadCertificate() : null; } - private X509Certificate2 GetCertificate(string thumbprint = null) + private X509Certificate2? GetCertificate(string? thumbprint = null) { - using (var store = new X509Store(StoreName, StoreLocation)) - { - store.Open(OpenFlags.ReadOnly); - var signingCert = store.Certificates.Find( - X509FindType.FindByThumbprint, - thumbprint ?? _certificateThumbprint, - false); - return signingCert.Count == 0 ? null : signingCert[0]; - } + using var store = new X509Store(StoreName, StoreLocation); + store.Open(OpenFlags.ReadOnly); + var signingCert = store.Certificates.Find( + X509FindType.FindByThumbprint, + thumbprint ?? _certificateThumbprint, + false); + return signingCert.Count == 0 ? null : signingCert[0]; } private bool AddCertificateToStore() { - using (var store = new X509Store(StoreName, StoreLocation)) + using var store = new X509Store(StoreName, StoreLocation); + try { - try - { - store.Open(OpenFlags.ReadWrite); - store.Add(_certificate); - return true; - } - catch - { - return false; - } + store.Open(OpenFlags.ReadWrite); + store.Add(_certificate); + return true; + } + catch + { + return false; } } @@ -284,7 +280,7 @@ private bool TryRegisterCertificate() "The provided certificate cannot be added to the default store, add it manually"); } - var netsh = GetNetsh("add", $"certhash={_certificate.Thumbprint} appid={{adaa04bb-8b63-4073-a12f-d6f8c0b4383f}}"); + using var netsh = GetNetsh("add", $"certhash={_certificate.Thumbprint} appid={{adaa04bb-8b63-4073-a12f-d6f8c0b4383f}}"); var sb = new StringBuilder(); diff --git a/src/EmbedIO/WebSockets/IWebSocket.cs b/src/EmbedIO/WebSockets/IWebSocket.cs index 3121bc6b1..789c012d1 100644 --- a/src/EmbedIO/WebSockets/IWebSocket.cs +++ b/src/EmbedIO/WebSockets/IWebSocket.cs @@ -49,6 +49,6 @@ public interface IWebSocket : IDisposable /// /// The task object representing the asynchronous operation. /// - Task CloseAsync(CloseStatusCode code, string comment = null, CancellationToken cancellationToken = default); + Task CloseAsync(CloseStatusCode code, string? comment = null, CancellationToken cancellationToken = default); } } diff --git a/src/EmbedIO/WebSockets/Internal/PayloadData.cs b/src/EmbedIO/WebSockets/Internal/PayloadData.cs index f910f05e8..271c00526 100644 --- a/src/EmbedIO/WebSockets/Internal/PayloadData.cs +++ b/src/EmbedIO/WebSockets/Internal/PayloadData.cs @@ -20,7 +20,7 @@ internal PayloadData(byte[] data) _data = data; } - internal PayloadData(ushort code = 1005, string reason = null) + internal PayloadData(ushort code = 1005, string? reason = null) { _code = code; _data = code == 1005 ? Array.Empty() : Append(code, reason); @@ -52,7 +52,7 @@ internal ushort Code public override string ToString() => BitConverter.ToString(_data); - internal static byte[] Append(ushort code, string reason) + internal static byte[] Append(ushort code, string? reason) { var ret = code.ToByteArray(Endianness.Big); if (string.IsNullOrEmpty(reason)) return ret; diff --git a/src/EmbedIO/WebSockets/Internal/StreamExtensions.cs b/src/EmbedIO/WebSockets/Internal/StreamExtensions.cs index 5cc33618c..83c6a439f 100644 --- a/src/EmbedIO/WebSockets/Internal/StreamExtensions.cs +++ b/src/EmbedIO/WebSockets/Internal/StreamExtensions.cs @@ -25,39 +25,31 @@ public static async Task CompressAsync( case CompressionMethod.Deflate: if (compress) { - using (var compressor = new DeflateStream(targetStream, CompressionMode.Compress, true)) - { - await @this.CopyToAsync(compressor, 1024, cancellationToken).ConfigureAwait(false); - await @this.CopyToAsync(compressor).ConfigureAwait(false); + using var compressor = new DeflateStream(targetStream, CompressionMode.Compress, true); + await @this.CopyToAsync(compressor, 1024, cancellationToken).ConfigureAwait(false); + await @this.CopyToAsync(compressor).ConfigureAwait(false); - // WebSocket use this - targetStream.Write(LastByte, 0, 1); - targetStream.Position = 0; - } + // WebSocket use this + targetStream.Write(LastByte, 0, 1); + targetStream.Position = 0; } else { - using (var compressor = new DeflateStream(@this, CompressionMode.Decompress)) - { - await compressor.CopyToAsync(targetStream).ConfigureAwait(false); - } + using var compressor = new DeflateStream(@this, CompressionMode.Decompress); + await compressor.CopyToAsync(targetStream).ConfigureAwait(false); } break; case CompressionMethod.Gzip: if (compress) { - using (var compressor = new GZipStream(targetStream, CompressionMode.Compress, true)) - { - await @this.CopyToAsync(compressor).ConfigureAwait(false); - } + using var compressor = new GZipStream(targetStream, CompressionMode.Compress, true); + await @this.CopyToAsync(compressor).ConfigureAwait(false); } else { - using (var compressor = new GZipStream(@this, CompressionMode.Decompress)) - { - await compressor.CopyToAsync(targetStream).ConfigureAwait(false); - } + using var compressor = new GZipStream(@this, CompressionMode.Decompress); + await compressor.CopyToAsync(targetStream).ConfigureAwait(false); } break; diff --git a/src/EmbedIO/WebSockets/Internal/SystemWebSocket.cs b/src/EmbedIO/WebSockets/Internal/SystemWebSocket.cs index ec9d93b78..8f5659419 100644 --- a/src/EmbedIO/WebSockets/Internal/SystemWebSocket.cs +++ b/src/EmbedIO/WebSockets/Internal/SystemWebSocket.cs @@ -40,7 +40,7 @@ public Task CloseAsync(CancellationToken cancellationToken = default) => UnderlyingWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); /// - public Task CloseAsync(CloseStatusCode code, string comment = null, CancellationToken cancellationToken = default)=> + public Task CloseAsync(CloseStatusCode code, string? comment = null, CancellationToken cancellationToken = default)=> UnderlyingWebSocket.CloseAsync(MapCloseStatus(code), comment ?? string.Empty, cancellationToken); private void Dispose(bool disposing) @@ -51,28 +51,16 @@ private void Dispose(bool disposing) UnderlyingWebSocket.Dispose(); } - private WebSocketCloseStatus MapCloseStatus(CloseStatusCode code) - { - switch (code) - { - case CloseStatusCode.Normal: - return WebSocketCloseStatus.NormalClosure; - case CloseStatusCode.ProtocolError: - return WebSocketCloseStatus.ProtocolError; - case CloseStatusCode.InvalidData: - case CloseStatusCode.UnsupportedData: - return WebSocketCloseStatus.InvalidPayloadData; - case CloseStatusCode.PolicyViolation: - return WebSocketCloseStatus.PolicyViolation; - case CloseStatusCode.TooBig: - return WebSocketCloseStatus.MessageTooBig; - case CloseStatusCode.MandatoryExtension: - return WebSocketCloseStatus.MandatoryExtension; - case CloseStatusCode.ServerError: - return WebSocketCloseStatus.InternalServerError; - default: - throw new ArgumentOutOfRangeException(nameof(code), code, null); - } - } + private WebSocketCloseStatus MapCloseStatus(CloseStatusCode code) => code switch { + CloseStatusCode.Normal => WebSocketCloseStatus.NormalClosure, + CloseStatusCode.ProtocolError => WebSocketCloseStatus.ProtocolError, + CloseStatusCode.InvalidData => WebSocketCloseStatus.InvalidPayloadData, + CloseStatusCode.UnsupportedData => WebSocketCloseStatus.InvalidPayloadData, + CloseStatusCode.PolicyViolation => WebSocketCloseStatus.PolicyViolation, + CloseStatusCode.TooBig => WebSocketCloseStatus.MessageTooBig, + CloseStatusCode.MandatoryExtension => WebSocketCloseStatus.MandatoryExtension, + CloseStatusCode.ServerError => WebSocketCloseStatus.InternalServerError, + _ => throw new ArgumentOutOfRangeException(nameof(code), code, null) + }; } } \ No newline at end of file diff --git a/src/EmbedIO/WebSockets/Internal/WebSocket.cs b/src/EmbedIO/WebSockets/Internal/WebSocket.cs index e60e5e7bc..be3bba2c4 100644 --- a/src/EmbedIO/WebSockets/Internal/WebSocket.cs +++ b/src/EmbedIO/WebSockets/Internal/WebSocket.cs @@ -29,11 +29,11 @@ internal sealed class WebSocket : IWebSocket private readonly TimeSpan _waitTime = TimeSpan.FromSeconds(1); private volatile WebSocketState _readyState; - private AutoResetEvent _exitReceiving; - private FragmentBuffer _fragmentsBuffer; + private AutoResetEvent? _exitReceiving; + private FragmentBuffer? _fragmentsBuffer; private volatile bool _inMessage; - private AutoResetEvent _receivePong; - private Stream _stream; + private AutoResetEvent? _receivePong; + private Stream? _stream; private WebSocket(HttpConnection connection) { @@ -50,7 +50,7 @@ private WebSocket(HttpConnection connection) /// /// Occurs when the receives a message. /// - public event EventHandler OnMessage; + public event EventHandler? OnMessage; /// public WebSocketState State => _readyState; @@ -70,7 +70,7 @@ private WebSocket(HttpConnection connection) /// public Task CloseAsync( CloseStatusCode code = CloseStatusCode.Undefined, - string reason = null, + string? reason = null, CancellationToken cancellationToken = default) { bool CheckParametersForClose() @@ -158,11 +158,9 @@ public async Task SendAsync(byte[] data, Opcode opcode, CancellationToken cancel if (_readyState != WebSocketState.Open) throw new WebSocketException(CloseStatusCode.Normal, $"This operation isn\'t available in: {_readyState.ToString()}"); - using (var stream = new WebSocketStream(data, opcode, Compression)) - { - foreach (var frame in stream.GetFrames()) - await Send(frame).ConfigureAwait(false); - } + using var stream = new WebSocketStream(data, opcode, Compression); + foreach (var frame in stream.GetFrames()) + await Send(frame).ConfigureAwait(false); } /// @@ -180,10 +178,8 @@ string CreateResponseKey(string clientKey) var buff = new StringBuilder(clientKey, 64).Append(Guid); #pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms - using (var sha1 = SHA1.Create()) - { - return Convert.ToBase64String(sha1.ComputeHash(Encoding.UTF8.GetBytes(buff.ToString()))); - } + using var sha1 = SHA1.Create(); + return Convert.ToBase64String(sha1.ComputeHash(Encoding.UTF8.GetBytes(buff.ToString()))); #pragma warning restore CA5350 // Do Not Use Weak Cryptographic Algorithms } @@ -246,7 +242,7 @@ private void Dispose(bool disposing) } private async Task InternalCloseAsync( - PayloadData payloadData = null, + PayloadData? payloadData = null, bool send = true, bool receive = true, CancellationToken cancellationToken = default) @@ -286,7 +282,7 @@ private async Task InternalCloseAsync( } private async Task CloseHandshakeAsync( - byte[] frameAsBytes, + byte[]? frameAsBytes, bool receive, CancellationToken cancellationToken) { @@ -301,7 +297,7 @@ private async Task CloseHandshakeAsync( _exitReceiving?.WaitOne(_waitTime); } - private void Fatal(string message, Exception exception = null) + private void Fatal(string message, Exception? exception = null) => Fatal(message, (exception as WebSocketException)?.Code ?? CloseStatusCode.Abnormal); private void Fatal(string message, CloseStatusCode code) @@ -358,7 +354,7 @@ private async Task ProcessDataFrame(WebSocketFrame frame) { if (frame.IsCompressed) { - var ms = await frame.PayloadData.ApplicationData.CompressAsync(Compression, false, CancellationToken.None).ConfigureAwait(false); + using var ms = await frame.PayloadData.ApplicationData.CompressAsync(Compression, false, CancellationToken.None).ConfigureAwait(false); _messageEventQueue.Enqueue(new MessageEventArgs(frame.Opcode, ms.ToArray())); } @@ -404,7 +400,7 @@ private Task ProcessPingFrame(WebSocketFrame frame) private void ProcessPongFrame() { - _receivePong.Set(); + _receivePong?.Set(); "Received a pong.".Trace(nameof(ProcessPongFrame)); } diff --git a/src/EmbedIO/WebSockets/Internal/WebSocketFrame.cs b/src/EmbedIO/WebSockets/Internal/WebSocketFrame.cs index bb913b573..c014e4cf8 100644 --- a/src/EmbedIO/WebSockets/Internal/WebSocketFrame.cs +++ b/src/EmbedIO/WebSockets/Internal/WebSocketFrame.cs @@ -127,45 +127,43 @@ public string PrintToString() public byte[] ToArray() { - using (var buff = new MemoryStream()) - { - var header = (int)Fin; + using var buff = new MemoryStream(); + var header = (int)Fin; - header = (header << 1) + (int)Rsv1; - header = (header << 1) + (int)Rsv2; - header = (header << 1) + (int)Rsv3; - header = (header << 4) + (int)Opcode; - header = (header << 1) + (int)Mask; - header = (header << 7) + PayloadLength; - buff.Write(((ushort)header).ToByteArray(Endianness.Big), 0, 2); + header = (header << 1) + (int)Rsv1; + header = (header << 1) + (int)Rsv2; + header = (header << 1) + (int)Rsv3; + header = (header << 4) + (int)Opcode; + header = (header << 1) + (int)Mask; + header = (header << 7) + PayloadLength; + buff.Write(((ushort)header).ToByteArray(Endianness.Big), 0, 2); - if (PayloadLength > 125) - buff.Write(ExtendedPayloadLength, 0, PayloadLength == 126 ? 2 : 8); + if (PayloadLength > 125) + buff.Write(ExtendedPayloadLength, 0, PayloadLength == 126 ? 2 : 8); - if (Mask == Mask.On) - buff.Write(MaskingKey, 0, 4); + if (Mask == Mask.On) + buff.Write(MaskingKey, 0, 4); - if (PayloadLength > 0) + if (PayloadLength > 0) + { + var bytes = PayloadData.ToArray(); + if (PayloadLength < 127) { - var bytes = PayloadData.ToArray(); - if (PayloadLength < 127) - { - buff.Write(bytes, 0, bytes.Length); - } - else - { - using (var input = new MemoryStream(bytes)) - input.CopyTo(buff, 1024); - } + buff.Write(bytes, 0, bytes.Length); + } + else + { + using var input = new MemoryStream(bytes); + input.CopyTo(buff, 1024); } - - return buff.ToArray(); } + + return buff.ToArray(); } public override string ToString() => BitConverter.ToString(ToArray()); - internal static WebSocketFrame CreateCloseFrame(PayloadData payloadData) => new WebSocketFrame(Fin.Final, Opcode.Close, payloadData ?? new PayloadData()); + internal static WebSocketFrame CreateCloseFrame(PayloadData? payloadData) => new WebSocketFrame(Fin.Final, Opcode.Close, payloadData ?? new PayloadData()); internal static WebSocketFrame CreatePingFrame() => new WebSocketFrame(Fin.Final, Opcode.Ping, new PayloadData()); diff --git a/src/EmbedIO/WebSockets/Internal/WebSocketFrameStream.cs b/src/EmbedIO/WebSockets/Internal/WebSocketFrameStream.cs index 8c9a0bccd..bfcf0ce71 100644 --- a/src/EmbedIO/WebSockets/Internal/WebSocketFrameStream.cs +++ b/src/EmbedIO/WebSockets/Internal/WebSocketFrameStream.cs @@ -16,7 +16,7 @@ public WebSocketFrameStream(Stream stream, bool unmask = false) _unmask = unmask; } - internal async Task ReadFrameAsync(WebSocket webSocket) + internal async Task ReadFrameAsync(WebSocket webSocket) { if (_stream == null) return null; diff --git a/src/EmbedIO/WebSockets/WebSocketException.cs b/src/EmbedIO/WebSockets/WebSocketException.cs index eb3f5ccf1..a628b1b03 100644 --- a/src/EmbedIO/WebSockets/WebSocketException.cs +++ b/src/EmbedIO/WebSockets/WebSocketException.cs @@ -9,18 +9,18 @@ namespace EmbedIO.WebSockets public class WebSocketException : Exception #pragma warning restore CA1032 { - internal WebSocketException(string message = null) + internal WebSocketException(string? message = null) : this(CloseStatusCode.Abnormal, message) { // Ignore } - internal WebSocketException(CloseStatusCode code, Exception innerException = null) + internal WebSocketException(CloseStatusCode code, Exception? innerException = null) : this(code, null, innerException) { } - internal WebSocketException(CloseStatusCode code, string message, Exception innerException = null) + internal WebSocketException(CloseStatusCode code, string? message, Exception? innerException = null) : base(message ?? GetMessage(code), innerException) { Code = code; @@ -35,31 +35,17 @@ internal WebSocketException(CloseStatusCode code, string message, Exception inne /// public CloseStatusCode Code { get; } - internal static string GetMessage(CloseStatusCode code) - { - switch (code) - { - case CloseStatusCode.ProtocolError: - return "A WebSocket protocol error has occurred."; - case CloseStatusCode.UnsupportedData: - return "Unsupported data has been received."; - case CloseStatusCode.Abnormal: - return "An exception has occurred."; - case CloseStatusCode.InvalidData: - return "Invalid data has been received."; - case CloseStatusCode.PolicyViolation: - return "A policy violation has occurred."; - case CloseStatusCode.TooBig: - return "A too big message has been received."; - case CloseStatusCode.MandatoryExtension: - return "WebSocket client didn't receive expected extension(s)."; - case CloseStatusCode.ServerError: - return "WebSocket server got an internal error."; - case CloseStatusCode.TlsHandshakeFailure: - return "An error has occurred during a TLS handshake."; - default: - return string.Empty; - } - } + internal static string GetMessage(CloseStatusCode code) => code switch { + CloseStatusCode.ProtocolError => "A WebSocket protocol error has occurred.", + CloseStatusCode.UnsupportedData => "Unsupported data has been received.", + CloseStatusCode.Abnormal => "An exception has occurred.", + CloseStatusCode.InvalidData => "Invalid data has been received.", + CloseStatusCode.PolicyViolation => "A policy violation has occurred.", + CloseStatusCode.TooBig => "A too big message has been received.", + CloseStatusCode.MandatoryExtension => "WebSocket client didn't receive expected extension(s).", + CloseStatusCode.ServerError => "WebSocket server got an internal error.", + CloseStatusCode.TlsHandshakeFailure => "An error has occurred during a TLS handshake.", + _ => string.Empty + }; } } \ No newline at end of file diff --git a/src/EmbedIO/WebSockets/WebSocketModule.cs b/src/EmbedIO/WebSockets/WebSocketModule.cs index 75b48df7b..fdecaa28f 100644 --- a/src/EmbedIO/WebSockets/WebSocketModule.cs +++ b/src/EmbedIO/WebSockets/WebSocketModule.cs @@ -48,7 +48,7 @@ public abstract class WebSocketModule : WebModuleBase, IDisposable private int _maxMessageSize; private TimeSpan _keepAliveInterval; private Encoding _encoding; - private PeriodicTask _connectionWatchdog; + private PeriodicTask? _connectionWatchdog; /// /// Initializes a new instance of the class. @@ -160,7 +160,7 @@ protected sealed override async Task OnRequestAsync(IHttpContext context) .Where(s => s.Length > 0) .ToArray() ?? Array.Empty(); - string acceptedProtocol; + string? acceptedProtocol; bool acceptConnection; if (_protocols.Count > 0) { diff --git a/test/EmbedIO.Tests/ActionModuleTest.cs b/test/EmbedIO.Tests/ActionModuleTest.cs index 6b23b89cf..1e96e8c77 100644 --- a/test/EmbedIO.Tests/ActionModuleTest.cs +++ b/test/EmbedIO.Tests/ActionModuleTest.cs @@ -20,12 +20,10 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.GetAsync("/").ConfigureAwait(false)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(Ok, responseString); - } + using var response = await client.GetAsync("/").ConfigureAwait(false); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(Ok, responseString); } return TestWebServer.UseAsync(Configure, Use); @@ -39,12 +37,10 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.GetAsync("/").ConfigureAwait(false)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(Ok, responseString); - } + using var response = await client.GetAsync("/").ConfigureAwait(false); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(Ok, responseString); } return TestWebServer.UseAsync(Configure, Use); @@ -58,12 +54,10 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.PostAsync("/", null).ConfigureAwait(false)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(Ok, responseString); - } + using var response = await client.PostAsync("/", null).ConfigureAwait(false); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(Ok, responseString); } return TestWebServer.UseAsync(Configure, Use); @@ -77,12 +71,10 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.PutAsync("/", null).ConfigureAwait(false)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(Ok, responseString); - } + using var response = await client.PutAsync("/", null).ConfigureAwait(false); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(Ok, responseString); } return TestWebServer.UseAsync(Configure, Use); @@ -96,12 +88,10 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.HeadAsync("/").ConfigureAwait(false)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(Ok, responseString); - } + using var response = await client.HeadAsync("/").ConfigureAwait(false); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(Ok, responseString); } return TestWebServer.UseAsync(Configure, Use); @@ -115,12 +105,10 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.DeleteAsync("/").ConfigureAwait(false)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(Ok, responseString); - } + using var response = await client.DeleteAsync("/").ConfigureAwait(false); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(Ok, responseString); } return TestWebServer.UseAsync(Configure, Use); @@ -134,12 +122,10 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.OptionsAsync("/").ConfigureAwait(false)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(Ok, responseString); - } + using var response = await client.OptionsAsync("/").ConfigureAwait(false); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(Ok, responseString); } return TestWebServer.UseAsync(Configure, Use); @@ -153,12 +139,10 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.PatchAsync("/", null).ConfigureAwait(false)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(Ok, responseString); - } + using var response = await client.PatchAsync("/", null).ConfigureAwait(false); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(Ok, responseString); } return TestWebServer.UseAsync(Configure, Use); diff --git a/test/EmbedIO.Tests/BasicAuthenticationModuleTest.cs b/test/EmbedIO.Tests/BasicAuthenticationModuleTest.cs index 2637d1d3a..7c72d048a 100644 --- a/test/EmbedIO.Tests/BasicAuthenticationModuleTest.cs +++ b/test/EmbedIO.Tests/BasicAuthenticationModuleTest.cs @@ -53,7 +53,7 @@ public async Task RequestWithNoAuthorizationHeader_ReturnsUnauthorized() Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode, "Status Code Unauthorized"); } - private Task MakeRequest(string userName, string password) + private Task MakeRequest(string? userName, string? password) { var request = new HttpRequestMessage(HttpMethod.Get, WebServerUrl); diff --git a/test/EmbedIO.Tests/EmbedIO.Tests.csproj b/test/EmbedIO.Tests/EmbedIO.Tests.csproj index 11584df4f..113355740 100644 --- a/test/EmbedIO.Tests/EmbedIO.Tests.csproj +++ b/test/EmbedIO.Tests/EmbedIO.Tests.csproj @@ -2,10 +2,11 @@ Copyright (c) 2016-2019 - Unosquare - netcoreapp2.2 + netcoreapp3.0 UnitTest ..\..\StyleCop.Analyzers.ruleset - 7.3 + 8.0 + enable diff --git a/test/EmbedIO.Tests/FluentTest.cs b/test/EmbedIO.Tests/FluentTest.cs index 577bf9faa..db37a6067 100644 --- a/test/EmbedIO.Tests/FluentTest.cs +++ b/test/EmbedIO.Tests/FluentTest.cs @@ -10,7 +10,7 @@ namespace EmbedIO.Tests [TestFixture] public class FluentTest { - private readonly WebServer _nullWebServer = null; + private readonly WebServer? _nullWebServer = null; private string _rootPath; private string _webServerUrl; diff --git a/test/EmbedIO.Tests/HttpsTest.cs b/test/EmbedIO.Tests/HttpsTest.cs index 424904ec6..e3a78b995 100644 --- a/test/EmbedIO.Tests/HttpsTest.cs +++ b/test/EmbedIO.Tests/HttpsTest.cs @@ -30,21 +30,15 @@ public async Task OpenWebServerHttps_RetrievesIndex() .WithAutoLoadCertificate() .WithMode(HttpListenerMode.EmbedIO); - using (var webServer = new WebServer(options)) - { - webServer.OnAny(ctx => ctx.SendStringAsync(DefaultMessage, MimeType.PlainText, Encoding.UTF8)); + using var webServer = new WebServer(options); + webServer.OnAny(ctx => ctx.SendStringAsync(DefaultMessage, MimeType.PlainText, Encoding.UTF8)); - var dump = webServer.RunAsync(); + var dump = webServer.RunAsync(); - using (var httpClientHandler = new HttpClientHandler()) - { - httpClientHandler.ServerCertificateCustomValidationCallback = ValidateCertificate; - using (var httpClient = new HttpClient(httpClientHandler)) - { - Assert.AreEqual(DefaultMessage, await httpClient.GetStringAsync(HttpsUrl)); - } - } - } + using var httpClientHandler = new HttpClientHandler(); + httpClientHandler.ServerCertificateCustomValidationCallback = ValidateCertificate; + using var httpClient = new HttpClient(httpClientHandler); + Assert.AreEqual(DefaultMessage, await httpClient.GetStringAsync(HttpsUrl)); } [Test] diff --git a/test/EmbedIO.Tests/IPv6Test.cs b/test/EmbedIO.Tests/IPv6Test.cs index 65932ca47..6f0e791d4 100644 --- a/test/EmbedIO.Tests/IPv6Test.cs +++ b/test/EmbedIO.Tests/IPv6Test.cs @@ -30,10 +30,8 @@ public async Task WithUseIpv6_ReturnsValid(string urlTest) var dump = instance.RunAsync(); - using (var client = new HttpClient()) - { - Assert.IsNotEmpty(await client.GetStringAsync(urlTest)); - } + using var client = new HttpClient(); + Assert.IsNotEmpty(await client.GetStringAsync(urlTest)); } [Test] @@ -47,10 +45,8 @@ public async Task WithIpv6Loopback_ReturnsValid() var dump = instance.RunAsync(); - using (var client = new HttpClient()) - { - Assert.IsNotEmpty(await client.GetStringAsync("http://[::1]:8877")); - } + using var client = new HttpClient(); + Assert.IsNotEmpty(await client.GetStringAsync("http://[::1]:8877")); } [TearDown] diff --git a/test/EmbedIO.Tests/IWebServerTest.cs b/test/EmbedIO.Tests/IWebServerTest.cs index e6250a0da..26fb3805e 100644 --- a/test/EmbedIO.Tests/IWebServerTest.cs +++ b/test/EmbedIO.Tests/IWebServerTest.cs @@ -12,63 +12,53 @@ public class IWebServerTest [Test] public void SetupInMemoryWebServer_ReturnsValidInstance() { - using (var webserver = new TestWebServer()) - { - Assert.IsNotNull(webserver); - } + using var webserver = new TestWebServer(); + Assert.IsNotNull(webserver); } [Test] public void AddModule_ReturnsValidInstance() { - using (var webserver = new TestWebServer()) - { - webserver.WithCors(); + using var webserver = new TestWebServer(); + webserver.WithCors(); - Assert.AreEqual(1, webserver.Modules.Count); - } + Assert.AreEqual(1, webserver.Modules.Count); } [Test] public void SetSessionManager_ReturnsValidInstance() { - using (var webserver = new TestWebServer()) - { - webserver.SessionManager = new LocalSessionManager(); + using var webserver = new TestWebServer(); + webserver.SessionManager = new LocalSessionManager(); - Assert.NotNull(webserver.SessionManager); - } + Assert.NotNull(webserver.SessionManager); } [Test] public void SetSessionManagerToNull_ReturnsValidInstance() { - using (var webserver = new TestWebServer()) - { - webserver.SessionManager = new LocalSessionManager(); - webserver.SessionManager = null; + using var webserver = new TestWebServer(); + webserver.SessionManager = new LocalSessionManager(); + webserver.SessionManager = null; - Assert.IsNull(webserver.SessionManager); - } + Assert.IsNull(webserver.SessionManager); } [Test] public async Task RunsServerAndRequestData_ReturnsValidData() { - using (var server = new TestWebServer()) - { - server - .OnAny(ctx => ctx.SendDataAsync(new Person {Name = nameof(Person)})) - .Start(); + using var server = new TestWebServer(); + server + .OnAny(ctx => ctx.SendDataAsync(new Person {Name = nameof(Person)})) + .Start(); - var data = await server.Client.GetStringAsync("/").ConfigureAwait(false); - Assert.IsNotNull(data); + var data = await server.Client.GetStringAsync("/").ConfigureAwait(false); + Assert.IsNotNull(data); - var person = Json.Deserialize(data); - Assert.IsNotNull(person); + var person = Json.Deserialize(data); + Assert.IsNotNull(person); - Assert.AreEqual(person.Name, nameof(Person)); - } + Assert.AreEqual(person.Name, nameof(Person)); } } } \ No newline at end of file diff --git a/test/EmbedIO.Tests/Issues/Issue318_StartupDeadlock.cs b/test/EmbedIO.Tests/Issues/Issue318_StartupDeadlock.cs index 72903949a..2f94285f0 100644 --- a/test/EmbedIO.Tests/Issues/Issue318_StartupDeadlock.cs +++ b/test/EmbedIO.Tests/Issues/Issue318_StartupDeadlock.cs @@ -12,13 +12,11 @@ void ConfigureServerOptions(WebServerOptions options) => options .WithMode(listenerMode) .WithUrlPrefix("http://*:12345"); - using (var server1 = new WebServer(ConfigureServerOptions)) - using (var server2 = new WebServer(ConfigureServerOptions)) - { - server1.Start(); - server2.Start(); - Assert.AreEqual(WebServerState.Stopped, server2.State); - } + using var server1 = new WebServer(ConfigureServerOptions); + using var server2 = new WebServer(ConfigureServerOptions); + server1.Start(); + server2.Start(); + Assert.AreEqual(WebServerState.Stopped, server2.State); } } } \ No newline at end of file diff --git a/test/EmbedIO.Tests/Issues/Issue352_FileSystemProviderEscapedString.cs b/test/EmbedIO.Tests/Issues/Issue352_FileSystemProviderEscapedString.cs index 408b94468..5c55bad07 100644 --- a/test/EmbedIO.Tests/Issues/Issue352_FileSystemProviderEscapedString.cs +++ b/test/EmbedIO.Tests/Issues/Issue352_FileSystemProviderEscapedString.cs @@ -25,11 +25,9 @@ void Configure(IWebServer server) => server async Task Use(HttpClient client) { - using (var response = await client.GetAsync($"/{tempFolder}").ConfigureAwait(false)) - { - var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Assert.AreEqual(ok, responseString); - } + using var response = await client.GetAsync($"/{tempFolder}").ConfigureAwait(false); + var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Assert.AreEqual(ok, responseString); } return TestWebServer.UseAsync(Configure, Use); diff --git a/test/EmbedIO.Tests/Issues/Issue355_ContentResponseLength.cs b/test/EmbedIO.Tests/Issues/Issue355_ContentResponseLength.cs index 9e0ea8e98..13e289b1f 100644 --- a/test/EmbedIO.Tests/Issues/Issue355_ContentResponseLength.cs +++ b/test/EmbedIO.Tests/Issues/Issue355_ContentResponseLength.cs @@ -14,27 +14,21 @@ public async Task ActionModuleWithProperty_Handle_ContentLengthProperly() var ok = Encoding.UTF8.GetBytes("content"); - using (var server = new WebServer(HttpListenerMode.EmbedIO, DefaultUrl)) + using var server = new WebServer(HttpListenerMode.EmbedIO, DefaultUrl); + server.WithAction("/", HttpVerbs.Get, async context => { - server.WithAction("/", HttpVerbs.Get, async context => - { - context.Response.ContentLength64 = ok.Length; + context.Response.ContentLength64 = ok.Length; - await context.Response.OutputStream.WriteAsync(ok, 0, ok.Length); - }); + await context.Response.OutputStream.WriteAsync(ok, 0, ok.Length); + }); - server.RunAsync(); + _ = server.RunAsync(); - using (var client = new HttpClient()) - { - using (var response = await client.GetAsync(DefaultUrl).ConfigureAwait(false)) - { - var responseArray = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + using var client = new HttpClient(); + using var response = await client.GetAsync(DefaultUrl).ConfigureAwait(false); + var responseArray = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); - Assert.AreEqual(ok[0], responseArray[0]); - } - } - } + Assert.AreEqual(ok[0], responseArray[0]); } [Test] @@ -42,27 +36,21 @@ public async Task ActionModuleWithHeaderCollection_Handle_ContentLengthProperly( { var ok = Encoding.UTF8.GetBytes("content"); - using (var server = new WebServer(1234)) + using var server = new WebServer(1234); + server.WithAction("/", HttpVerbs.Get, async context => { - server.WithAction("/", HttpVerbs.Get, async context => - { - context.Response.Headers[HttpHeaderNames.ContentLength] = ok.Length.ToString(); + context.Response.Headers[HttpHeaderNames.ContentLength] = ok.Length.ToString(); - await context.Response.OutputStream.WriteAsync(ok, 0, ok.Length); - }); + await context.Response.OutputStream.WriteAsync(ok, 0, ok.Length); + }); - server.RunAsync(); + _ = server.RunAsync(); - using (var client = new HttpClient()) - { - using (var response = await client.GetAsync("http://localhost:1234/").ConfigureAwait(false)) - { - var responseArray = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + using var client = new HttpClient(); + using var response = await client.GetAsync("http://localhost:1234/").ConfigureAwait(false); + var responseArray = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); - Assert.AreEqual(ok[0], responseArray[0]); - } - } - } + Assert.AreEqual(ok[0], responseArray[0]); } } } \ No newline at end of file diff --git a/test/EmbedIO.Tests/LocalSessionManagerTest.cs b/test/EmbedIO.Tests/LocalSessionManagerTest.cs index 5ad70f8e6..23249802d 100644 --- a/test/EmbedIO.Tests/LocalSessionManagerTest.cs +++ b/test/EmbedIO.Tests/LocalSessionManagerTest.cs @@ -124,16 +124,14 @@ public async Task RetrieveCookie() WebServerUrl + TestLocalSessionController.GetCookie); var uri = new Uri(WebServerUrl + TestLocalSessionController.GetCookie); - using (var response = await Client.SendAsync(request)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Status OK"); - var responseCookies = Client.CookieContainer.GetCookies(uri).Cast(); - Assert.IsNotNull(responseCookies, "Cookies are not null"); - - Assert.Greater(responseCookies.Count(), 0, "Cookies are not empty"); - var cookieName = responseCookies.FirstOrDefault(c => c.Name == TestLocalSessionController.CookieName); - Assert.AreEqual(TestLocalSessionController.CookieName, cookieName?.Name); - } + using var response = await Client.SendAsync(request); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Status OK"); + var responseCookies = Client.CookieContainer.GetCookies(uri).Cast(); + Assert.IsNotNull(responseCookies, "Cookies are not null"); + + Assert.Greater(responseCookies.Count(), 0, "Cookies are not empty"); + var cookieName = responseCookies.FirstOrDefault(c => c.Name == TestLocalSessionController.CookieName); + Assert.AreEqual(TestLocalSessionController.CookieName, cookieName?.Name); } [Test] diff --git a/test/EmbedIO.Tests/ResourceFileProviderTest.cs b/test/EmbedIO.Tests/ResourceFileProviderTest.cs index b49e2076e..848cbca16 100644 --- a/test/EmbedIO.Tests/ResourceFileProviderTest.cs +++ b/test/EmbedIO.Tests/ResourceFileProviderTest.cs @@ -37,8 +37,8 @@ public void OpenFile_ReturnsCorrectContent(string urlPath) var expectedText = StockResource.GetText(urlPath, Encoding.UTF8); string actualText; using (var stream = _fileProvider.OpenFile(info.Path)) - using (var reader = new StreamReader(stream, Encoding.UTF8, false, WebServer.StreamCopyBufferSize, true)) { + using var reader = new StreamReader(stream, Encoding.UTF8, false, WebServer.StreamCopyBufferSize, true); actualText = reader.ReadToEnd(); } diff --git a/test/EmbedIO.Tests/StaticFilesModuleTest.cs b/test/EmbedIO.Tests/StaticFilesModuleTest.cs index bdbdb33b8..12fb81172 100644 --- a/test/EmbedIO.Tests/StaticFilesModuleTest.cs +++ b/test/EmbedIO.Tests/StaticFilesModuleTest.cs @@ -74,14 +74,12 @@ public async Task TestHeadIndex() { var request = new HttpRequestMessage(HttpMethod.Head, UrlPath.Root); - using (var response = await Client.SendAsync(request)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Status Code OK"); + using var response = await Client.SendAsync(request); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Status Code OK"); - var html = await response.Content.ReadAsStringAsync(); + var html = await response.Content.ReadAsStringAsync(); - Assert.IsEmpty(html, "Content Empty"); - } + Assert.IsEmpty(html, "Content Empty"); } [Test] @@ -91,21 +89,19 @@ public async Task FileWritable() var file = Path.Combine(root, "index.html"); File.WriteAllText(file, Resources.Index); - using (var server = new TestWebServer()) - { - server - .WithStaticFolder("/", root, false) - .Start(); + using var server = new TestWebServer(); + server + .WithStaticFolder("/", root, false) + .Start(); - var remoteFile = await server.Client.GetStringAsync(UrlPath.Root); - File.WriteAllText(file, Resources.SubIndex); + var remoteFile = await server.Client.GetStringAsync(UrlPath.Root); + File.WriteAllText(file, Resources.SubIndex); - var remoteUpdatedFile = await server.Client.GetStringAsync(UrlPath.Root); - File.WriteAllText(file, nameof(WebServer)); + var remoteUpdatedFile = await server.Client.GetStringAsync(UrlPath.Root); + File.WriteAllText(file, nameof(WebServer)); - Assert.AreEqual(Resources.Index, remoteFile); - Assert.AreEqual(Resources.SubIndex, remoteUpdatedFile); - } + Assert.AreEqual(Resources.Index, remoteFile); + Assert.AreEqual(Resources.SubIndex, remoteUpdatedFile); } [Test] @@ -139,18 +135,14 @@ public async Task GetPartialContent(string message, int offset, int length) var request = new HttpRequestMessage(HttpMethod.Get, StaticFolder.WithDataFiles.BigDataFile); request.Headers.Range = new RangeHeaderValue(offset, offset + length - 1); - using (var response = await Client.SendAsync(request)) - { - Assert.AreEqual(HttpStatusCode.PartialContent, response.StatusCode, "Responds with 216 Partial Content"); + using var response = await Client.SendAsync(request); + Assert.AreEqual(HttpStatusCode.PartialContent, response.StatusCode, "Responds with 216 Partial Content"); - using (var ms = new MemoryStream()) - { - var responseStream = await response.Content.ReadAsStreamAsync(); - responseStream.CopyTo(ms); - var data = ms.ToArray(); - Assert.IsTrue(ServedFolder.BigData.Skip(offset).Take(length).SequenceEqual(data), message); - } - } + using var ms = new MemoryStream(); + var responseStream = await response.Content.ReadAsStreamAsync(); + responseStream.CopyTo(ms); + var data = ms.ToArray(); + Assert.IsTrue(ServedFolder.BigData.Skip(offset).Take(length).SequenceEqual(data), message); } [Test] @@ -158,15 +150,13 @@ public async Task NotPartial() { var request = new HttpRequestMessage(HttpMethod.Get, StaticFolder.WithDataFiles.BigDataFile); - using (var response = await Client.SendAsync(request)) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Status Code OK"); + using var response = await Client.SendAsync(request); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Status Code OK"); - var data = await response.Content.ReadAsByteArrayAsync(); + var data = await response.Content.ReadAsByteArrayAsync(); - Assert.IsNotNull(data, "Data is not empty"); - Assert.IsTrue(ServedFolder.BigData.SequenceEqual(data)); - } + Assert.IsNotNull(data, "Data is not empty"); + Assert.IsTrue(ServedFolder.BigData.SequenceEqual(data)); } [Test] @@ -191,17 +181,13 @@ public async Task ReconstructFileFromPartials() request.Headers.Range = new RangeHeaderValue(offset, top); - using (var response = await Client.SendAsync(request)) - { - Assert.AreEqual(HttpStatusCode.PartialContent, response.StatusCode); - - using (var ms = new MemoryStream()) - { - var stream = await response.Content.ReadAsStreamAsync(); - stream.CopyTo(ms); - Buffer.BlockCopy(ms.GetBuffer(), 0, buffer, offset, (int)ms.Length); - } - } + using var response = await Client.SendAsync(request); + Assert.AreEqual(HttpStatusCode.PartialContent, response.StatusCode); + + using var ms = new MemoryStream(); + var stream = await response.Content.ReadAsStreamAsync(); + stream.CopyTo(ms); + Buffer.BlockCopy(ms.GetBuffer(), 0, buffer, offset, (int)ms.Length); } Assert.IsTrue(ServedFolder.BigData.SequenceEqual(buffer)); @@ -212,17 +198,13 @@ public async Task InvalidRange_RespondsWith416() { var requestHead = new HttpRequestMessage(HttpMethod.Get, WebServerUrl + StaticFolder.WithDataFiles.BigDataFile); - using (var res = await Client.SendAsync(requestHead)) - { - var request = new HttpRequestMessage(HttpMethod.Get, WebServerUrl + StaticFolder.WithDataFiles.BigDataFile); - request.Headers.Range = new RangeHeaderValue(0, StaticFolder.WithDataFiles.BigDataSize + 10); + using var res = await Client.SendAsync(requestHead); + var request = new HttpRequestMessage(HttpMethod.Get, WebServerUrl + StaticFolder.WithDataFiles.BigDataFile); + request.Headers.Range = new RangeHeaderValue(0, StaticFolder.WithDataFiles.BigDataSize + 10); - using (var response = await Client.SendAsync(request)) - { - Assert.AreEqual(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode); - Assert.AreEqual(StaticFolder.WithDataFiles.BigDataSize, response.Content.Headers.ContentRange.Length); - } - } + using var response = await Client.SendAsync(request); + Assert.AreEqual(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode); + Assert.AreEqual(StaticFolder.WithDataFiles.BigDataSize, response.Content.Headers.ContentRange.Length); } } @@ -237,14 +219,14 @@ public async Task GetGzip() using (var response = await Client.SendAsync(request)) { Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Status Code OK"); - using (var memoryStream = new MemoryStream()) + using var memoryStream = new MemoryStream(); + using (var compressor = new GZipStream(memoryStream, CompressionMode.Compress)) { - using (var compressor = new GZipStream(memoryStream, CompressionMode.Compress)) - using (var responseStream = await response.Content.ReadAsStreamAsync()) - responseStream.CopyTo(compressor); - - compressedBytes = memoryStream.ToArray(); + using var responseStream = await response.Content.ReadAsStreamAsync(); + responseStream.CopyTo(compressor); } + + compressedBytes = memoryStream.ToArray(); } request = new HttpRequestMessage(HttpMethod.Get, UrlPath.Root); diff --git a/test/EmbedIO.Tests/WebServerTest.cs b/test/EmbedIO.Tests/WebServerTest.cs index 46c4a2be1..167f5fac3 100644 --- a/test/EmbedIO.Tests/WebServerTest.cs +++ b/test/EmbedIO.Tests/WebServerTest.cs @@ -100,14 +100,12 @@ public void ExceptionText() { var url = Resources.GetServerAddress(); - using (var instance = new WebServer(url)) - { - instance.Modules.Add(nameof(ActionModule), new ActionModule(_ => throw new InvalidOperationException("Error"))); + using var instance = new WebServer(url); + instance.Modules.Add(nameof(ActionModule), new ActionModule(_ => throw new InvalidOperationException("Error"))); - var runTask = instance.RunAsync(); - var request = new HttpClient(); - await request.GetStringAsync(url); - } + var runTask = instance.RunAsync(); + var request = new HttpClient(); + await request.GetStringAsync(url); }); } @@ -118,12 +116,10 @@ public void EmptyModules_NotFoundStatusCode() { var url = Resources.GetServerAddress(); - using (var instance = new WebServer(url)) - { - var runTask = instance.RunAsync(); - var request = new HttpClient(); - await request.GetStringAsync(url); - } + using var instance = new WebServer(url); + var runTask = instance.RunAsync(); + var request = new HttpClient(); + await request.GetStringAsync(url); }); } @@ -134,63 +130,57 @@ public async Task EncodingTest(string encodeName) { var url = Resources.GetServerAddress(); - using (var instance = new WebServer(url)) + using var instance = new WebServer(url); + instance.OnPost(ctx => { - instance.OnPost(ctx => + var encoding = Encoding.GetEncoding("UTF-8"); + + try + { + var encodeValue = + ctx.Request.ContentType.Split(';') + .FirstOrDefault(x => + x.Trim().StartsWith("charset", StringComparison.OrdinalIgnoreCase)) + ? + .Split('=') + .Skip(1) + .FirstOrDefault()? + .Trim(); + encoding = Encoding.GetEncoding(encodeValue ?? throw new InvalidOperationException()); + } + catch { - var encoding = Encoding.GetEncoding("UTF-8"); - - try - { - var encodeValue = - ctx.Request.ContentType.Split(';') - .FirstOrDefault(x => - x.Trim().StartsWith("charset", StringComparison.OrdinalIgnoreCase)) - ? - .Split('=') - .Skip(1) - .FirstOrDefault()? - .Trim(); - encoding = Encoding.GetEncoding(encodeValue ?? throw new InvalidOperationException()); - } - catch - { - Assert.Inconclusive("Invalid encoding in system"); - } - - return ctx.SendDataAsync(new EncodeCheck - { - Encoding = encoding.EncodingName, - IsValid = ctx.Request.ContentEncoding.EncodingName == encoding.EncodingName, - }); + Assert.Inconclusive("Invalid encoding in system"); + } + + return ctx.SendDataAsync(new EncodeCheck + { + Encoding = encoding.EncodingName, + IsValid = ctx.Request.ContentEncoding.EncodingName == encoding.EncodingName, }); + }); - var runTask = instance.RunAsync(); + var runTask = instance.RunAsync(); - using (var client = new HttpClient()) - { - client.DefaultRequestHeaders.Accept - .Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(MimeType.Json)); - - var request = new HttpRequestMessage(HttpMethod.Post, url) - { - Content = new StringContent( - "POST DATA", - Encoding.GetEncoding(encodeName), - MimeType.Json), - }; - - using (var response = await client.SendAsync(request)) - { - var data = await response.Content.ReadAsStringAsync(); - Assert.IsNotNull(data, "Data is not empty"); - var model = Json.Deserialize(data); - - Assert.IsNotNull(model); - Assert.IsTrue(model.IsValid); - } - } - } + using var client = new HttpClient(); + client.DefaultRequestHeaders.Accept + .Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(MimeType.Json)); + + var request = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = new StringContent( + "POST DATA", + Encoding.GetEncoding(encodeName), + MimeType.Json), + }; + + using var response = await client.SendAsync(request); + var data = await response.Content.ReadAsStringAsync(); + Assert.IsNotNull(data, "Data is not empty"); + var model = Json.Deserialize(data); + + Assert.IsNotNull(model); + Assert.IsTrue(model.IsValid); } internal class EncodeCheck diff --git a/test/EmbedIO.Tests/WebSocketModuleTest.cs b/test/EmbedIO.Tests/WebSocketModuleTest.cs index e38729d06..f783dec5d 100644 --- a/test/EmbedIO.Tests/WebSocketModuleTest.cs +++ b/test/EmbedIO.Tests/WebSocketModuleTest.cs @@ -77,19 +77,17 @@ protected static async Task ReadString(System.Net.WebSockets.ClientWebSo { var buffer = new ArraySegment(new byte[8192]); - using (var ms = new MemoryStream()) - { - System.Net.WebSockets.WebSocketReceiveResult result; - - do - { - result = await ws.ReceiveAsync(buffer, default); - ms.Write(buffer.Array, buffer.Offset, result.Count); - } - while (!result.EndOfMessage); + using var ms = new MemoryStream(); + System.Net.WebSockets.WebSocketReceiveResult result; - return Encoding.UTF8.GetString(ms.ToArray()); + do + { + result = await ws.ReceiveAsync(buffer, default); + ms.Write(buffer.Array, buffer.Offset, result.Count); } + while (!result.EndOfMessage); + + return Encoding.UTF8.GetString(ms.ToArray()); } } } \ No newline at end of file