@@ -47,17 +47,6 @@ public static async Task BindAsync(IServerAddressesFeature addresses,
47
47
await strategy . BindAsync ( context ) . ConfigureAwait ( false ) ;
48
48
}
49
49
50
- private class AddressBindContext
51
- {
52
- public ICollection < string > Addresses { get ; set ; }
53
- public List < ListenOptions > ListenOptions { get ; set ; }
54
- public KestrelServerOptions ServerOptions { get ; set ; }
55
- public ILogger Logger { get ; set ; }
56
- public IDefaultHttpsProvider DefaultHttpsProvider { get ; set ; }
57
-
58
- public Func < ListenOptions , Task > CreateBinding { get ; set ; }
59
- }
60
-
61
50
private static IStrategy CreateStrategy ( ListenOptions [ ] listenOptions , string [ ] addresses , bool preferAddresses )
62
51
{
63
52
var hasListenOptions = listenOptions . Length > 0 ;
@@ -109,10 +98,7 @@ protected internal static bool TryCreateIPEndPoint(ServerAddress address, out IP
109
98
return true ;
110
99
}
111
100
112
- private static Task BindEndpointAsync ( IPEndPoint endpoint , AddressBindContext context )
113
- => BindEndpointAsync ( new ListenOptions ( endpoint ) , context ) ;
114
-
115
- private static async Task BindEndpointAsync ( ListenOptions endpoint , AddressBindContext context )
101
+ internal static async Task BindEndpointAsync ( ListenOptions endpoint , AddressBindContext context )
116
102
{
117
103
try
118
104
{
@@ -126,60 +112,7 @@ private static async Task BindEndpointAsync(ListenOptions endpoint, AddressBindC
126
112
context . ListenOptions . Add ( endpoint ) ;
127
113
}
128
114
129
- private static async Task BindLocalhostAsync ( ServerAddress address , AddressBindContext context , bool https )
130
- {
131
- if ( address . Port == 0 )
132
- {
133
- throw new InvalidOperationException ( CoreStrings . DynamicPortOnLocalhostNotSupported ) ;
134
- }
135
-
136
- var exceptions = new List < Exception > ( ) ;
137
-
138
- try
139
- {
140
- var options = new ListenOptions ( new IPEndPoint ( IPAddress . Loopback , address . Port ) ) ;
141
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
142
-
143
- if ( https )
144
- {
145
- options . KestrelServerOptions = context . ServerOptions ;
146
- context . DefaultHttpsProvider . ConfigureHttps ( options ) ;
147
- }
148
- }
149
- catch ( Exception ex ) when ( ! ( ex is IOException ) )
150
- {
151
- context . Logger . LogWarning ( 0 , CoreStrings . NetworkInterfaceBindingFailed , address , "IPv4 loopback" , ex . Message ) ;
152
- exceptions . Add ( ex ) ;
153
- }
154
-
155
- try
156
- {
157
- var options = new ListenOptions ( new IPEndPoint ( IPAddress . IPv6Loopback , address . Port ) ) ;
158
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
159
-
160
- if ( https )
161
- {
162
- options . KestrelServerOptions = context . ServerOptions ;
163
- context . DefaultHttpsProvider . ConfigureHttps ( options ) ;
164
- }
165
- }
166
- catch ( Exception ex ) when ( ! ( ex is IOException ) )
167
- {
168
- context . Logger . LogWarning ( 0 , CoreStrings . NetworkInterfaceBindingFailed , address , "IPv6 loopback" , ex . Message ) ;
169
- exceptions . Add ( ex ) ;
170
- }
171
-
172
- if ( exceptions . Count == 2 )
173
- {
174
- throw new IOException ( CoreStrings . FormatAddressBindingFailed ( address ) , new AggregateException ( exceptions ) ) ;
175
- }
176
-
177
- // If StartLocalhost doesn't throw, there is at least one listener.
178
- // The port cannot change for "localhost".
179
- context . Addresses . Add ( address . ToString ( ) ) ;
180
- }
181
-
182
- private static async Task BindAddressAsync ( string address , AddressBindContext context )
115
+ internal static ListenOptions ParseAddress ( string address , KestrelServerOptions serverOptions , IDefaultHttpsProvider defaultHttpsProvider )
183
116
{
184
117
var parsedAddress = ServerAddress . FromUrl ( address ) ;
185
118
var https = false ;
@@ -202,47 +135,29 @@ private static async Task BindAddressAsync(string address, AddressBindContext co
202
135
if ( parsedAddress . IsUnixPipe )
203
136
{
204
137
options = new ListenOptions ( parsedAddress . UnixPipePath ) ;
205
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
206
- context . Addresses . Add ( options . GetDisplayName ( ) ) ;
207
138
}
208
139
else if ( string . Equals ( parsedAddress . Host , "localhost" , StringComparison . OrdinalIgnoreCase ) )
209
140
{
210
141
// "localhost" for both IPv4 and IPv6 can't be represented as an IPEndPoint.
211
- await BindLocalhostAsync ( parsedAddress , context , https ) . ConfigureAwait ( false ) ;
142
+ options = new LocalhostListenOptions ( parsedAddress . Port ) ;
143
+ }
144
+ else if ( TryCreateIPEndPoint ( parsedAddress , out var endpoint ) )
145
+ {
146
+ options = new ListenOptions ( endpoint ) ;
212
147
}
213
148
else
214
149
{
215
- if ( TryCreateIPEndPoint ( parsedAddress , out var endpoint ) )
216
- {
217
- options = new ListenOptions ( endpoint ) ;
218
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
219
- }
220
- else
221
- {
222
- // when address is 'http://hostname:port', 'http://*:port', or 'http://+:port'
223
- try
224
- {
225
- options = new ListenOptions ( new IPEndPoint ( IPAddress . IPv6Any , parsedAddress . Port ) ) ;
226
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
227
- }
228
- catch ( Exception ex ) when ( ! ( ex is IOException ) )
229
- {
230
- context . Logger . LogDebug ( CoreStrings . FormatFallbackToIPv4Any ( parsedAddress . Port ) ) ;
231
-
232
- // for machines that do not support IPv6
233
- options = new ListenOptions ( new IPEndPoint ( IPAddress . Any , parsedAddress . Port ) ) ;
234
- await BindEndpointAsync ( options , context ) . ConfigureAwait ( false ) ;
235
- }
236
- }
237
-
238
- context . Addresses . Add ( options . GetDisplayName ( ) ) ;
150
+ // when address is 'http://hostname:port', 'http://*:port', or 'http://+:port'
151
+ options = new AnyIPListenOptions ( parsedAddress . Port ) ;
239
152
}
240
153
241
- if ( https && options != null )
154
+ if ( https )
242
155
{
243
- options . KestrelServerOptions = context . ServerOptions ;
244
- context . DefaultHttpsProvider . ConfigureHttps ( options ) ;
156
+ options . KestrelServerOptions = serverOptions ;
157
+ defaultHttpsProvider . ConfigureHttps ( options ) ;
245
158
}
159
+
160
+ return options ;
246
161
}
247
162
248
163
private interface IStrategy
@@ -256,7 +171,8 @@ public async Task BindAsync(AddressBindContext context)
256
171
{
257
172
context . Logger . LogDebug ( CoreStrings . BindingToDefaultAddress , Constants . DefaultServerAddress ) ;
258
173
259
- await BindLocalhostAsync ( ServerAddress . FromUrl ( Constants . DefaultServerAddress ) , context , https : false ) . ConfigureAwait ( false ) ;
174
+ await ParseAddress ( Constants . DefaultServerAddress , context . ServerOptions , context . DefaultHttpsProvider )
175
+ . BindAsync ( context ) . ConfigureAwait ( false ) ;
260
176
}
261
177
}
262
178
@@ -308,9 +224,7 @@ public virtual async Task BindAsync(AddressBindContext context)
308
224
{
309
225
foreach ( var endpoint in _endpoints )
310
226
{
311
- await BindEndpointAsync ( endpoint , context ) . ConfigureAwait ( false ) ;
312
-
313
- context . Addresses . Add ( endpoint . GetDisplayName ( ) ) ;
227
+ await endpoint . BindAsync ( context ) . ConfigureAwait ( false ) ;
314
228
}
315
229
}
316
230
}
@@ -328,7 +242,8 @@ public virtual async Task BindAsync(AddressBindContext context)
328
242
{
329
243
foreach ( var address in _addresses )
330
244
{
331
- await BindAddressAsync ( address , context ) . ConfigureAwait ( false ) ;
245
+ await ParseAddress ( address , context . ServerOptions , context . DefaultHttpsProvider )
246
+ . BindAsync ( context ) . ConfigureAwait ( false ) ;
332
247
}
333
248
}
334
249
}
0 commit comments