diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
new file mode 100644
index 00000000..f71b1eb2
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,2 @@
+paths-ignore:
+ - '**/bundle.js'
diff --git a/.github/stale.yml b/.github/stale.yml
index dc90e5a1..d302861c 100644
--- a/.github/stale.yml
+++ b/.github/stale.yml
@@ -5,7 +5,7 @@ daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- - security
+ - area:security
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cfd90b60..6bc51722 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,14 +11,14 @@ jobs:
os: [ubuntu-latest, macos-latest]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup .NET Core
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v2
with:
- dotnet-version: 5.0
+ dotnet-version: 6.0
- name: Test with dotnet
run: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:Exclude=[NUnit3.TestAdapter]* ./test/EmbedIO.Tests/EmbedIO.Tests.csproj -c Release
- - uses: codecov/codecov-action@v1
+ - uses: codecov/codecov-action@v3
with:
file: test/EmbedIO.Tests/coverage.info
token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000..394c8f98
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,67 @@
+name: "CodeQL"
+
+on:
+ push:
+ branches: [master, "v[1-9].X"]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [master, "v[1-9].X"]
+ schedule:
+ - cron: '0 6 * * 6'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ # Override automatic language detection by changing the below list
+ # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
+ language: ['csharp', 'javascript']
+ # Learn more...
+ # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+ with:
+ # We must fetch at least the immediate parents so that if this is
+ # a pull request then we can checkout the head.
+ fetch-depth: 2
+
+ # If this run was triggered by a pull request event, then checkout
+ # the head of the pull request instead of the merge commit.
+ - run: git checkout HEAD^2
+ if: ${{ github.event_name == 'pull_request' }}
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ config-file: ./.github/codeql/codeql-config.yml
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v2
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/Directory.Build.props b/Directory.Build.props
index de4992f2..da2d3396 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,22 +5,22 @@
- Copyright (C) Unosquare 2013-2021
+ Copyright (C) Unosquare 2013-2022
3.5.0
+ true
latest
enable
true
$(MSBuildThisFileDirectory)StyleCop.Analyzers.ruleset
+ latest
+ All
+ true
-
- all
- runtime; build; native; contentfiles; analyzers
-
all
runtime; build; native; contentfiles; analyzers
diff --git a/Directory.Packages.props b/Directory.Packages.props
index d8ab33a6..5c6a8124 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,14 +1,13 @@
-
-
-
+
+
-
-
-
-
+
+
+
+
diff --git a/EmbedIO.sln b/EmbedIO.sln
index c883f1de..fecdce67 100644
--- a/EmbedIO.sln
+++ b/EmbedIO.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29609.76
+# Visual Studio Version 17
+VisualStudioVersion = 17.2.32526.322
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{97BC259A-4E78-4BA8-8F4D-2656BC78BB34}"
EndProject
diff --git a/EmbedIO.sln.DotSettings b/EmbedIO.sln.DotSettings
index ebc98fb9..d90d95cb 100644
--- a/EmbedIO.sln.DotSettings
+++ b/EmbedIO.sln.DotSettings
@@ -467,6 +467,7 @@
2
True
<Configurator><ConnectList /></Configurator>
+ True
True
True
True
diff --git a/NuGet.config b/NuGet.config
new file mode 100644
index 00000000..45bc4e94
--- /dev/null
+++ b/NuGet.config
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 1ceefdde..bbdc8a66 100644
--- a/README.md
+++ b/README.md
@@ -223,9 +223,9 @@ namespace Unosquare
///
/// Defines a very simple chat server.
///
- public class WebSocketsChatServer : WebSocketModule
+ public class WebSocketsChatModule : WebSocketModule
{
- public WebSocketsChatServer(string urlPath)
+ public WebSocketsChatModule(string urlPath)
: base(urlPath, true)
{
// placeholder
diff --git a/appveyor.yml b/appveyor.yml
index fdc06ccd..c21d1018 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,7 +1,5 @@
version: '3.0.{build}'
-image:
-- Visual Studio 2019
-- Ubuntu
+image: ["Visual Studio 2022"] # TODO: change back to ["Visual Studio 2022", "Ubuntu"] when Ubuntu image gets .NET SDK updated to 6.0.300
environment:
APPVEYOR_YML_DISABLE_PS_LINUX: true
COVERALLS_REPO_TOKEN:
diff --git a/global.json b/global.json
new file mode 100644
index 00000000..3a8f1701
--- /dev/null
+++ b/global.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "6.0.300",
+ "rollForward": "latestMinor",
+ "allowPrerelease": false
+ }
+}
diff --git a/src/EmbedIO.Samples/EmbedIO.Samples.csproj b/src/EmbedIO.Samples/EmbedIO.Samples.csproj
index 468f8d64..ba3a79e6 100644
--- a/src/EmbedIO.Samples/EmbedIO.Samples.csproj
+++ b/src/EmbedIO.Samples/EmbedIO.Samples.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net6.0
EmbedIO.Samples
Exe
false
diff --git a/src/EmbedIO/Files/Internal/HtmlDirectoryLister.cs b/src/EmbedIO/Files/Internal/HtmlDirectoryLister.cs
index 7a8c4afc..f85eebf2 100644
--- a/src/EmbedIO/Files/Internal/HtmlDirectoryLister.cs
+++ b/src/EmbedIO/Files/Internal/HtmlDirectoryLister.cs
@@ -4,7 +4,6 @@
using System.IO;
using System.Linq;
using System.Net;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
using EmbedIO.Utilities;
@@ -52,7 +51,7 @@ public async Task ListDirectoryAsync(
foreach (var directory in entries.Where(m => m.IsDirectory).OrderBy(e => e.Name))
{
- text.Write($"{WebUtility.HtmlEncode(directory.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');
diff --git a/src/EmbedIO/Net/Internal/HttpListenerRequest.cs b/src/EmbedIO/Net/Internal/HttpListenerRequest.cs
index 8b4f5597..548f44d7 100644
--- a/src/EmbedIO/Net/Internal/HttpListenerRequest.cs
+++ b/src/EmbedIO/Net/Internal/HttpListenerRequest.cs
@@ -218,10 +218,11 @@ internal void FinishInitialization()
host = rawUri?.Host ?? UserHostAddress;
}
- var colon = host.LastIndexOf(':');
- if (colon >= 0)
+ var colonPos = host.LastIndexOf(':');
+ var closedSquareBracketPos = host.LastIndexOf(']');
+ if (colonPos >= 0 && closedSquareBracketPos < colonPos)
{
- host = host.Substring(0, colon);
+ host = host.Substring(0, colonPos);
}
// var baseUri = $"{(IsSecureConnection ? "https" : "http")}://{host}:{LocalEndPoint.Port}";
diff --git a/src/EmbedIO/Net/Internal/HttpListenerResponse.cs b/src/EmbedIO/Net/Internal/HttpListenerResponse.cs
index ff029103..be8703a9 100644
--- a/src/EmbedIO/Net/Internal/HttpListenerResponse.cs
+++ b/src/EmbedIO/Net/Internal/HttpListenerResponse.cs
@@ -177,8 +177,8 @@ internal MemoryStream SendHeaders(bool closing)
{
if (_contentType != null)
{
- var contentTypeValue = _contentType.IndexOf("charset=", StringComparison.Ordinal) == -1
- ? $"{_contentType}; charset={WebServer.DefaultEncoding.WebName}"
+ var contentTypeValue = _contentType.IndexOf("charset=", StringComparison.Ordinal) == -1 && ContentEncoding is not null
+ ? $"{_contentType}; charset={ContentEncoding.WebName}"
: _contentType;
Headers.Add(HttpHeaderNames.ContentType, contentTypeValue);
@@ -194,25 +194,37 @@ internal MemoryStream SendHeaders(bool closing)
Headers.Add(HttpHeaderNames.Date, HttpDate.Format(DateTime.UtcNow));
}
- if (closing)
+ // HTTP did not support chunked transfer encoding before version 1.1;
+ // besides, there's no point in setting transfer encoding at all without a request body.
+ if (closing || ProtocolVersion < HttpVersion.Version11)
{
- Headers[HttpHeaderNames.ContentLength] = "0";
_chunked = false;
}
- else
+
+ // Was content length set to a valid value, AND chunked encoding not set?
+ // Note that this does not mean that a response body _will_ be sent
+ // as this could be the response to a HEAD request.
+ var haveContentLength = !_chunked
+ && Headers.ContainsKey(HttpHeaderNames.ContentLength)
+ && long.TryParse(Headers[HttpHeaderNames.ContentLength], NumberStyles.None, CultureInfo.InvariantCulture, out var contentLength)
+ && contentLength >= 0L;
+
+ if (!haveContentLength)
{
- if (ProtocolVersion < HttpVersion.Version11)
+ // Content length could have been set to an invalid value (e.g. "-1")
+ // so we must either force it to 0, or remove the header completely.
+ if (closing)
{
- _chunked = false;
+ // Content length was not explicitly set to a valid value,
+ // and there is no request body.
+ Headers[HttpHeaderNames.ContentLength] = "0";
}
-
- var haveContentLength = !_chunked
- && Headers.ContainsKey(HttpHeaderNames.ContentLength)
- && long.TryParse(Headers[HttpHeaderNames.ContentLength], out var contentLength)
- && contentLength >= 0L;
-
- if (!haveContentLength)
+ else
{
+ // Content length was not explicitly set to a valid value,
+ // and we're going to send a request body.
+ // - Remove possibly invalid Content-Length header
+ // - Enable chunked transfer encoding for HTTP 1.1
Headers.Remove(HttpHeaderNames.ContentLength);
if (ProtocolVersion >= HttpVersion.Version11)
{
diff --git a/src/EmbedIO/Net/Internal/ListenerPrefix.cs b/src/EmbedIO/Net/Internal/ListenerPrefix.cs
index 11bfc47e..7bd2f1e4 100644
--- a/src/EmbedIO/Net/Internal/ListenerPrefix.cs
+++ b/src/EmbedIO/Net/Internal/ListenerPrefix.cs
@@ -1,5 +1,4 @@
using System;
-using System.Globalization;
namespace EmbedIO.Net.Internal
{
@@ -7,44 +6,11 @@ internal sealed class ListenerPrefix
{
public ListenerPrefix(string uri)
{
- var defaultPort = 80;
-
- if (uri.StartsWith("https://", StringComparison.Ordinal))
- {
- defaultPort = 443;
- Secure = true;
- }
-
- var length = uri.Length;
- var startHost = uri.IndexOf(':') + 3;
-
- if (startHost >= length)
- {
- throw new ArgumentException("No host specified.");
- }
-
- var colon = uri.LastIndexOf(':');
- int root;
-
- if (colon > 0)
- {
- Host = uri.Substring(startHost, colon - startHost);
- root = uri.IndexOf('/', colon, length - colon);
- Port = int.Parse(uri.Substring(colon + 1, root - colon - 1), CultureInfo.InvariantCulture);
- }
- else
- {
- root = uri.IndexOf('/', startHost, length - startHost);
- Host = uri.Substring(startHost, root - startHost);
- Port = defaultPort;
- }
-
- Path = uri.Substring(root);
-
- if (Path.Length != 1)
- {
- Path = Path.Substring(0, Path.Length - 1);
- }
+ var parsedUri = ListenerUri.Parse(uri);
+ Secure = parsedUri.Secure;
+ Host = parsedUri.Host;
+ Port = parsedUri.Port;
+ Path = parsedUri.Path;
}
public HttpListener? Listener { get; set; }
@@ -59,58 +25,7 @@ public ListenerPrefix(string uri)
public static void CheckUri(string uri)
{
- if (uri == null)
- {
- throw new ArgumentNullException(nameof(uri));
- }
-
- if (!uri.StartsWith("http://", StringComparison.Ordinal) && !uri.StartsWith("https://", StringComparison.Ordinal))
- {
- throw new ArgumentException("Only 'http' and 'https' schemes are supported.");
- }
-
- var length = uri.Length;
- var startHost = uri.IndexOf(':') + 3;
-
- if (startHost >= length)
- {
- throw new ArgumentException("No host specified.");
- }
-
- var colon = uri.Substring(startHost).IndexOf(':') > 0 ? uri.LastIndexOf(':') : -1;
-
- if (startHost == colon)
- {
- throw new ArgumentException("No host specified.");
- }
-
- int root;
- if (colon > 0)
- {
- root = uri.IndexOf('/', colon, length - colon);
- if (root == -1)
- {
- throw new ArgumentException("No path specified.");
- }
-
- if (!int.TryParse(uri.Substring(colon + 1, root - colon - 1), out var p) || p <= 0 || p >= 65536)
- {
- throw new ArgumentException("Invalid port.");
- }
- }
- else
- {
- root = uri.IndexOf('/', startHost, length - startHost);
- if (root == -1)
- {
- throw new ArgumentException("No path specified.");
- }
- }
-
- if (uri[uri.Length - 1] != '/')
- {
- throw new ArgumentException("The prefix must end with '/'");
- }
+ _ = ListenerUri.Parse(uri);
}
public bool IsValid() => Path.IndexOf('%') == -1 && Path.IndexOf("//", StringComparison.Ordinal) == -1;
diff --git a/src/EmbedIO/Net/Internal/ListenerUri.cs b/src/EmbedIO/Net/Internal/ListenerUri.cs
new file mode 100644
index 00000000..e89080d2
--- /dev/null
+++ b/src/EmbedIO/Net/Internal/ListenerUri.cs
@@ -0,0 +1,91 @@
+using System;
+
+namespace EmbedIO.Net.Internal
+{
+ internal class ListenerUri
+ {
+ private ListenerUri(bool secure,
+ string host,
+ int port,
+ string path)
+ {
+ Secure = secure;
+ Host = host;
+ Port = port;
+ Path = path;
+ }
+
+ public bool Secure { get; private set; }
+
+ public string Host { get; private set; }
+
+ public int Port { get; private set; }
+
+ public string Path { get; private set; }
+
+ public static ListenerUri Parse(string uri)
+ {
+ bool secure;
+ int port;
+ int parsingPosition;
+ if (uri.StartsWith("http://"))
+ {
+ secure = false;
+ port = 80;
+ parsingPosition = "http://".Length;
+ }
+ else if (uri.StartsWith("https://"))
+ {
+ secure = true;
+ port = 443;
+ parsingPosition = "https://".Length;
+ }
+ else
+ {
+ throw new Exception("Only 'http' and 'https' schemes are supported.");
+ }
+
+ var startOfPath = uri.IndexOf('/', parsingPosition);
+ if (startOfPath == -1)
+ {
+ throw new ArgumentException("Path should end in '/'.");
+ }
+
+ var hostWithPort = uri.Substring(parsingPosition, startOfPath - parsingPosition);
+
+ var startOfPortWithColon = hostWithPort.LastIndexOf(':');
+ if (startOfPortWithColon > -1)
+ {
+ startOfPortWithColon += parsingPosition;
+ }
+
+ var endOfIpV6 = hostWithPort.LastIndexOf(']');
+ if (endOfIpV6 > -1)
+ {
+ endOfIpV6 += parsingPosition;
+ }
+
+ if (endOfIpV6 > startOfPortWithColon)
+ {
+ startOfPortWithColon = -1;
+ }
+
+ if (startOfPortWithColon != -1 && startOfPortWithColon < startOfPath)
+ {
+ if (!int.TryParse(uri.Substring(startOfPortWithColon + 1, startOfPath - startOfPortWithColon - 1), out port) || port <= 0 || port >= 65535)
+ {
+ throw new ArgumentException("Invalid port.");
+ }
+ }
+
+ var host = uri.Substring(parsingPosition, (startOfPortWithColon == -1 ? startOfPath : startOfPortWithColon) - parsingPosition);
+ var path = uri.Substring(startOfPath);
+ if (!path.EndsWith("/"))
+ {
+ throw new ArgumentException("Path should end in '/'.");
+ }
+
+ return new ListenerUri(secure, host, port, path);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/EmbedIO/WebSockets/WebSocketModule.cs b/src/EmbedIO/WebSockets/WebSocketModule.cs
index b1d5e522..a4cef0ac 100644
--- a/src/EmbedIO/WebSockets/WebSocketModule.cs
+++ b/src/EmbedIO/WebSockets/WebSocketModule.cs
@@ -512,7 +512,11 @@ protected virtual void Dispose(bool disposing)
private void RemoveWebSocket(IWebSocketContext context)
{
- _ = _contexts.TryRemove(context.Id, out _);
+ if (!_contexts.TryRemove(context.Id, out _))
+ {
+ return;
+ }
+
context.WebSocket?.Dispose();
// OnClientDisconnectedAsync is better called in its own task,
diff --git a/test/EmbedIO.Tests/EmbedIO.Tests.csproj b/test/EmbedIO.Tests/EmbedIO.Tests.csproj
index 4dbd71e7..1ad58b4a 100644
--- a/test/EmbedIO.Tests/EmbedIO.Tests.csproj
+++ b/test/EmbedIO.Tests/EmbedIO.Tests.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net6.0
UnitTest
diff --git a/test/EmbedIO.Tests/EndToEndFixtureBase.cs b/test/EmbedIO.Tests/EndToEndFixtureBase.cs
index 8f17e4e6..b63a78bd 100644
--- a/test/EmbedIO.Tests/EndToEndFixtureBase.cs
+++ b/test/EmbedIO.Tests/EndToEndFixtureBase.cs
@@ -11,10 +11,12 @@ namespace EmbedIO.Tests
public abstract class EndToEndFixtureBase : IDisposable
{
private readonly bool _useTestWebServer;
+ private readonly bool _useIPv6;
- protected EndToEndFixtureBase(bool useTestWebServer = true)
+ protected EndToEndFixtureBase(bool useTestWebServer = true, bool useIPv6 = false)
{
_useTestWebServer = useTestWebServer;
+ _useIPv6 = useIPv6;
}
~EndToEndFixtureBase()
@@ -37,7 +39,7 @@ public void Dispose()
[SetUp]
public void SetUp()
{
- WebServerUrl = Resources.GetServerAddress();
+ WebServerUrl = Resources.GetServerAddress(_useIPv6);
if (_useTestWebServer)
{
diff --git a/test/EmbedIO.Tests/FileModuleTest.cs b/test/EmbedIO.Tests/FileModuleTest.cs
index 3b60d8d1..0f3fc54a 100644
--- a/test/EmbedIO.Tests/FileModuleTest.cs
+++ b/test/EmbedIO.Tests/FileModuleTest.cs
@@ -1,16 +1,15 @@
-using EmbedIO.Tests.TestObjects;
-using NUnit.Framework;
-using System;
+using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
-using System.Runtime.InteropServices;
using System.Threading.Tasks;
using EmbedIO.Testing;
+using EmbedIO.Tests.TestObjects;
using EmbedIO.Utilities;
+using NUnit.Framework;
namespace EmbedIO.Tests
{
@@ -78,11 +77,9 @@ public async Task TestHeadIndex()
}
[Test]
+ [Platform(Exclude = "MacOsX", Reason = "OSX doesn't support FileSystemWatcher.")]
public async Task FileWritable()
{
- if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
- Assert.Ignore("OSX doesn't support FileSystemWatcher");
-
var root = Path.GetTempPath();
var file = Path.Combine(root, "index.html");
File.WriteAllText(file, Resources.Index);
diff --git a/test/EmbedIO.Tests/HttpsTest.cs b/test/EmbedIO.Tests/HttpsTest.cs
index 9a0b23c5..04b738d2 100644
--- a/test/EmbedIO.Tests/HttpsTest.cs
+++ b/test/EmbedIO.Tests/HttpsTest.cs
@@ -3,11 +3,9 @@
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
-using System.Text;
using System.Threading.Tasks;
using EmbedIO.Tests.TestObjects;
using NUnit.Framework;
-using Swan;
namespace EmbedIO.Tests
{
@@ -18,11 +16,9 @@ public class HttpsTest
private const string HttpsUrl = "https://localhost:5555";
[Test]
+ [Platform("Win")]
public async Task OpenWebServerHttps_RetrievesIndex()
{
- if (SwanRuntime.OS != Swan.OperatingSystem.Windows)
- Assert.Ignore("Only Windows");
-
ServicePointManager.ServerCertificateValidationCallback = ValidateCertificate;
var options = new WebServerOptions()
@@ -41,11 +37,9 @@ public async Task OpenWebServerHttps_RetrievesIndex()
}
[Test]
+ [Platform(Exclude = "Win")]
public void OpenWebServerHttpsWithLinuxOrMac_ThrowsInvalidOperation()
{
- if (SwanRuntime.OS == Swan.OperatingSystem.Windows)
- Assert.Ignore("Ignore Windows");
-
Assert.Throws(() => {
var options = new WebServerOptions()
.WithUrlPrefix(HttpsUrl)
@@ -56,11 +50,9 @@ public void OpenWebServerHttpsWithLinuxOrMac_ThrowsInvalidOperation()
}
[Test]
+ [Platform("Win")]
public void OpenWebServerHttpsWithoutCert_ThrowsInvalidOperation()
{
- if (SwanRuntime.OS != Swan.OperatingSystem.Windows)
- Assert.Ignore("Only Windows");
-
var options = new WebServerOptions()
.WithUrlPrefix(HttpsUrl)
.WithAutoRegisterCertificate();
@@ -69,11 +61,9 @@ public void OpenWebServerHttpsWithoutCert_ThrowsInvalidOperation()
}
[Test]
+ [Platform("Win")]
public void OpenWebServerHttpsWithInvalidStore_ThrowsInvalidOperation()
{
- if (SwanRuntime.OS != Swan.OperatingSystem.Windows)
- Assert.Ignore("Only Windows");
-
var options = new WebServerOptions()
.WithUrlPrefix(HttpsUrl)
.WithCertificate(new X509Certificate2())
diff --git a/test/EmbedIO.Tests/IPv6Test.cs b/test/EmbedIO.Tests/IPv6Test.cs
index 5c2db09f..961eee83 100644
--- a/test/EmbedIO.Tests/IPv6Test.cs
+++ b/test/EmbedIO.Tests/IPv6Test.cs
@@ -1,8 +1,7 @@
-using NUnit.Framework;
-using Swan;
-using System;
-using System.Net.Http;
+using System.Net.Http;
using System.Threading.Tasks;
+using EmbedIO.Tests.TestObjects;
+using NUnit.Framework;
namespace EmbedIO.Tests
{
@@ -11,13 +10,11 @@ public class IPv6Test
{
[TestCase("http://[::1]:8877")]
[TestCase("http://127.0.0.1:8877")]
- public async Task WithUseIpv6_ReturnsValid(string urlTest)
+ [Platform("Win")]
+ public async Task WebServer_WithWildcardAddress_RespondsToClient(string urlTest)
{
- if (SwanRuntime.OS != Swan.OperatingSystem.Windows)
- Assert.Ignore("Only Windows");
-
var instance = new WebServer(HttpListenerMode.EmbedIO, "http://*:8877");
- instance.OnAny(ctx => ctx.SendDataAsync(DateTime.Now));
+ instance.OnAny(Resources.SendTestStringAsync);
_= instance.RunAsync();
@@ -26,13 +23,11 @@ public async Task WithUseIpv6_ReturnsValid(string urlTest)
}
[Test]
+ [Platform("Win")]
public async Task WithIpv6Loopback_ReturnsValid()
{
- if (SwanRuntime.OS != Swan.OperatingSystem.Windows)
- Assert.Ignore("Only Windows");
-
var instance = new WebServer(HttpListenerMode.EmbedIO, "http://[::1]:8877");
- instance.OnAny(ctx => ctx.SendDataAsync(DateTime.Now));
+ instance.OnAny(Resources.SendTestStringAsync);
_ = instance.RunAsync();
diff --git a/test/EmbedIO.Tests/Issues/Issue531_DefaultPort.cs b/test/EmbedIO.Tests/Issues/Issue531_DefaultPort.cs
new file mode 100644
index 00000000..cb049786
--- /dev/null
+++ b/test/EmbedIO.Tests/Issues/Issue531_DefaultPort.cs
@@ -0,0 +1,30 @@
+using System.Collections;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace EmbedIO.Tests.Issues
+{
+ [TestFixtureSource(nameof(FixtureArgs))]
+ public class Issue531_DefaultPort : EndToEndFixtureBase
+ {
+ private const string TestString = "This is a test.";
+ private static readonly IEnumerable FixtureArgs = new[] { false, true };
+
+ public Issue531_DefaultPort(bool useIPv6)
+ : base(true, useIPv6)
+ {
+ }
+
+ protected override void OnSetUp()
+ {
+ Server.WithAction("/", HttpVerbs.Get, context => context.SendStringAsync(TestString, MimeType.PlainText, WebServer.DefaultEncoding));
+ }
+
+ [Test]
+ public async Task DefaultPort_Ok()
+ {
+ var responseString = await Client.GetStringAsync(WebServerUrl);
+ Assert.AreEqual(TestString, responseString);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/EmbedIO.Tests/TestObjects/Resources.cs b/test/EmbedIO.Tests/TestObjects/Resources.cs
index 0fd09ac8..0a728a24 100644
--- a/test/EmbedIO.Tests/TestObjects/Resources.cs
+++ b/test/EmbedIO.Tests/TestObjects/Resources.cs
@@ -1,9 +1,12 @@
using System.Threading;
+using System.Threading.Tasks;
namespace EmbedIO.Tests.TestObjects
{
public static class Resources
{
+ public static readonly string TestString = "This is a test.";
+
public static readonly string SubIndex = @"
@@ -30,12 +33,17 @@ This is a placeholder
private static int _counter = 9699;
- public static string GetServerAddress()
+ public static string GetServerAddress(bool useIPv6 = false)
{
- const string serverAddress = "http://localhost:{0}/";
+ var serverAddress = useIPv6
+ ? "http://[::1]:{0}/"
+ : "http://localhost:{0}/";
Interlocked.Increment(ref _counter);
return string.Format(serverAddress, _counter);
}
+
+ public static Task SendTestStringAsync(this IHttpContext ctx)
+ => ctx.SendStringAsync(Resources.TestString, MimeType.PlainText, WebServer.DefaultEncoding);
}
}