* Improve ConnectionLimitMiddleware and connection pipeline building
* Add IDecrementConcurrentConnectionCountFeature
* Flow connection features from connection middleware
- Use the pipe events and removed the Tasks from ConnectionContext
- Remove OnConnectionClosed from FrameConnection. Since the `FrameConnetion` is a single middleware, not the entire pipeline, we shouldn't need to wait on the connection close there.
- It seems like the callbacks are rooted on the pipe even after they fire. This needs to be investigated in pipelines.
Current path is:
Parser -> HttpVersion Enum -> Get Version String -> Set `HttpVersion` with string -> Convert back to Enum
Can just set the enum directly since its already parsed.
Also using the const rather than strings; where the strings are in code
* Added initial connection middleware pipeline
- 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
- Removed IConnectionApplicationFeature
- Moved Application to IConnectionTransportFeature
PackageLineup is a way to manage PackageReference versions across large projects. It removes the version information from the repository and instead pulls the information from an external "lineup" file.
What works:
- HTTP/2 over TLS1.2 with ALPN
- Request and response flow
- Headers are compressed and decompressed with HPACK
- Request body can be read by streams (if present)
- MVC template app with individual auth works fine
- PRIORITY frames are validated
- RST_STREAM frames are validated and abort streams
- SETTINGS frames are validated and ACKed
- PING frames are validated and ACKed
- GOAWAY frames stop connections
- WINDOW_UPDATE frames are validated
- CONTINUATION frames are sent for large header blocks
What doesn't work yet:
- Flow control in either direction
- It's not possible to encode a single header across more than one frame
- Affects only a very large header (name and value combined ~16KB long)
- Request trailers
- Response trailers
- Limits and timeouts in `KestrelServerLimits` are not enforced on HTTP/2
- HPACK use is very limited on the send side
- Literals are not Huffman-encoded
- Common headers (e.g. "server: Kestrel") are never indexed
- Honoring client settings
- Some error checking is still missing (e.g. validating incoming frame size)
- Added Protocols.Abstractions
- IConnectionHandler.OnConnection takes an IFeatureCollection instead of
IConnectionInfo
- Removed IConnectionContext and IConnectionInformation replaced with
IConnectionTransportFeature
- Updated FrameConnectionContext and FrameContext to have the relevant
state instead of flowing the ConnectionInformation.
- Updated tests
* UvPipeHandle.Open(IntPtr) and underlying interop
* LibuvConstants.ENOTSUP
* IEndpointInformation.HandleType along with ListenOptions extra ctor and handle type re-specification
* Exception-based auto-detection of socket type in Listener, accept socket creation support for detected handle types in ListenerContext
* Added systemd Unix socket activation tests
- Added new options to allow configuring the maximum number of concurrent connections and upgraded connections.
- `KestrelServerLimits.MaxConcurrentConnections` defaults unlimited.
- `KestrelServerLimits.MaxConcurrentUpgradedConnections` defaults to unlimited.
- Calls to IHttpUpgradeFeature.UpgradeAsync() will throw when the MaxConcurrentUpgradedConnections limit has been reached.
- Kestrel will close new connections without response when MaxConcurrentConnections is reached.
* Invert the dependency between connection adapters and Frame
- Removed PrepareRequest from IAdaptedConnection and instead added
a feature collection to the ConnectionAdapterContext. This allows features to be set
once by the adapter instead of per request. It's the Frame's job to copy features
from the connection level feature collection into the per request feature collection.
- Set the scheme to "https" based on the presence of ITlsConnectionFeature.
- Always set ITlsConnection feature if the HttpsAdaptedConnection doesn't throw during
the handshake
* More FrameConnection refactoring
- This change reverts the change to complete the writer with an
exception on abort because of the number of first chance exceptions
that get thrown.
- This change also moves connection logging into FrameConnection instead
of being split between the ConnectionHandler and FrameConnection.
- Fixed issues with LibuvOutputConsumerTests that leak WriteReq since
cancelled writes no longer end the connection.
* Refactoring and of FrameConnection and Frame
- Building on top of the last refactoring of FrameConnection, this change aims to clean up
the communication between the Frame and FrameConnection by removing some concepts and
being consistent about the communication between Frame and FrameConnection with or without
connection adapters. Changes include:
- Removing ConnectionLifetimeControl, ISocketOutput, StreamSocketOutput
- Moving more initialization of the frame to FrameConnection after the pipes
are setup
- OutputProducer communicates cancellation via the IPipeWriter instead of the output's IPipeReader.
- Frame always communicates via the pipes and that communications flows through the layers to the transport.
This means that each 1/2 of the adapted pipeline handles closing the right side of the transport at the
right time, propagating exceptions as necessary.
- This is how the flow looks now:
-> ->
[transport] [connection adapters] [frame]
<- <-
- Transports need to handle a ConnectionAbortedException on the output as a signal to stop
writing and end the connection. This will no longer try to drain the output but will just stop
writing and end the response immediately.
- Remove frame.Abort when cancellation on Write fails.
- Unify the connection shutdown logic
- Dispose 1/2 initialized connection adapters
#1815
* Added a ConnectionAbortedException to Transport.Abstractions
- To avoid hard coding TaskCanceledException in each transport
- This PR tries to keep compatibility by converting the ConnectionAbortedException
to a TaskCanceledException on exceptions in FrameRequestStream. The downside is that
this conversion causes an async state machine to be created per call to ReadAsync.
CopyToAsync isn't that bad because it's a single long running task.
* Fix race where ListenerPrimary is disposed before secondary listeners spin up
- Since we only add listeners to dispatch pipes after receiving the "ack" message
it's possible to have pipes that were created but not acked yet. We might miss
disposal of those pipes if they were never added to the list of _dispatchPipes.
#1761
The format:
The trace identifier begins with connection ID and ends with a number that increments with each request per connection.
Example:
Connection ID = xyz
Request 1 = "xyz:00000001"
Request 2 = "xyz:00000002"
...
Request 15 = "xyz:0000000F"
Request 16 = "xyz:00000010"
- This change does a few things:
1. It adds the events we will replace with
pipe events to IConnectionContext and IConnectionInformation to get out of
band notifications about pipe completions.
2. It also implements those callbacks
and exposing slight changes we'll need to make once we have them. The idea is
that we can delete/replace these methods once we have the new pipe API and things
will keep working.
- FIN from the client shouldn't throw
- Forced close from the server should throw
- Properly wrap connection reset exceptions and other exceptions
in IO exceptions
- This gives kestrel control over when the output closes
- Fixed one test that assumed libuv
- Dispose the connection to yield the reader
Fixes#1774
* Schedule connection adapter reads on configured thread pool
- This should speed up connection adapters as we don't block
new reads. It *might* also help some of the test flakiness
* Clean up libuv connection
- Cancel all pending flushes on the input writer before
disposing the stream handle.
- Complete the pipe before disposing the socket
- Added logging for connection pause/resume.
- Added test
After upgrade has been accepted by the server:
- Reads to HttpRequest.Body always return 0
- Writes to HttpResponse.Body always throw
- The only valid way to communicate is to use the stream returned by IHttpUpgradeFeature.UpgradeAsync()
Also, Kestrel returns HTTP 400 if requests attempt to send a request body along with Connection: Upgrade
- Simplify KestrelServer by refactoring address binding into a separate class
- Use strategy pattern to implement address binding for different sceanrios
- Add fallback from binding 0.0.0.0 if binding to [::] fails (can happen if UvException with EAFNOSUPPORT is thrown)
* Make all UvRequest objects normal GC handles
- This avoids the cost of using GCHandle.Alloc per operation.
- It *does* mean that we need to explicitly dispose UvRequest objects
after using them (which we did before anyways). This change does
add a few try catch statements to make sure we always dispose the UvRequest
if there are synchronous exceptions.
- This is ~1.5% of the overhead in the benchmarks today
- Keep track of all allocated UvRequest objects with a WeakReference in DEBUG
and assert none are kept around after cleaning up.
- Fixed a leak where we don't clean up UvWriteReq objects when writing
to the named pipe.
- This property will force Kestrel to use whatever scheduler the transport
used when write and read callbacks are fired. The default value is false so
all calls to user code including connection adapters, and the application function,
and cancellation token callbacks.
- Transports may expose configuration that changes what the transport thread is.
- Removed InternalKestrelServerOptions.cs
- Added a configurable UseSockets overload (even though there are no options yet)
- Remove RequiresDispatch from the IConnectionInformation
Improves Kestrel to reject requests that don't conform to HTTP spec.
RFC 7230 section 5.4: "A server MUST respond with a 400 (Bad Request)
status code to any HTTP/1.1 request message that lacks a Host header
field and to any request message that contains more than one Host
header field or a Host header field with an invalid field-value."
See https://tools.ietf.org/html/rfc7230#section-5.4.
Other changes:
- update VS code settings to work better with CLI 2.0
- update tests that were subject to infinite hangs
- Style changes: Sort usings, use more var and C#7
- Added ConfigureAwait to stop dead locks with xunit
- Remove duplicate handling of aborts in the receiver
- Handle the case where output ends before input
- This change adds the initial socket transport for Kestrel, all of the tests pass but there are still
a couple of things that aren't done yet.
- The functional tests support running both on both transports but tests aren't running for sockets right now. We need to parameterize these.
- TimeoutServerTests hard code the libuv transport, this needs to support any transport.
- There is no handling of connection stopping on application shutdown. This is being implemented in kestrel core so transports don't need to handle it. Sockets won't be the default transport until that is the case.
- Performance needs to be looked at, today the SocketTransport doesn't dispatch by default and we're not buffering in kestrel.core, this can hurt as the number of kernel calls map 1:1 with application writes.
Add an internal API to ListenOptions to determine if an endpoint is configured to use HTTPS. This is a temporary as the design of connection adapters and configuration will churn before release.
Changed the IHttpParser interface to be generic. This lets use a struct to
get better code generation and also should allow us to inline calls back into
the handler from the parser.
- Renamed KestrelHttpParser to HttpParser
- Removed the generic virtual dispatch as it turns out to be an
order of magnitude slower than regular virtual dispatch. This change
means we also lose the inlining of Frame.OnStartLine and Frame.OnHeader.
* Rename EngineTests to LibuvTransportTests.
* Move libuv-specific tests into their own test project.
* Move LibuvOutputConsumerTests.AllocCommitCanBeCalledAfterConnectionClose to new OutputProducerTests class and rename it to WritesNoopAfterConnectionCloses.
* Remove TransportContext from TestServiceContext.
* Make KestrelTests depend on Kestrel.Core only.
* Rename Microsoft.AspNetCore.Server.Kestrel.KestrelTests to Microsoft.AspNetCore.Server.Kestrel.Core.Tests.
* Add Microsoft.AspNetCore.Server.Kestrel.Tests test project for WebHostBuilderKestrelExtensionsTests.
* Increase socket receive timeout in MaxRequestBufferSizeTests to mitigate flakiness.
* Anything using TestServer should be a functional test.
* Move out of LibuvTransportTests tests that are not specific to LibuvTransport.
- Move to RequestTests:
- Http11 (rename to Http11KeptAliveByDefault)
- Http10ContentLength (rename to Http10NotKeptAliveByDefault)
- Http10KeepAlive
- Http10KeepAliveNotUsedIfResponseContentLengthNotSet (rename to Http10KeepAliveNotHonoredIfResponseContentLengthNotSet)
- Http10ContentLengthKeepAlive (rename to Http10KeepAliveHonoredIfResponseContentLengthSet)
- Expect100ContinueForBody (rename to Expect100ContinueHonored)
- ZeroContentLengthAssumedOnNonKeepAliveRequestsWithoutContentLengthOrTransferEncodingHeader
- ConnectionClosesWhenFinReceivedBeforeRequestCompletes (test was actually not marked as Theory, and was incorrect)
- RequestsCanBeAbortedMidRead
- RequestHeadersAreResetOnEachRequest
- UpgradeRequestIsNotKeptAliveOrChunked
- HeadersAndStreamsAreReused (rename to HeadersAndStreamsAreReusedAcrossRequests)
- Move to ResponseTests:
- Http10RequestReceivesHttp11Response (rename to Http11ResponseSentToHttp10Request)
- ZeroContentLengthSetAutomaticallyAfterNoWrites
- ZeroContentLengthSetAutomaticallyForNonKeepAliveRequests
- ZeroContentLengthNotSetAutomaticallyForHeadRequests
- ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes
- ConnectionClosedAfter101Response
- ThrowingResultsIn500Response
- ThrowingAfterWritingKillsConnection
- ThrowingAfterPartialWriteKillsConnection
- ThrowingInOnStartingResultsInFailedWritesAnd500Response
- ThrowingInOnCompletedIsLoggedAndClosesConnection
- FailedWritesResultInAbortedRequest
- NoErrorsLoggedWhenServerEndsConnectionBeforeClient
- NoResponseSentWhenConnectionIsClosedByServerBeforeClientFinishesSendingRequest
- ResponseHeadersAreResetOnEachRequest
- OnStartingCallbacksAreCalledInLastInFirstOutOrder
- OnCompletedCallbacksAreCalledInLastInFirstOutOrder
- Remove:
- RePathEscapeTests (theory data to HttpParsingData)
- ReDisconnectingClient (what was that testing?)
- Put everything in the libuv transport package under `Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.*` namespaces.
- Move stuff in Transport.Libuv/Internal/Http and Transport.Libuv/Internal/Infrastructure to Transport.Libuv/Internal (keep the Networking directory for the libuv wrappers).
- Add `Libuv` prefix to most libuv internal classes.
- Rename `KestrelEngine` to `LibuvTransport`.
- Rename `SocketOutputConsumer` to `LibuvOutputConsumer`.
- Rename `SocketOutputProducer` to `OutputProducer`.
- Fix namespaces in `Microsoft.AspNetCore.Server.Kestrel.Core.`
* Don't update consumed if we didn't see a new line
- The start line parser incorrectly updated the consumed cursor
when it attempted to find new lines across buffers. This change fixes
that and also removes passing the span by reference (which will be illegal).
- Added a unit test
This feature generates a unique ID per request. This unique ID can be
used in event source and logging.
Also, this change improves KestrelEventSource by moving it back into the
Kestrel.Core assembly and de-coupling from the Libuv transport. This
adds two new events, RequestStart and RequestStop, which can be used to
identify the correlation between connection ID and request trace
identifier.
- Remove Libuv and Hosting dependency from Kestrel.Core
- Kestrel.Https and Kestrel.Core depend on Hosting.Abstractions
* wip
* Added separate ServerAddressesFeature
* Review feedback
- Added TlsConnectionFeature to Https
* Fixed regression caused by transport refactoring
- Libuv should not close the socket until it has started it. Before this was enforced
by calling ReadStart before starting the frame but the flow has changed. Now that closing the connection
is communicated via the pipe, we need to start consuming writes after calling ReadStart.
- Renamed OnSocketClosed to Close and moved dispose and logging into that method.
Fixes#1571
* Optimize calls into StreamSocketOuput to WriteFast further
- Added overloads to array, offset, length to avoid implicit conversions to
ReadOnlySpan.
- Use similar optimizations for multi buffer writes for strings and ints
- Use ref locals in multi write instead of pointers and pinning
- SocketOutput.WriteAsync will be synchronous for a majority of cases
(until you reach the limit) so no need to pay the async state machine
cost until then.
- Change Alloc to be a Write with a callback that exposes the WritableBuffer.
This allows the ISocketOutput to implementation to not call the callback if
the underlying socket is dead.
- Added a new functional test
* Faster Write implementation
- Use Unsafe.CopyBlockUnaligned to copy bytes to the
WritableBuffer. This is temporary until we get newer
corefx bits with a better span.CopyTo implementation.
- Remove WritableBufferExtensions from Performance project
- Split method into WriteFast and WriteMultiBuffer
- Cache the span for the common case where
the buffer is non empty.
- Use ref locals instead of pinning pointers in fast path
Explicit static cctors cause the C# compiler to not mark types as
beforefieldinit, which means the JIT will add checks to each static
method and instance constructor of the type to make sure that the static
constructor was previously called.
- Changed socket output to be based on pipelines
- Changed connection filter glue to be based on pipelines
- Codegen that used `MemoryPoolIterator` for output now uses `WritableBuffer`
- Made `UvWriteReq` async/await friendly with `LibuvAwaitable<T>`
- Deleted MemoryPool and friends
Improves compliance with RFC 7230 on the expected handling of requests
that have URI or asterisk in the request target.
This means rejecting asterisk requests that are not OPTIONS and rejecting
authority-form requests taht are not CONNECT.
This also means the server will handle the path and query on targets
with absolute URIs as request-targets.
* Made changes to TakeSingleHeader
- Remove state machine and just parse in place
- Inline OnHeader into TakeSingleHeader
- Use IndexOfVectorized instead of custom indexof
- Normalize header whitespace error
- Combine IndexOf and IndexOfAny into a single IndexOfNameEnd call
- Attempt at making the reader better for multispan parsing
- Try tighter inner loop
- Fix boundary case and clean code up
- Update the cursor once instead of after every header
- Fix errors with not updating consumed state on incomplete header payload
- Filled a test hole, removed a condition that should never happen
- Avoid struct copies every iteration when parsing headers
* Use ascii decoding routine that disallows null chars
- GetAsciiString() in newer corefxlab builds allows 0 (which is a valid
ascii char). To avoid future regressions, GetAsciiStringNonNullCharacters()
was added and used in place of GetAsciiString() when interpreting the
request line and headers
- Make GetAsciiStringNonNullCharacters return empty instead of null
- Added a fast path for single span in the start line parsing
- Added a fast path for single span header parsing
- Changed the out header loop to be pointer based (instead of slicing)
* Make the IHttpParser per frame and add a reset
- Made the IHttpParser a per frame object so state can be stored
across method calls and parses.
- Added HttpParserFactory to ServiceContext
- Less passes over the buffer
- Single pass to find all start line delimiters instead
of calling IndexOf multiple times.
- Made TakeStartLine and TakeMessageHeaders a state machine
- Only check length against remaining bytes once
- Change variable names to match TakeStartLine
- Use ReadableBuffer.First.Span instead of ToSpan()
- Added test for missing path with a querystring
Remove runtimeconfig.template.json
Remove ToolsVersion attribute
Use repo.targets instead of makefile.shade
Rename code gen app to shorter name
Use GetOSPlatform task
Upgrade tests to .NET Framework 4.5.2
Cleanup solution configurations. Set the class libraries to AnyCPU even when on the x86 or x64 solution config.
- 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