diff --git a/samples/AppSettings/AppSettings.csproj b/samples/AppSettings/AppSettings.csproj
index bf6be606f3..621da3c9ca 100644
--- a/samples/AppSettings/AppSettings.csproj
+++ b/samples/AppSettings/AppSettings.csproj
@@ -16,10 +16,8 @@
-
diff --git a/samples/AppSettings/appsettings.json b/samples/AppSettings/appsettings.json
index fac810ec12..ab315a0242 100644
--- a/samples/AppSettings/appsettings.json
+++ b/samples/AppSettings/appsettings.json
@@ -27,8 +27,6 @@
"Certificate": {
"Source": "File",
"Path": "testCert.pfx",
- // TODO: remove when dotnet user-secrets is working again
- "Password": "testPassword"
}
},
// Add testCert.pfx to the current user's certificate store to enable this scenario.
@@ -48,8 +46,6 @@
"TestCert": {
"Source": "File",
"Path": "testCert.pfx",
- // TODO: remove when dotnet user-secrets is working again
- "Password": "testPassword"
},
// Add testCert.pfx to the current user's certificate store to enable this scenario.
//"TestCertInStore": {
diff --git a/test/Microsoft.AspNetCore.FunctionalTests/HttpClientSlim.cs b/test/Microsoft.AspNetCore.FunctionalTests/HttpClientSlim.cs
new file mode 100644
index 0000000000..a85b03aa40
--- /dev/null
+++ b/test/Microsoft.AspNetCore.FunctionalTests/HttpClientSlim.cs
@@ -0,0 +1,130 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Http;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.Testing
+{
+ // Lightweight version of HttpClient implemented using Socket and SslStream
+ public static class HttpClientSlim
+ {
+ public static async Task GetStringAsync(string requestUri, bool validateCertificate = true)
+ => await GetStringAsync(new Uri(requestUri), validateCertificate).ConfigureAwait(false);
+
+ public static async Task GetStringAsync(Uri requestUri, bool validateCertificate = true)
+ {
+ using (var stream = await GetStream(requestUri, validateCertificate).ConfigureAwait(false))
+ {
+ using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true))
+ {
+ await writer.WriteAsync($"GET {requestUri.PathAndQuery} HTTP/1.0\r\n").ConfigureAwait(false);
+ await writer.WriteAsync($"Host: {requestUri.Authority}\r\n").ConfigureAwait(false);
+ await writer.WriteAsync("\r\n").ConfigureAwait(false);
+ }
+
+ return await ReadResponse(stream).ConfigureAwait(false);
+ }
+ }
+
+ public static async Task PostAsync(string requestUri, HttpContent content, bool validateCertificate = true)
+ => await PostAsync(new Uri(requestUri), content, validateCertificate).ConfigureAwait(false);
+
+ public static async Task PostAsync(Uri requestUri, HttpContent content, bool validateCertificate = true)
+ {
+ using (var stream = await GetStream(requestUri, validateCertificate))
+ {
+ using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true))
+ {
+ await writer.WriteAsync($"POST {requestUri.PathAndQuery} HTTP/1.0\r\n").ConfigureAwait(false);
+ await writer.WriteAsync($"Host: {requestUri.Authority}\r\n").ConfigureAwait(false);
+ await writer.WriteAsync($"Content-Type: {content.Headers.ContentType}\r\n").ConfigureAwait(false);
+ await writer.WriteAsync($"Content-Length: {content.Headers.ContentLength}\r\n").ConfigureAwait(false);
+ await writer.WriteAsync("\r\n").ConfigureAwait(false);
+ }
+
+ await content.CopyToAsync(stream).ConfigureAwait(false);
+
+ return await ReadResponse(stream).ConfigureAwait(false);
+ }
+ }
+
+ private static async Task ReadResponse(Stream stream)
+ {
+ using (var reader = new StreamReader(stream, Encoding.ASCII, detectEncodingFromByteOrderMarks: true,
+ bufferSize: 1024, leaveOpen: true))
+ {
+ var response = await reader.ReadToEndAsync().ConfigureAwait(false);
+
+ var status = GetStatus(response);
+ new HttpResponseMessage(status).EnsureSuccessStatusCode();
+
+ var body = response.Substring(response.IndexOf("\r\n\r\n") + 4);
+ return body;
+ }
+
+ }
+
+ private static HttpStatusCode GetStatus(string response)
+ {
+ var statusStart = response.IndexOf(' ') + 1;
+ var statusEnd = response.IndexOf(' ', statusStart) - 1;
+ var statusLength = statusEnd - statusStart + 1;
+ return (HttpStatusCode)int.Parse(response.Substring(statusStart, statusLength));
+ }
+
+ private static async Task GetStream(Uri requestUri, bool validateCertificate)
+ {
+ var socket = await GetSocket(requestUri);
+ var stream = new NetworkStream(socket, ownsSocket: true);
+
+ if (requestUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase))
+ {
+ var sslStream = new SslStream(stream, leaveInnerStreamOpen: false, userCertificateValidationCallback:
+ validateCertificate ? null : (RemoteCertificateValidationCallback)((a, b, c, d) => true));
+
+ await sslStream.AuthenticateAsClientAsync(requestUri.Host, clientCertificates: null,
+ enabledSslProtocols: SslProtocols.Tls11 | SslProtocols.Tls12,
+ checkCertificateRevocation: validateCertificate).ConfigureAwait(false);
+ return sslStream;
+ }
+ else
+ {
+ return stream;
+ }
+ }
+
+ public static async Task GetSocket(Uri requestUri)
+ {
+ var tcs = new TaskCompletionSource();
+
+ var socketArgs = new SocketAsyncEventArgs();
+ socketArgs.RemoteEndPoint = new DnsEndPoint(requestUri.DnsSafeHost, requestUri.Port);
+ socketArgs.Completed += (s, e) => tcs.TrySetResult(e.ConnectSocket);
+
+ // Must use static ConnectAsync(), since instance Connect() does not support DNS names on OSX/Linux.
+ if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, socketArgs))
+ {
+ await tcs.Task.ConfigureAwait(false);
+ }
+
+ var socket = socketArgs.ConnectSocket;
+
+ if (socket == null)
+ {
+ throw new SocketException((int)socketArgs.SocketError);
+ }
+ else
+ {
+ return socket;
+ }
+ }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.FunctionalTests/Microsoft.AspNetCore.FunctionalTests.csproj b/test/Microsoft.AspNetCore.FunctionalTests/Microsoft.AspNetCore.FunctionalTests.csproj
index 13d57e6616..e2596080ea 100644
--- a/test/Microsoft.AspNetCore.FunctionalTests/Microsoft.AspNetCore.FunctionalTests.csproj
+++ b/test/Microsoft.AspNetCore.FunctionalTests/Microsoft.AspNetCore.FunctionalTests.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/test/Microsoft.AspNetCore.FunctionalTests/TestArtifacts/Certificate.pfx b/test/Microsoft.AspNetCore.FunctionalTests/TestArtifacts/Certificate.pfx
deleted file mode 100644
index c792c52248..0000000000
Binary files a/test/Microsoft.AspNetCore.FunctionalTests/TestArtifacts/Certificate.pfx and /dev/null differ
diff --git a/test/Microsoft.AspNetCore.FunctionalTests/WebHostFunctionalTests.cs b/test/Microsoft.AspNetCore.FunctionalTests/WebHostFunctionalTests.cs
index 00e1fbfba6..fa24b34684 100644
--- a/test/Microsoft.AspNetCore.FunctionalTests/WebHostFunctionalTests.cs
+++ b/test/Microsoft.AspNetCore.FunctionalTests/WebHostFunctionalTests.cs
@@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Xunit;
@@ -134,7 +135,8 @@ namespace Microsoft.AspNetCore.Tests
""Certificates"": {
""TestCert"": {
""Source"": ""File"",
- ""Path"": ""TestArtifacts/Certificate.pfx""
+ ""Path"": ""testCert.pfx"",
+ ""Password"": ""testPassword""
}
}
}
@@ -143,13 +145,8 @@ namespace Microsoft.AspNetCore.Tests
{
var port = GetWebHostPort(webHost);
- Assert.NotEqual(0, port);
-
- using (var client = new HttpClient(new HttpClientHandler { ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true }))
- {
- var response = await client.GetAsync($"https://127.0.0.1:{port}");
- response.EnsureSuccessStatusCode();
- }
+ var response = await HttpClientSlim.GetStringAsync($"https://127.0.0.1:{port}", validateCertificate: false);
+ Assert.Equal("Hello, World!", response);
}
}
finally
@@ -172,7 +169,8 @@ namespace Microsoft.AspNetCore.Tests
""Port"": 0,
""Certificate"": {
""Source"": ""File"",
- ""Path"": ""TestArtifacts/Certificate.pfx"",
+ ""Path"": ""testCert.pfx"",
+ ""Password"": ""testPassword""
}
}
}
@@ -183,13 +181,8 @@ namespace Microsoft.AspNetCore.Tests
{
var port = GetWebHostPort(webHost);
- Assert.NotEqual(0, port);
-
- using (var client = new HttpClient(new HttpClientHandler { ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true }))
- {
- var response = await client.GetAsync($"https://127.0.0.1:{port}");
- response.EnsureSuccessStatusCode();
- }
+ var response = await HttpClientSlim.GetStringAsync($"https://127.0.0.1:{port}", validateCertificate: false);
+ Assert.Equal("Hello, World!", response);
}
}
finally
diff --git a/test/Microsoft.AspNetCore.FunctionalTests/testCert.pfx b/test/Microsoft.AspNetCore.FunctionalTests/testCert.pfx
new file mode 100644
index 0000000000..7118908c2d
Binary files /dev/null and b/test/Microsoft.AspNetCore.FunctionalTests/testCert.pfx differ