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

Create a direct way to configure endpoints on KestrelEngine #1280

Merged
merged 1 commit into from
Jan 7, 2017

Conversation

halter73
Copy link
Member

@halter73 halter73 commented Jan 4, 2017

  • 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

#996

@halter73 halter73 force-pushed the halter73/996 branch 4 times, most recently from 51ef5c5 to 9e2947f Compare January 5, 2017 03:08
options.UseSystemd();

// The following section should be used to demo sockets
//options.ListenUnixSocket("http://unix:/tmp/kestrel-test.sock");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be:

options.ListenUnixSocket("/tmp/kestrel-test.sock");

}

_options = options;
_logger = loggerFactory?.CreateLogger(nameof(HttpsConnectionAdapter));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is the logger factory null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the HttpsConnectionAdapter is initialized directly using the other ctor.


namespace Microsoft.AspNetCore.Hosting
{
public static class ListenOptionsHttpsExtensions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Add doc comment

/// <returns>
/// The <see cref="ListenOptions"/>.
/// </returns>
public static ListenOptions UseConnectionLogging(this ListenOptions listenOptions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these are listen options? Shouldn't it be on the top level kestrel options?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConnectionAdapters are configured per endpoint. This is important for HTTPS.

If you want to configure all endpoints in the same way (e.g. to enable connection logging for everything), I would recommend creating a static method with a ListenOptions parameter to share the configuration code.

/// <remarks>
/// Defaults to empty.
/// </remarks>
public List<IConnectionAdapter> ConnectionAdapters { get; } = new List<IConnectionAdapter>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have the filters moved to listen options? These should be ok KestrelServerOptions still no?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Different adapters per endpoint?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CesarBS is right. Different adapters per endpoint is nice for HTTPS.

/// <remarks>
/// Defaults to true.
/// </remarks>
public bool NoDelay
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider splitting the configuration for accepted sockets vs the listen socket.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though we call uv_tcp_nodelay on the listen socket, I don't think it has any effect there (it might get inherited but that's pretty moot). I think the only important thing is configuring nodelay for the accepted sockets.

I certainly wouldn't split the configuration. We could remove the call uv_tcp_nodelay for the listen socket, but I would do that as part of another change and make absolutely sure that it doesn't affect perf.


return pipe;
default:
throw new InvalidOperationException();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NotSupportedException seems more appropriate


_frame.PrepareRequest = _filterContext.PrepareRequest;
_frame.Start();
_frame.PrepareRequest = features =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could avoid the allocation by setting the list of adaptedConnections on the frame itself and having it do this logic in Frame. It's actually a bit cleaner than assigning a delegate in Connection.

@@ -1,61 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These deleted files make me so happy 👍

@@ -92,7 +92,7 @@ public unsafe IPEndPoint GetIPEndPoint()
*((long*)(b + 8)) = _field2;
}

return new IPEndPoint(new IPAddress(bytes), port);
return new IPEndPoint(new IPAddress(bytes, scopeid: _field3 & 0xFFFFFFFF), port);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is comment worthy.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added to the big comment above.

private LibuvStream _libuvStream;
private FilteredStreamAdapter _filteredStreamAdapter;
private readonly List<IConnectionAdapter> _connectionAdapters;
private AdaptedPipeline _filteredStreamAdapter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: rename to _adaptedPipeline?

}
catch (Exception ex)
{
Log.LogError(0, ex, "ConnectioAdapter.PrepareRequest");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConnectioAdapter -> ConnectionAdapter

use nameof 😁

}
catch (Exception ex)
{
Log.LogError(0, ex, "ConnectioAdapter.OnConnectionAsync");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same typo here

}
catch (UvException ex)
{
Log.LogError(0, ex, "Listener.OnConnection");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use nameof

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this need to be the following then?

Log.LogError(0, ex, $"{nameof(Listener)}.{nameof(Listener.OnConnection)}");

Not sure it's worth it since we never really expect the above to throw. If you search the Kestrel code base for "Log.LogError" you'll see a lot of places that need to change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to prefer nameof for things like this because it's easy to miss that if there's a rename.

@@ -61,49 +61,33 @@ public void Dispose()
#endif
}

public IDisposable CreateServer(ServerAddress address)
public IDisposable CreateServer(ListenOptions listenOptions)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Soooo much better to read 👍

/// <remarks>
/// Defaults to empty.
/// </remarks>
public List<IConnectionAdapter> ConnectionAdapters { get; } = new List<IConnectionAdapter>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Different adapters per endpoint?


namespace Microsoft.AspNetCore.Hosting
{
public static class KesterlServerOptionsSystemdExtensions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should offer this in a separate package.

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add set -e at the top to fail the script if any command fails.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


# Ensure that dotnet is added to the PATH
scriptDir=$(dirname "${BASH_SOURCE[0]}")
repoDir=$(cd $scriptDir/../../.. && pwd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace cd $scriptDir/../../.. && pwd with readlink -e $scriptDir/../../..

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually want to change directories.

}

[Fact]
public void NoDelayPropogatesToListenOptions()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Propagates

Copy link
Member

@Tratcher Tratcher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the WebListener API for reference:
https://github.com/aspnet/HttpSysServer/blob/dev/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs#L38-L43
https://github.com/aspnet/HttpSysServer/blob/dev/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs

It's a lot simpler because there are no per-endpoint settings. All the information is captured in the prefix or stored via netsh.

.UseKestrel(options =>
var hostBuilder = new WebHostBuilder().UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, 5000, listenOptions =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a realistic sample the IP and port need to come from command line / env / config. We need to make that possible in one or two lines. Even if it means having a Listen overload that takes a string for IP:port that understands IPv4, IPv6, and *.
@shirhatti
options.Listen(config["IPAndPort"], listenOptions => ...

Note IPEndpoint does not implement Parse so you can't just punt this over there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the VS 2017 self-host profile now sets the ASPNETCORE_URLS environment variable by default so apps are unlikely to start from VS on localhost:5000 anymore. /cc: @BillHiebert

if (listenOptions.Any())
{
var addresses = _serverAddresses.Addresses;
if (addresses.SingleOrDefault() != "http://localhost:5000")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird guesswork that makes assumptions about the intent of the caller. I'd rather reconsider the Hosting default logic. WebListener is going to have a similar issue when it's configured to attach to an existing queue. @davidfowl

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFIAK, the idea is to remove the IServerAddresses feature entirely prior to 2.0, so this heuristic is only temporary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove IServerAddresses? What's the rest of that plan?

if (string.Equals(Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture), Environment.GetEnvironmentVariable("LISTEN_PID"), StringComparison.Ordinal))
{
// SD_LISTEN_FDS_START = 3
options.ListenHandle(3, configure);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

define constants

Copy link
Contributor

@cesarblum cesarblum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor follow-up comment but LGTM otherwise. :shipit:

- 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
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants