diff --git a/examples/WireMock.Net.Console.NETCoreApp3WithCertificate/Program.cs b/examples/WireMock.Net.Console.NETCoreApp3WithCertificate/Program.cs index 54878ddc..1c73463c 100644 --- a/examples/WireMock.Net.Console.NETCoreApp3WithCertificate/Program.cs +++ b/examples/WireMock.Net.Console.NETCoreApp3WithCertificate/Program.cs @@ -1,4 +1,4 @@ -using WireMock.Logging; +using WireMock.Logging; using WireMock.Server; using WireMock.Settings; @@ -24,7 +24,6 @@ namespace WireMock.Net.Console.NETCoreApp3WithCertificate // X509CertificateFilePath = "example.pfx", // X509CertificatePassword = "wiremock" } - }); System.Console.WriteLine("WireMockServer listening at {0}", string.Join(",", server.Urls)); diff --git a/src/WireMock.Net/Owin/HostUrlOptions.cs b/src/WireMock.Net/Owin/HostUrlOptions.cs index 1e515043..8d514e8f 100644 --- a/src/WireMock.Net/Owin/HostUrlOptions.cs +++ b/src/WireMock.Net/Owin/HostUrlOptions.cs @@ -12,8 +12,6 @@ internal class HostUrlOptions public int? Port { get; set; } - public int? HttpsPort { get; set; } - public HostingScheme HostingScheme { get; set; } public IReadOnlyList GetDetails() diff --git a/src/WireMock.Net/Server/WireMockServer.cs b/src/WireMock.Net/Server/WireMockServer.cs index 0b982f9b..90fc19e2 100644 --- a/src/WireMock.Net/Server/WireMockServer.cs +++ b/src/WireMock.Net/Server/WireMockServer.cs @@ -141,6 +141,31 @@ public partial class WireMockServer : IWireMockServer return client; } + /// + /// Create a which can be used to call this instance. + /// + /// The inner handler represents the destination of the HTTP message channel. + /// An ordered list of System.Net.Http.DelegatingHandler instances to be invoked + /// as an System.Net.Http.HttpRequestMessage travels from the System.Net.Http.HttpClient + /// to the network and an System.Net.Http.HttpResponseMessage travels from the network + /// back to System.Net.Http.HttpClient. The handlers are invoked in a top-down fashion. + /// That is, the first entry is invoked first for an outbound request message but + /// last for an inbound response message. + /// + /// + [PublicAPI] + public HttpClient CreateClient(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers) + { + if (!IsStarted) + { + throw new InvalidOperationException("Unable to create HttpClient because the service is not started."); + } + + var client = HttpClientFactory2.Create(innerHandler, handlers); + client.BaseAddress = new Uri(Url!); + return client; + } + /// /// Create s (one for each URL) which can be used to call this instance. /// The inner handler represents the destination of the HTTP message channel. diff --git a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs index 28f651bc..4aeca8f6 100644 --- a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs +++ b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs @@ -215,10 +215,13 @@ public class WireMockAssertionsTests : IDisposable { // Arrange using var server = WireMockServer.Start(); - using var client = server.CreateClient(); + using var client1 = server.CreateClient(); + + var handler = new HttpClientHandler(); + using var client2 = server.CreateClient(handler); // Act 1 - await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") + await client1.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") { Headers = { @@ -227,7 +230,7 @@ public class WireMockAssertionsTests : IDisposable }); // Act 2 - await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") + await client2.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") { Headers = { diff --git a/test/WireMock.Net.Tests/Owin/HostUrlOptionsTests.cs b/test/WireMock.Net.Tests/Owin/HostUrlOptionsTests.cs new file mode 100644 index 00000000..d52b3e65 --- /dev/null +++ b/test/WireMock.Net.Tests/Owin/HostUrlOptionsTests.cs @@ -0,0 +1,60 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using FluentAssertions; +using WireMock.Owin; +using WireMock.Types; +using Xunit; + +namespace WireMock.Net.Tests.Owin; + +[ExcludeFromCodeCoverage] +public class HostUrlOptionsTests +{ + [Fact] + public void GetDetails_WithNoUrlsAndHttpScheme_ShouldReturnCorrectDetails() + { + // Arrange + var options = new HostUrlOptions + { + HostingScheme = HostingScheme.Http, + Port = 8080 + }; + + // Act + var details = options.GetDetails(); + + // Assert + details.Should().HaveCount(1); + var detail = details.Single(); + detail.Should().Match(d => + d.Scheme == "http" && + d.Host == "localhost" && + d.Port == 8080 && + d.IsHttps == false + ); + } + + [Fact] + public void GetDetails_WithNoUrlsAndHttpsScheme_ShouldReturnCorrectDetails() + { + // Arrange + var options = new HostUrlOptions + { + HostingScheme = HostingScheme.Https, + Port = 8081 + }; + + // Act + var details = options.GetDetails(); + + // Assert + details.Should().HaveCount(1); + var detail = details.Single(); + detail.Should().Match(d => + d.Scheme == "https" && + d.Host == "localhost" && + d.Port == 8081 && + d.IsHttps == true + ); + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj index c6f56ad4..f6a3fb59 100644 --- a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj +++ b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj @@ -110,6 +110,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/test/WireMock.Net.Tests/WireMockServerTests.cs b/test/WireMock.Net.Tests/WireMockServerTests.cs index 1cd2e989..2ac9c271 100644 --- a/test/WireMock.Net.Tests/WireMockServerTests.cs +++ b/test/WireMock.Net.Tests/WireMockServerTests.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -100,6 +101,99 @@ public partial class WireMockServerTests server.Stop(); } +#if NET461_OR_GREATER || NET6_0_OR_GREATER + [Fact] + public async Task WireMockServer_Should_Support_Https() + { + // Arrange + const string body = "example"; + var path = $"/foo_{Guid.NewGuid()}"; + var settings = new WireMockServerSettings + { + UseSSL = true + }; + var server = WireMockServer.Start(settings); + + server + .Given(Request.Create() + .WithPath(path) + .UsingGet() + ) + .RespondWith(Response.Create() + .WithBody(body) + ); + + // Configure the HttpClient to trust self-signed certificates + var handler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (_, _, _, _) => true + }; + using var client = new HttpClient(handler); + + // Act + var result = await client.GetStringAsync($"{server.Url}{path}").ConfigureAwait(false); + + // Assert + result.Should().Be(body); + + server.Stop(); + } +#endif + +#if NET6_0_OR_GREATER + [Fact] + public async Task WireMockServer_When_HttpClientWithWebProxyCallsHttp_Should_Work_Correct() + { + // Arrange + const string body = "example"; + var settings = new WireMockServerSettings + { + HostingScheme = HostingScheme.Http + }; + var server = WireMockServer.Start(settings); + + // The response to an HTTP CONNECT method, which is used to establish a tunnel with a proxy, should typically be a 200 OK status code if the connection is successful. + // This indicates that a tunnel has been established successfully between the client and the server via the proxy. + server + .Given(Request.Create() + .UsingConnect() + ) + .RespondWith(Response.Create() + .WithBody("Connection established") + ); + + server + .Given(Request.Create() + .UsingGet() + ) + .RespondWith(Response.Create() + .WithBody(body) + ); + + var httpUrl = server.Urls.First(); + + // Act + string result; + var currentProxy = HttpClient.DefaultProxy; + try + { + HttpClient.DefaultProxy = new WebProxy(httpUrl, false); + + result = await new HttpClient().GetStringAsync(httpUrl).ConfigureAwait(false); + } + finally + { + // Revert + HttpClient.DefaultProxy = currentProxy; + } + + // Assert + result.Should().Be(body); + + server.Stop(); + } +#endif + [Fact] public async Task WireMockServer_Should_respond_a_redirect_without_body() { diff --git a/test/WireMock.Net.Tests/cert.pem b/test/WireMock.Net.Tests/cert.pem new file mode 100644 index 00000000..8f6ecc06 --- /dev/null +++ b/test/WireMock.Net.Tests/cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB9TCCAZugAwIBAgIUYH7UM/DAXzosxsT+ea2jdYvhqqMwCgYIKoZIzj0EAwIw +UDELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUtU3RhdGUxFTATBgNVBAoMDFdp +cmVNb2NrLk5ldDEVMBMGA1UEAwwMV2lyZU1vY2suTmV0MB4XDTIyMDgxMTE2MjE0 +NFoXDTMyMDYxOTE2MjE0NFowUDELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUt +U3RhdGUxFTATBgNVBAoMDFdpcmVNb2NrLk5ldDEVMBMGA1UEAwwMV2lyZU1vY2su +TmV0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE39VoI268uDuIeKmRzr9e9jgM +SGeuJTvTG7+cSXmeDymrVgIGXQgmqKA8TDXpJNrRhWMd/fpsnWu1JwJUjBmspaNT +MFEwHQYDVR0OBBYEFILL8V+fAtMnccWKGAdkx2Dh/v/TMB8GA1UdIwQYMBaAFILL +8V+fAtMnccWKGAdkx2Dh/v/TMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwID +SAAwRQIgKDLAG8OWK6GF5HV4kmWz3kp2V3yVsNK2V9Lw3dSE+YsCIQCK1EEBvuqc +0ncZV4ETVnOY23PWFOMk1VwN2aoTi5n++Q== +-----END CERTIFICATE-----