Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit 51ef5c5

Browse files
committed
Create a direct way to configure endpoints on KestrelEngine
- Replace endpoint configuration via .UseUrls() or --server.urls with Listen* methods on KestrelSerrverOptions. - Replace IConnectionFilter with IConnectionAdapter which no longer exposes ServerAddress via a context. - Simplify libuv Listener classes - Support systemd socket activation - Add docker-based test for systemd socket activation to be run on Travis
1 parent b46e48f commit 51ef5c5

File tree

82 files changed

+2054
-1472
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2054
-1472
lines changed

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
language: csharp
22
sudo: required
33
dist: trusty
4+
services:
5+
- docker
46
addons:
57
apt:
68
packages:
@@ -30,3 +32,4 @@ before_install:
3032
- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi
3133
script:
3234
- ./build.sh --quiet verify
35+
- if test '$TRAVIS_OS_NAME' != 'osx'; then bash test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/SystemdActivation/docker.sh; fi

samples/LargeResponseApp/Startup.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.IO;
5+
using System.Net;
56
using System.Text;
67
using System.Threading.Tasks;
78
using Microsoft.AspNetCore.Builder;
@@ -40,8 +41,10 @@ public void Configure(IApplicationBuilder app)
4041
public static void Main(string[] args)
4142
{
4243
var host = new WebHostBuilder()
43-
.UseKestrel()
44-
.UseUrls("http://localhost:5001/")
44+
.UseKestrel(options =>
45+
{
46+
options.Listen(IPAddress.Loopback, 5001);
47+
})
4548
.UseContentRoot(Directory.GetCurrentDirectory())
4649
.UseStartup<Startup>()
4750
.Build();

samples/SampleApp/Startup.cs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.IO;
6+
using System.Net;
67
using Microsoft.AspNetCore.Builder;
78
using Microsoft.AspNetCore.Hosting;
89
using Microsoft.AspNetCore.Http;
@@ -33,24 +34,33 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
3334

3435
public static void Main(string[] args)
3536
{
36-
var host = new WebHostBuilder()
37-
.UseKestrel(options =>
37+
var hostBuilder = new WebHostBuilder().UseKestrel(options =>
38+
{
39+
options.Listen(IPAddress.Loopback, 5000, listenOptions =>
40+
{
41+
// Uncomment the following to enable Nagle's algorithm for this endpoint.
42+
//listenOptions.NoDelay = false;
43+
44+
listenOptions.UseConnectionLogging();
45+
});
46+
options.Listen(IPAddress.Loopback, 5001, listenOptions =>
3847
{
39-
// options.ThreadCount = 4;
40-
options.NoDelay = true;
41-
options.UseHttps("testCert.pfx", "testPassword");
42-
options.UseConnectionLogging();
43-
})
44-
.UseUrls("http://localhost:5000", "https://localhost:5001")
45-
.UseContentRoot(Directory.GetCurrentDirectory())
46-
.UseStartup<Startup>()
47-
.Build();
48-
49-
// The following section should be used to demo sockets
50-
//var addresses = application.GetAddresses();
51-
//addresses.Clear();
52-
//addresses.Add("http://unix:/tmp/kestrel-test.sock");
48+
listenOptions.UseHttps("testCert.pfx", "testPassword");
49+
listenOptions.UseConnectionLogging();
50+
});
51+
52+
options.UseSystemd();
53+
54+
// The following section should be used to demo sockets
55+
//options.ListenUnixSocket("http://unix:/tmp/kestrel-test.sock");
56+
57+
// Uncomment the following line to change the default number of libuv threads for all endpoints.
58+
// options.ThreadCount = 4;
59+
})
60+
.UseContentRoot(Directory.GetCurrentDirectory())
61+
.UseStartup<Startup>();
5362

63+
var host = hostBuilder.Build();
5464
host.Run();
5565
}
5666
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.IO;
6+
using System.Net.Security;
7+
using System.Security.Cryptography.X509Certificates;
8+
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Http.Features;
10+
using Microsoft.AspNetCore.Server.Kestrel.Adapter;
11+
using Microsoft.AspNetCore.Server.Kestrel.Https.Internal;
12+
using Microsoft.Extensions.Logging;
13+
14+
namespace Microsoft.AspNetCore.Server.Kestrel.Https
15+
{
16+
public class HttpsConnectionAdapter : IConnectionAdapter
17+
{
18+
private static readonly ClosedAdaptedConnection _closedAdaptedConnection = new ClosedAdaptedConnection();
19+
20+
private readonly HttpsConnectionAdapterOptions _options;
21+
private readonly ILogger _logger;
22+
23+
public HttpsConnectionAdapter(HttpsConnectionAdapterOptions options)
24+
: this(options, loggerFactory: null)
25+
{
26+
}
27+
28+
public HttpsConnectionAdapter(HttpsConnectionAdapterOptions options, ILoggerFactory loggerFactory)
29+
{
30+
if (options == null)
31+
{
32+
throw new ArgumentNullException(nameof(options));
33+
}
34+
if (options.ServerCertificate == null)
35+
{
36+
throw new ArgumentException("The server certificate parameter is required.");
37+
}
38+
39+
_options = options;
40+
_logger = loggerFactory?.CreateLogger(nameof(HttpsConnectionAdapter));
41+
}
42+
43+
public async Task<IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
44+
{
45+
SslStream sslStream;
46+
bool certificateRequired;
47+
48+
if (_options.ClientCertificateMode == ClientCertificateMode.NoCertificate)
49+
{
50+
sslStream = new SslStream(context.ConnectionStream);
51+
certificateRequired = false;
52+
}
53+
else
54+
{
55+
sslStream = new SslStream(context.ConnectionStream, leaveInnerStreamOpen: false,
56+
userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) =>
57+
{
58+
if (certificate == null)
59+
{
60+
return _options.ClientCertificateMode != ClientCertificateMode.RequireCertificate;
61+
}
62+
63+
if (_options.ClientCertificateValidation == null)
64+
{
65+
if (sslPolicyErrors != SslPolicyErrors.None)
66+
{
67+
return false;
68+
}
69+
}
70+
71+
var certificate2 = ConvertToX509Certificate2(certificate);
72+
if (certificate2 == null)
73+
{
74+
return false;
75+
}
76+
77+
if (_options.ClientCertificateValidation != null)
78+
{
79+
if (!_options.ClientCertificateValidation(certificate2, chain, sslPolicyErrors))
80+
{
81+
return false;
82+
}
83+
}
84+
85+
return true;
86+
});
87+
88+
certificateRequired = true;
89+
}
90+
91+
try
92+
{
93+
await sslStream.AuthenticateAsServerAsync(_options.ServerCertificate, certificateRequired,
94+
_options.SslProtocols, _options.CheckCertificateRevocation);
95+
}
96+
catch (IOException ex)
97+
{
98+
_logger?.LogInformation(1, ex, "Failed to authenticate HTTPS connection.");
99+
sslStream.Dispose();
100+
return _closedAdaptedConnection;
101+
}
102+
103+
return new HttpsAdaptedConnection(sslStream);
104+
}
105+
106+
private static X509Certificate2 ConvertToX509Certificate2(X509Certificate certificate)
107+
{
108+
if (certificate == null)
109+
{
110+
return null;
111+
}
112+
113+
X509Certificate2 certificate2 = certificate as X509Certificate2;
114+
if (certificate2 != null)
115+
{
116+
return certificate2;
117+
}
118+
119+
#if NETSTANDARD1_3
120+
// conversion X509Certificate to X509Certificate2 not supported
121+
// https://github.com/dotnet/corefx/issues/4510
122+
return null;
123+
#else
124+
return new X509Certificate2(certificate);
125+
#endif
126+
}
127+
128+
private class HttpsAdaptedConnection : IAdaptedConnection
129+
{
130+
private readonly SslStream _sslStream;
131+
132+
public HttpsAdaptedConnection(SslStream sslStream)
133+
{
134+
_sslStream = sslStream;
135+
}
136+
137+
public Stream ConnectionStream => _sslStream;
138+
139+
public void PrepareRequest(IFeatureCollection requestFeatures)
140+
{
141+
var clientCertificate = ConvertToX509Certificate2(_sslStream.RemoteCertificate);
142+
if (clientCertificate != null)
143+
{
144+
requestFeatures.Set<ITlsConnectionFeature>(new TlsConnectionFeature { ClientCertificate = clientCertificate });
145+
}
146+
147+
requestFeatures.Get<IHttpRequestFeature>().Scheme = "https";
148+
}
149+
}
150+
151+
private class ClosedAdaptedConnection : IAdaptedConnection
152+
{
153+
public Stream ConnectionStream { get; } = new ClosedStream();
154+
155+
public void PrepareRequest(IFeatureCollection requestFeatures)
156+
{
157+
}
158+
}
159+
}
160+
}

src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionFilterOptions.cs renamed to src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionAdapterOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
namespace Microsoft.AspNetCore.Server.Kestrel.Https
1010
{
11-
public class HttpsConnectionFilterOptions
11+
public class HttpsConnectionAdapterOptions
1212
{
13-
public HttpsConnectionFilterOptions()
13+
public HttpsConnectionAdapterOptions()
1414
{
1515
ClientCertificateMode = ClientCertificateMode.NoCertificate;
1616
SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11;

0 commit comments

Comments
 (0)