Permalink
Please sign in to comment.
Browse files
Enable all tests in HttpsConnectionFilterTests to run on all platforms
- Move HttpClientSlim.cs to test\shared - Change HttpClientSlim to static class to simplify calling code - Add HttpClientSlim.PostAsync()
- Loading branch information...
Showing
with
278 additions
and 168 deletions.
- +7 −1 KestrelHttpServer.sln
- +2 −2 test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/AddressRegistrationTests.cs
- +0 −88 test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpClientSlim.cs
- +106 −0 test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpClientSlimTests.cs
- +6 −1 test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/IWebHostPortExtensions.cs
- +5 −0 test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json
- +18 −76 test/Microsoft.AspNetCore.Server.KestrelTests/HttpsConnectionFilterTests.cs
- +5 −0 test/Microsoft.AspNetCore.Server.KestrelTests/project.json
- +129 −0 test/shared/HttpClientSlim.cs
8
KestrelHttpServer.sln
4
test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/AddressRegistrationTests.cs
88
test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpClientSlim.cs
| @@ -1,88 +0,0 @@ | ||
| -// 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.Security; | ||
| -using System.Net.Sockets; | ||
| -using System.Security.Authentication; | ||
| -using System.Text; | ||
| -using System.Threading.Tasks; | ||
| - | ||
| -namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests | ||
| -{ | ||
| - // Lightweight version of HttpClient implemented using Socket and SslStream | ||
| - public class HttpClientSlim | ||
| - { | ||
| - public bool ValidateCertificate { get; set; } = true; | ||
| - | ||
| - public Task<string> GetStringAsync(string requestUri) => GetStringAsync(new Uri(requestUri)); | ||
| - | ||
| - public async Task<string> GetStringAsync(Uri requestUri) | ||
| - { | ||
| - using (var stream = await GetStream(requestUri)) | ||
| - { | ||
| - using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true)) | ||
| - { | ||
| - await writer.WriteAsync($"GET {requestUri.PathAndQuery} HTTP/1.0\r\n"); | ||
| - await writer.WriteAsync($"Host: {requestUri.Authority}\r\n"); | ||
| - await writer.WriteAsync("\r\n"); | ||
| - } | ||
| - | ||
| - using (var reader = new StreamReader(stream, Encoding.ASCII)) | ||
| - { | ||
| - var response = await reader.ReadToEndAsync(); | ||
| - var body = response.Substring(response.IndexOf("\r\n\r\n") + 4); | ||
| - return body; | ||
| - } | ||
| - } | ||
| - } | ||
| - | ||
| - private async Task<Stream> GetStream(Uri requestUri) | ||
| - { | ||
| - var socket = await GetSocket(requestUri); | ||
| - Stream 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); | ||
| - return sslStream; | ||
| - } | ||
| - else | ||
| - { | ||
| - return stream; | ||
| - } | ||
| - } | ||
| - | ||
| - private static async Task<Socket> GetSocket(Uri requestUri) | ||
| - { | ||
| - var tcs = new TaskCompletionSource<Socket>(); | ||
| - | ||
| - 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; | ||
| - } | ||
| - | ||
| - var socket = socketArgs.ConnectSocket; | ||
| - | ||
| - if (socket == null) | ||
| - { | ||
| - throw new SocketException((int)socketArgs.SocketError); | ||
| - } | ||
| - else | ||
| - { | ||
| - return socket; | ||
| - } | ||
| - } | ||
| - } | ||
| -} |
106
test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpClientSlimTests.cs
| @@ -0,0 +1,106 @@ | ||
| +// 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.Linq; | ||
| +using System.Net.Http; | ||
| +using System.Text; | ||
| +using System.Threading.Tasks; | ||
| +using Microsoft.AspNetCore.Builder; | ||
| +using Microsoft.AspNetCore.Hosting; | ||
| +using Microsoft.AspNetCore.Http; | ||
| +using Microsoft.AspNetCore.Testing; | ||
| +using Xunit; | ||
| + | ||
| +namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests | ||
| +{ | ||
| + public class HttpClientSlimTests | ||
| + { | ||
| + [Fact] | ||
| + public async Task GetStringAsyncHttp() | ||
| + { | ||
| + using (var host = StartHost()) | ||
| + { | ||
| + Assert.Equal("test", await HttpClientSlim.GetStringAsync(host.GetUri())); | ||
| + } | ||
| + } | ||
| + | ||
| + [Fact] | ||
| + public async Task GetStringAsyncHttps() | ||
| + { | ||
| + using (var host = StartHost(protocol: "https")) | ||
| + { | ||
| + Assert.Equal("test", await HttpClientSlim.GetStringAsync(host.GetUri(), validateCertificate: false)); | ||
| + } | ||
| + } | ||
| + | ||
| + [Fact] | ||
| + public async Task GetStringAsyncThrowsForErrorResponse() | ||
| + { | ||
| + using (var host = StartHost(statusCode: 500)) | ||
| + { | ||
| + await Assert.ThrowsAnyAsync<HttpRequestException>(() => HttpClientSlim.GetStringAsync(host.GetUri())); | ||
| + } | ||
| + } | ||
| + | ||
| + [Fact] | ||
| + public async Task PostAsyncHttp() | ||
| + { | ||
| + using (var host = StartHost(handler: (context) => context.Request.Body.CopyToAsync(context.Response.Body))) | ||
| + { | ||
| + Assert.Equal("test post", await HttpClientSlim.PostAsync(host.GetUri(), new StringContent("test post"))); | ||
| + } | ||
| + } | ||
| + | ||
| + [Fact] | ||
| + public async Task PostAsyncHttps() | ||
| + { | ||
| + using (var host = StartHost(protocol: "https", | ||
| + handler: (context) => context.Request.Body.CopyToAsync(context.Response.Body))) | ||
| + { | ||
| + Assert.Equal("test post", await HttpClientSlim.PostAsync(host.GetUri(), | ||
| + new StringContent("test post"), validateCertificate: false)); | ||
| + } | ||
| + } | ||
| + | ||
| + [Fact] | ||
| + public async Task PostAsyncThrowsForErrorResponse() | ||
| + { | ||
| + using (var host = StartHost(statusCode: 500)) | ||
| + { | ||
| + await Assert.ThrowsAnyAsync<HttpRequestException>( | ||
| + () => HttpClientSlim.PostAsync(host.GetUri(), new StringContent(""))); | ||
| + } | ||
| + } | ||
| + | ||
| + private IWebHost StartHost(string protocol = "http", int statusCode = 200, Func<HttpContext, Task> handler = null) | ||
| + { | ||
| + var host = new WebHostBuilder() | ||
| + .UseUrls($"{protocol}://127.0.0.1:0") | ||
| + .UseKestrel(options => | ||
| + { | ||
| + options.UseHttps(@"TestResources/testCert.pfx", "testPassword"); | ||
| + }) | ||
| + .Configure((app) => | ||
| + { | ||
| + app.Run(context => | ||
| + { | ||
| + context.Response.StatusCode = statusCode; | ||
| + if (handler == null) | ||
| + { | ||
| + return context.Response.WriteAsync("test"); | ||
| + } | ||
| + else | ||
| + { | ||
| + return handler(context); | ||
| + } | ||
| + }); | ||
| + }) | ||
| + .Build(); | ||
| + | ||
| + host.Start(); | ||
| + return host; | ||
| + } | ||
| + } | ||
| +} |
7
test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/IWebHostPortExtensions.cs
5
test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json
94
test/Microsoft.AspNetCore.Server.KestrelTests/HttpsConnectionFilterTests.cs
5
test/Microsoft.AspNetCore.Server.KestrelTests/project.json
129
test/shared/HttpClientSlim.cs
| @@ -0,0 +1,129 @@ | ||
| +// 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 Task<string> GetStringAsync(string requestUri, bool validateCertificate = true) | ||
| + => GetStringAsync(new Uri(requestUri), validateCertificate); | ||
| + | ||
| + public static async Task<string> GetStringAsync(Uri requestUri, 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($"GET {requestUri.PathAndQuery} HTTP/1.0\r\n"); | ||
| + await writer.WriteAsync($"Host: {requestUri.Authority}\r\n"); | ||
| + await writer.WriteAsync("\r\n"); | ||
| + } | ||
| + | ||
| + return await ReadResponse(stream); | ||
| + } | ||
| + } | ||
| + | ||
| + public static Task<string> PostAsync(string requestUri, HttpContent content, bool validateCertificate = true) | ||
| + => PostAsync(new Uri(requestUri), content, validateCertificate); | ||
| + | ||
| + public static async Task<string> 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"); | ||
| + await writer.WriteAsync($"Host: {requestUri.Authority}\r\n"); | ||
| + await writer.WriteAsync($"Content-Type: {content.Headers.ContentType}\r\n"); | ||
| + await writer.WriteAsync($"Content-Length: {content.Headers.ContentLength}\r\n"); | ||
| + await writer.WriteAsync("\r\n"); | ||
| + } | ||
| + | ||
| + await content.CopyToAsync(stream); | ||
| + | ||
| + return await ReadResponse(stream); | ||
| + } | ||
| + } | ||
| + | ||
| + private static async Task<string> ReadResponse(Stream stream) | ||
| + { | ||
| + using (var reader = new StreamReader(stream, Encoding.ASCII, detectEncodingFromByteOrderMarks: true, | ||
| + bufferSize: 1024, leaveOpen: true)) | ||
| + { | ||
| + var response = await reader.ReadToEndAsync(); | ||
| + | ||
| + 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<Stream> GetStream(Uri requestUri, bool validateCertificate) | ||
| + { | ||
| + var socket = await GetSocket(requestUri); | ||
| + Stream 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); | ||
| + return sslStream; | ||
| + } | ||
| + else | ||
| + { | ||
| + return stream; | ||
| + } | ||
| + } | ||
| + | ||
| + private static async Task<Socket> GetSocket(Uri requestUri) | ||
| + { | ||
| + var tcs = new TaskCompletionSource<Socket>(); | ||
| + | ||
| + 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; | ||
| + } | ||
| + | ||
| + var socket = socketArgs.ConnectSocket; | ||
| + | ||
| + if (socket == null) | ||
| + { | ||
| + throw new SocketException((int)socketArgs.SocketError); | ||
| + } | ||
| + else | ||
| + { | ||
| + return socket; | ||
| + } | ||
| + } | ||
| + } | ||
| +} |
0 comments on commit
41e50ba