3
3
4
4
using System ;
5
5
using System . Collections . Generic ;
6
+ using System . Diagnostics ;
6
7
using System . IO ;
7
8
using System . Linq ;
8
9
using System . Net ;
11
12
using Microsoft . AspNetCore . Hosting . Server . Features ;
12
13
using Microsoft . AspNetCore . Protocols ;
13
14
using Microsoft . AspNetCore . Server . Kestrel . Core . Internal . Infrastructure ;
15
+ using Microsoft . AspNetCore . Server . Kestrel . Transport . Abstractions . Internal ;
14
16
using Microsoft . Extensions . Logging ;
15
17
16
18
namespace Microsoft . AspNetCore . Server . Kestrel . Core . Internal
@@ -109,9 +111,6 @@ protected internal static bool TryCreateIPEndPoint(ServerAddress address, out IP
109
111
return true ;
110
112
}
111
113
112
- private static Task BindEndpointAsync ( IPEndPoint endpoint , AddressBindContext context )
113
- => BindEndpointAsync ( new ListenOptions ( endpoint ) , context ) ;
114
-
115
114
private static async Task BindEndpointAsync ( ListenOptions endpoint , AddressBindContext context )
116
115
{
117
116
try
@@ -122,12 +121,13 @@ private static async Task BindEndpointAsync(ListenOptions endpoint, AddressBindC
122
121
{
123
122
throw new IOException ( CoreStrings . FormatEndpointAlreadyInUse ( endpoint ) , ex ) ;
124
123
}
125
-
126
124
context . ListenOptions . Add ( endpoint ) ;
127
125
}
128
126
129
- private static async Task BindLocalhostAsync ( ServerAddress address , AddressBindContext context , bool https )
127
+ private static async Task BindLocalhostAsync ( ListenOptions listenOptions , AddressBindContext context )
130
128
{
129
+ var address = ServerAddress . FromUrl ( listenOptions . Prefix ) ;
130
+ Debug . Assert ( string . Equals ( address . Host , "localhost" , StringComparison . OrdinalIgnoreCase ) ) ;
131
131
if ( address . Port == 0 )
132
132
{
133
133
throw new InvalidOperationException ( CoreStrings . DynamicPortOnLocalhostNotSupported ) ;
@@ -137,14 +137,9 @@ private static async Task BindLocalhostAsync(ServerAddress address, AddressBindC
137
137
138
138
try
139
139
{
140
- var options = new ListenOptions ( new IPEndPoint ( IPAddress . Loopback , address . Port ) ) ;
140
+ var options = listenOptions . CloneAs ( ListenType . IPEndPoint ) ;
141
+ options . IPEndPoint = new IPEndPoint ( IPAddress . Loopback , address . Port ) ;
141
142
await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
142
-
143
- if ( https )
144
- {
145
- options . KestrelServerOptions = context . ServerOptions ;
146
- context . DefaultHttpsProvider . ConfigureHttps ( options ) ;
147
- }
148
143
}
149
144
catch ( Exception ex ) when ( ! ( ex is IOException ) )
150
145
{
@@ -154,14 +149,9 @@ private static async Task BindLocalhostAsync(ServerAddress address, AddressBindC
154
149
155
150
try
156
151
{
157
- var options = new ListenOptions ( new IPEndPoint ( IPAddress . IPv6Loopback , address . Port ) ) ;
152
+ var options = listenOptions . CloneAs ( ListenType . IPEndPoint ) ;
153
+ options . IPEndPoint = new IPEndPoint ( IPAddress . IPv6Loopback , address . Port ) ;
158
154
await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
159
-
160
- if ( https )
161
- {
162
- options . KestrelServerOptions = context . ServerOptions ;
163
- context . DefaultHttpsProvider . ConfigureHttps ( options ) ;
164
- }
165
155
}
166
156
catch ( Exception ex ) when ( ! ( ex is IOException ) )
167
157
{
@@ -179,69 +169,81 @@ private static async Task BindLocalhostAsync(ServerAddress address, AddressBindC
179
169
context . Addresses . Add ( address . ToString ( ) ) ;
180
170
}
181
171
182
- private static async Task BindAddressAsync ( string address , AddressBindContext context )
172
+ private static Task BindAddressAsync ( string address , AddressBindContext context )
173
+ {
174
+ return BindAddressAsync ( new ListenOptions ( ListenType . Prefix )
175
+ {
176
+ Prefix = address ,
177
+ KestrelServerOptions = context . ServerOptions ,
178
+ } , context ) ;
179
+ }
180
+
181
+ private static async Task BindAddressAsync ( ListenOptions listenOptions , AddressBindContext context )
183
182
{
184
- var parsedAddress = ServerAddress . FromUrl ( address ) ;
185
- var https = false ;
183
+ var parsedAddress = ServerAddress . FromUrl ( listenOptions . Prefix ) ;
184
+ var addHttps = false ;
186
185
187
186
if ( parsedAddress . Scheme . Equals ( "https" , StringComparison . OrdinalIgnoreCase ) )
188
187
{
189
- https = true ;
188
+ addHttps = true ;
190
189
}
191
190
else if ( ! parsedAddress . Scheme . Equals ( "http" , StringComparison . OrdinalIgnoreCase ) )
192
191
{
193
- throw new InvalidOperationException ( CoreStrings . FormatUnsupportedAddressScheme ( address ) ) ;
192
+ throw new InvalidOperationException ( CoreStrings . FormatUnsupportedAddressScheme ( listenOptions . Prefix ) ) ;
193
+ }
194
+
195
+ // Https may already be configured for this endpoint
196
+ if ( addHttps && ! listenOptions . ConnectionAdapters . Any ( f => f . IsHttps ) )
197
+ {
198
+ listenOptions . KestrelServerOptions = context . ServerOptions ;
199
+ context . DefaultHttpsProvider . ConfigureHttps ( listenOptions ) ;
194
200
}
195
201
196
202
if ( ! string . IsNullOrEmpty ( parsedAddress . PathBase ) )
197
203
{
198
204
throw new InvalidOperationException ( CoreStrings . FormatConfigurePathBaseFromMethodCall ( $ "{ nameof ( IApplicationBuilder ) } .UsePathBase()") ) ;
199
205
}
200
206
201
- ListenOptions options = null ;
202
207
if ( parsedAddress . IsUnixPipe )
203
208
{
204
- options = new ListenOptions ( parsedAddress . UnixPipePath ) ;
205
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
206
- context . Addresses . Add ( options . GetDisplayName ( ) ) ;
209
+ listenOptions . Type = ListenType . SocketPath ;
210
+ listenOptions . SocketPath = parsedAddress . UnixPipePath ;
211
+ await BindEndpointAsync ( listenOptions , context ) . ConfigureAwait ( false ) ;
212
+ context . Addresses . Add ( listenOptions . GetDisplayName ( ) ) ;
207
213
}
208
214
else if ( string . Equals ( parsedAddress . Host , "localhost" , StringComparison . OrdinalIgnoreCase ) )
209
215
{
210
216
// "localhost" for both IPv4 and IPv6 can't be represented as an IPEndPoint.
211
- await BindLocalhostAsync ( parsedAddress , context , https ) . ConfigureAwait ( false ) ;
217
+ await BindLocalhostAsync ( listenOptions , context ) . ConfigureAwait ( false ) ;
212
218
}
213
219
else
214
220
{
215
221
if ( TryCreateIPEndPoint ( parsedAddress , out var endpoint ) )
216
222
{
217
- options = new ListenOptions ( endpoint ) ;
218
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
223
+ listenOptions . Type = ListenType . IPEndPoint ;
224
+ listenOptions . IPEndPoint = endpoint ;
225
+ await BindEndpointAsync ( listenOptions , context ) . ConfigureAwait ( false ) ;
219
226
}
220
227
else
221
228
{
222
229
// when address is 'http://hostname:port', 'http://*:port', or 'http://+:port'
223
230
try
224
231
{
225
- options = new ListenOptions ( new IPEndPoint ( IPAddress . IPv6Any , parsedAddress . Port ) ) ;
226
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
232
+ listenOptions . Type = ListenType . IPEndPoint ;
233
+ listenOptions . IPEndPoint = new IPEndPoint ( IPAddress . IPv6Any , parsedAddress . Port ) ;
234
+ await BindEndpointAsync ( listenOptions , context ) . ConfigureAwait ( false ) ;
227
235
}
228
236
catch ( Exception ex ) when ( ! ( ex is IOException ) )
229
237
{
230
238
context . Logger . LogDebug ( CoreStrings . FormatFallbackToIPv4Any ( parsedAddress . Port ) ) ;
231
239
232
240
// for machines that do not support IPv6
233
- options = new ListenOptions ( new IPEndPoint ( IPAddress . Any , parsedAddress . Port ) ) ;
234
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
241
+ listenOptions . IPEndPoint = new IPEndPoint ( IPAddress . Any , parsedAddress . Port ) ;
242
+ await BindEndpointAsync ( listenOptions , context ) . ConfigureAwait ( false ) ;
235
243
}
236
244
}
237
245
238
- context . Addresses . Add ( options . GetDisplayName ( ) ) ;
239
- }
240
-
241
- if ( https && options != null )
242
- {
243
- options . KestrelServerOptions = context . ServerOptions ;
244
- context . DefaultHttpsProvider . ConfigureHttps ( options ) ;
246
+ context . Addresses . Add ( listenOptions . GetDisplayName ( ) ) ;
245
247
}
246
248
}
247
249
@@ -256,7 +258,11 @@ public async Task BindAsync(AddressBindContext context)
256
258
{
257
259
context . Logger . LogDebug ( CoreStrings . BindingToDefaultAddress , Constants . DefaultServerAddress ) ;
258
260
259
- await BindLocalhostAsync ( ServerAddress . FromUrl ( Constants . DefaultServerAddress ) , context , https : false ) . ConfigureAwait ( false ) ;
261
+ await BindLocalhostAsync ( new ListenOptions ( ListenType . Prefix )
262
+ {
263
+ Prefix = Constants . DefaultServerAddress ,
264
+ KestrelServerOptions = context . ServerOptions ,
265
+ } , context ) . ConfigureAwait ( false ) ;
260
266
}
261
267
}
262
268
@@ -308,9 +314,16 @@ public virtual async Task BindAsync(AddressBindContext context)
308
314
{
309
315
foreach ( var endpoint in _endpoints )
310
316
{
311
- await BindEndpointAsync ( endpoint , context ) . ConfigureAwait ( false ) ;
317
+ if ( endpoint . Type == ListenType . Prefix )
318
+ {
319
+ await BindAddressAsync ( endpoint , context ) ;
320
+ }
321
+ else
322
+ {
323
+ await BindEndpointAsync ( endpoint , context ) . ConfigureAwait ( false ) ;
312
324
313
- context . Addresses . Add ( endpoint . GetDisplayName ( ) ) ;
325
+ context . Addresses . Add ( endpoint . GetDisplayName ( ) ) ;
326
+ }
314
327
}
315
328
}
316
329
}
0 commit comments