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

Added initial connection middleware pipeline #2003

Merged
merged 5 commits into from
Aug 21, 2017
Merged

Conversation

davidfowl
Copy link
Member

@davidfowl davidfowl commented Aug 18, 2017

  • Implemented IConnectionBuilder on ListenOptions. Kept IConnectionAdapter for now.
  • Delay the configure callback for ListenOptions until the server has started.
  • Added ConnectionLimitMiddleware and HttpConnectionMiddleware
  • Expose ConnectionAborted and ConnectionClosed on ConnectionContext and IConnectionTransportFeature
  • Updated the tests

Progress on #1980
Progress on #1772

- Implemented IConnectionBuilder on ListenOptions. Kept IConnectionAdapter for now.
- Delay the configure callback for ListenOptions until the server has started.
- Added ConnectionLimitMiddleware and HttpConnectionMiddleware
- Expose ConnectionAborted and ConnectionClosed on ConnectionContext and
IConnectionTransportFeature
- Updated the tests
- Moved Application to IConnectionTransportFeature
Input = input.Reader,
Output = _outputPipe
Application = pair.Application,
Transport = pair.Transport
Copy link
Member

Choose a reason for hiding this comment

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

I think you want to use _outputPipe here so the Cleanup method works.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch.


Task ConnectionAborted { get; }

Task ConnectionClosed { get; }
Copy link
Member

Choose a reason for hiding this comment

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

Why can't a single Task represent aborted and closed?

Didn't we intend to communicate when/how the connection was closed via the IPipeConnections?

Copy link
Member Author

@davidfowl davidfowl Aug 21, 2017

Choose a reason for hiding this comment

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

It's broken because of the dispatching. Ordering problems cause issues that I don't want to fix while changing everything else. This maps to the existing behavior.

  • One Task maps to the input being aborted (FIN)
  • One Task maps to when the output has closed

var output = pipeFactory.Create(outputOptions);

var transportToApplication = new PipeConnection(output.Reader, input.Writer);
var applicationToTransport = new PipeConnection(input.Reader, output.Writer);
Copy link
Member

Choose a reason for hiding this comment

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

I like the TransportToApplication and ApplicationToTransport naming. Can we use this everywhere instead of of just Transport and Application?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, it's too verbose. Also the only thing that usually sees both sides are when you're implementing the transport. Notice the DefaultConnectionContext still has the Transport exposed.

var inputPipe = transportFeature.PipeFactory.Create(GetInputPipeOptions(transportFeature.InputWriterScheduler));
var outputPipe = transportFeature.PipeFactory.Create(GetOutputPipeOptions(transportFeature.OutputReaderScheduler));
// REVIEW: Unfortunately, we still need to use the service context to create the pipes since the settings
// for the scheduler and limits are specified here
Copy link
Member

Choose a reason for hiding this comment

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

Could you just pass in the KestrelServerOptions? Do you need to pass in a scheduler and the "ThreadPool"?

// application code.
connection.StartRequestProcessing(_application);
// REVIEW: This task should be tracked by the server for graceful shutdown
// Today it's handled specifically for http but not for aribitrary middleware
Copy link
Member

Choose a reason for hiding this comment

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

Can we at least log a critical error if something goes wrong? I know that shouldn't/won't hapeen today, but this would also help avoid potential unobserved exceptions in the future.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will do.

@@ -126,6 +129,10 @@ public FileHandleType HandleType
/// </remarks>
public List<IConnectionAdapter> ConnectionAdapters { get; } = new List<IConnectionAdapter>();

public IServiceProvider ApplicationServices => KestrelServerOptions?.ApplicationServices;
Copy link
Member

Choose a reason for hiding this comment

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

Not again! Where is this used?

Copy link
Member Author

Choose a reason for hiding this comment

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

ApplicationServices is part of the interface. It will be used to activate middleware, just like IApplicationBuilder. ApplicationServices

@@ -100,8 +100,7 @@ public void Listen(IPEndPoint endPoint, Action<ListenOptions> configure)
throw new ArgumentNullException(nameof(configure));
}

var listenOptions = new ListenOptions(endPoint) { KestrelServerOptions = this };
configure(listenOptions);
var listenOptions = new ListenOptions(endPoint) { KestrelServerOptions = this, Configure = configure };
Copy link
Member

Choose a reason for hiding this comment

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

Instead of adding this weird Configure callback, why not keep it the way it was and invoke configure directly in Listen()? Is this just for testing? Seems super confusing to me.

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 need to run this later so that I can wrap the connection limit around the entire pipeline.

Copy link
Member

Choose a reason for hiding this comment

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


namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
{
public class HttpConnectionMiddleware<TContext>
Copy link
Member

Choose a reason for hiding this comment

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

👍 I love that you were able to factor this out of ConnectionHandler.

}
}

public static class HttpConnectionBuilderExtensions
Copy link
Member

Choose a reason for hiding this comment

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

Move to a new file.

{
private FileHandleType _handleType;
private readonly List<Func<ConnectionDelegate, ConnectionDelegate>> _components = new List<Func<ConnectionDelegate, ConnectionDelegate>>();
Copy link
Member

Choose a reason for hiding this comment

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

🎉

}
}

public static class ConnectionLimitBuilderExtensions
Copy link
Member

Choose a reason for hiding this comment

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

Move to new file.

@davidfowl
Copy link
Member Author

🆙 📅

@davidfowl davidfowl merged commit 2e66870 into dev Aug 21, 2017
@davidfowl davidfowl deleted the davidfowl/pipeline branch November 9, 2017 08:11
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.

4 participants