Commit Graph

22 Commits

Author SHA1 Message Date
Cory Benfield 2d8e6ca36f
Tolerate sending data after close(mode: .output) (#2421)
Motivation

We shouldn't crash on somewhat likely user error.

Modifications

Pass on writes after close(mode: .output) instead of crashing.

Result

User code is more robust to weird edge cases.
2023-05-09 10:52:48 +01:00
Cory Benfield 5f8b0647e4
Handle close(output) in the pipeline handler. (#2414)
Motivation:

Currently the server pipeline handler ignores close. This generally works,
except in the rare case that the user calls close(mode: .output). In this
instance they have signalled that they'll never write again, and they're
likely expecting a final close shortly after.

However, it is possible that the pipeline handler has suspended reads
at the same time. On Linux this isn't an issue, because we'll still be told
about the eventual socket close. However, on Apple platforms we won't: we've
masked off the reads, and we can't listen to EVFILT_EXCEPT due to some
other issues. This means that on Apple platforms the server pipeline handler
can accidentally wedge the Channel open and prevent it from closing.

We should take this opportunity to have the server pipeline handler be smart
about close(mode: .output). What _should_ happen here is that the pipeline
handler should immediately refuse to deliver further requests on the Channel.
If one is in-flight, it can continue, but everything else should be dropped.
This is because the server cannot possibly respond to further requests.

Modifications:

- Add new states to the server pipeline handler
- Drop buffered requests and new data after close(mode: .output)
- Add tests

Result:

Server pipeline handler behaves way better.
2023-04-28 06:22:07 -07:00
David Nadoba 6720612111
Drop Swift 5.5 (#2406)
* Drop Swift 5.5

* Use `swift-atomics` 1.1.0 with `Sendable` adoption
2023-04-17 08:40:35 +01:00
David Nadoba 0abf7eb929
Adopt `Sendable` for types in `NIOHTTP1` (#2213) 2022-07-04 00:37:23 -07:00
Fabian Fett addf69cfe6
Allow HTTP Server to send multiple informational heads before actual response head (#1985)
Co-authored-by: Helge Heß <devteam@zeezide.de>
Co-authored-by: Tobias Haeberle <tobias.haeberle@holidu.com>

Co-authored-by: Helge Heß <devteam@zeezide.de>
Co-authored-by: Tobias Haeberle <tobias.haeberle@holidu.com>
2021-11-09 10:20:51 +00:00
Cory Benfield 64285cbff2
Clean up dependencies and imports. (#1935)
Motivation:

As we've largely completed our move to split out our core abstractions,
we now have an opportunity to clean up our dependencies and imports. We
should arrange for everything to only import NIO if it actually needs
it, and to correctly express dependencies on NIOCore and NIOEmbedded
where they exist.

We aren't yet splitting out tests that only test functionality in
NIOCore, that will follow in a separate patch.

Modifications:

- Fixed up imports
- Made sure our protocols only require NIOCore.

Result:

Better expression of dependencies.

Co-authored-by: George Barnett <gbarnett@apple.com>
2021-08-12 13:49:46 +01:00
Johannes Weiss 74944a937d
use Optional<T> instead of T? to workaround SR-11777 (#1252)
Motivation:

In Swift, writing

    var something: T?

    init() {
        self.something = someValue
    }

means that the compiler will first set `self.something` to `nil` and
then in the init override it with `self.someValue`
(https://bugs.swift.org/browse/SR-11777). Unfortunately, because of
https://bugs.swift.org/browse/SR-11768 , stored property initialisation
cannot be made `@inlinable` (short of using `@frozen` which isn't
available in Swift 5.0).

The combination of SR-11768 and SR-11777 leads to `var something: T?`
having much worse code than `var something: Optional<T>` iff the `init`
is `public` and `@inlinable`.

Modifications:

Change all `var something: T?` to `var something: Optional<T>`

Result:

Faster code, sad NIO developers.
2019-11-27 18:37:38 +00:00
Cory Benfield 6a79d4687e Make pipeline handler behave better when removed (#1080)
Motivation:

The HTTPServerPipelineHandler is removed from pipelines in many cases,
but the most common case is over upgrade. While the handler is
removable, it doesn't make any effort to ensure that it leaves the
pipeline in a sensible state, which is pretty awkward.

In particular, there are 3 things the pipeline handler may be holding
on to that can lead to damage. The first is pipelined requests: if there
are any, they should be delivered, as the user may be deliberately
allowing pipelining.

The second thing is read() calls. The HTTPServerPipelineHandler exerts
backpressure on clients that aggressively pipeline by refusing to read
from the socket. If that happens, and then the handler is removed from
the channel, it will "forget" to restart reading from the socket on the
way out. That leaves the channel quietly in a state where no reads will
occur ever again, which is pretty uncool.

The third thing is quiescing. The HTTPServerPipelineHandler catches
quiescing events and allows them to deliver a response before closing a
connection. If that has happened when the pipeline handler is removed,
it should fall back to the behaviour as though it were not there.

Modifications:

- Added a handlerRemoved implementation to play event state that should
    be replayed.
- Added a channelInactive implementation to drop data.

Result:

More graceful handler removal.
2019-07-23 20:10:26 +01:00
Johannes Weiss a41280919e
rename ctx to context (#842)
Motivation:

`ctx` was always an abbreviation was 'context` and in Swift we don't
really use abbreviations, so let's fix it.

Modifications:

- rename all instances of `ctx` to `context`

Result:

- fixes #483
2019-02-25 18:20:22 +00:00
Johannes Weiss d938264fcb
better ChannelHandler removal API (#767)
Motivation:

If ChannelHandler removal worked correctly, it was often either by
accident or by intricate knowledge about the implementation of the
ChannelHandler that is to be removed. Especially when it comes to
re-entrancy it mostly didn't work correctly.

Modifications:

- introduce a `RemovableChannelHandler` API
- raise allocation limit per HTTP connection by 1
  (https://bugs.swift.org/browse/SR-9905)

Result:

Make things work by contruction rather than accident
2019-02-12 11:27:48 +01:00
Nathan Harris caf9a3d8da standardize `ELF.cascade*` collection of methods (#802)
Motivation:

The `ELF.cascade` methods have a parameter label `promise` that does not match Swift API Guidelines, and a way to cascade just successes is not available - while for failures there is.

Modifications:

`ELF.cascade*` methods that already exist have had their `promise` label renamed to `to`, and a new `ELF.cascadeSuccess` method has been added.

Result:

EventLoopFuture now has the cascade methods `ELF.cascade(to:)`, `ELF.cascadeFailure(to:)`, and `ELF.cascadeSuccess(to:)`
2019-02-05 09:01:48 +00:00
Johannes Weiss 2ad1e21512 CircularBuffer.init: rename initialRingCapacity to initialCapacity
Motivation:

initialRingCapacity is not a great name, initialCapacity is much better

Modifications:

rename CircularBuffer(initialRingCapacity:) to initialCapacity

Result:

more consistent code
2019-01-29 12:29:04 +00:00
Johannes Weiss 3e7d6a7bfd rename ELF.then to ELF.flatMap (#760)
Motivation:

ELF's API should be as close as possible to the new Result's API.
Therefore, we should rename `then` to `flatMap`

Modifications:

- renamed `then` to `flatMap`
- renamed `thenIfError` to `flatMapError`
- renamed ELF's generic parameter from `T` to `Value`

Result:

- more like Result
- fixes #688
2019-01-21 16:41:04 +00:00
David Skrundz f7357e66ab make ELF.cascade accept an optional promise (#757)
* Make EventLoopFuture.cascade and cascadeFailure accept an optional promise

Motivation:

fixes #756

Modifications:

Change EventLoopFuture.cascade to func cascade(promise: EventLoopPromise<T>?)

Result:

EventLoopFuture.cascade can be called without needing to check if the promise is nil
2019-01-19 13:59:12 +00:00
Johannes Weiss 305ee9818b make factory method names start with make (#692)
Motivation:

Swift naming guidelines mandate that factory methods start with `make`,
like `makeSomething`. We had a few that were `newSomething`.

Modifications:

make all factories start with make

Result:

more compliant to Swift naming rules
2018-12-10 17:59:24 +00:00
Johannes Weiss 08ab8b51cd
remove ugly and unnecessary ignore result (_ = ...) (#652)
Motivation:

_ = expression() is ugly and in many cases unimportant. In fact we train
ourselves to overread it which makes special cases where you'd actually
expect a result to be used just look normal.

Modifications:

remove _ = from a lot of places. In many cases we already had a better
(and sometimes cheaper way) to not return a value but in some cases
(mostly `remove` functions) I added `@discardableResult`

Result:

NIO source code looks nicer
2018-11-13 14:49:08 +00:00
Johannes Weiss ce0c6d92e9
pipeline handler: fix error state tracking (#595)
Motivation:

@pushkarnk hit an interesting edge case that we previously mishandled
and crashed. All these conditions need to be true

1. Whilst have an ongoing request (ie. outstanding response), ...
2. ... a `HTTPParserError` arrives (which we correctly queue)
3. Later the outstanding response is completed and then ...
4. ... the `HTTPServerProtocolErrorHandler` sends a .badRequest response

We previously crashed. The reason we crashed is that the
`HTTPServerPipelineHandler` obviously tracks state and then asserts that
no response is sent for a wrong request. It does have an affordance to
allow a .badRequest response for a request it couldn't parse. However
this state tracking wasn't done if the error itself was enqueued for
later delivery.

Thanks very much @pushkarnk for the report!

Modifications:

instead of delivering the error directly use the `deliverOneError`
function which transitions the state correctly.

Result:

fewer crashes & hopefully happy Pushkar
2018-08-27 11:09:51 +01:00
Johannes Weiß cea84765de Channel quiescing support (#399)
Motivation:

In certain cases it's useful to quiesce a channel instead of just
closing them immediately for example when receiving a signal.
This lays the groundwork by introducing the
`ChannelShouldQuiesceUserEvent` user event that when received can be
interpreted by a ChannelHandler in a protocol & application specific
way. Some protocols support tear down and that would be a good place to
initiate the tear down.

Modifications:

- introduce `ChannelShouldQuiesceUserEvent`
- handle `ChannelShouldQuiesceUserEvent` in the `AcceptHandler` with
  closing the server socket
- handle `ChannelShouldQuiesceUserEvent` in the
  `HTTPServerPipelineHandler` by only handling a already in-flight
  request and then no longer accepting input
- added `CircularBuffer.removeAll` (& tests)
- added tests for `nextPowerOf2()`

Result:

- handlers can now support quiescing
2018-05-18 10:48:18 +02:00
adamnemecek 776c3f42cb trimmed whitespace (#361)
Trimmed trailing whitespace.

Motivation:

Trimmed trailing whitespace.

Modifications:

Trimmed trailing whitespace.

Result:

Less trailing whitespace.
2018-04-27 08:33:32 +02:00
Johannes Weiß ec30e5cc5a fix recursive channelReads in pipelining handler (#348)
Motivation:

The pipelining handler made the assumption that `channelRead` is never
called recursively. That's mostly true but there is at least one
situation where that's not true:
- pipelining handler seen a response .end and delivers a .head (which is
  done in `channelRead`)
- a handler further down stream writes and flushes some response data
- the flushes fail which leads to us draining the receive buffer
- if the receive buffer contained more requests, the pipelining
  handler's `channelRead` is called again (recursively)

The net result of that was that the new request parts from the receive
buffer would now jump the queue and go through the channel pipeline
next, before other already buffered messages.

Modifications:

made the pipelining handler buffer if a `channelRead` comes in from the
pipeline and there is already at least one message buffered.

Result:

the ordering of the incoming messages should now be respected which is
very important...
2018-04-24 08:18:21 +01:00
Johannes Weiß dc0d7311da
fix errors received when holding messages in HTTPServerPipelineHandler (#314)
Motivation:

We had a bug which is happens in the combination of these states:
- we held a request in the pipelining handler (because we're procesing a
  previous one)
- a http handler error happened whilst a response's `.head` had already
  been sent (but not yet the `.end`)
- the HTTPServerProtocolErrors handler is in use

That would lead to this situation:
- the error isn't held by the pipelining handler
- the error handler then just sends a full response (`.head` and `.end`)
  but the actual http server already send a `.head`. So all in all, we
  sent `.head`, `.head`, `.end` which is illegal
- the pipelining handler didn't notice this and beause it saw an `.end`
  it would send through the next requst
- now the http server handler is in the situation that it gets `.head`,
  `.head` too (which is illegal)

Modifications:

- hold HTTP errors in the pipelining handler too

Result:

- more correctness
2018-04-16 15:13:07 +01:00
Cory Benfield 860a7d40a3 Add channel handler for server side pipelining. (#62)
Motivation:

HTTP pipelining can be tricky to handle properly on the server side.
In particular, it's very easy to write out of order or inconsistently
mutate state. Users often need help to handle this appropriately.

Modifications:

Added a HTTPServerPipelineHandler that only lets one request through
at a time.

Result:

Better servers that are more able to handle HTTP pipelining
2018-03-13 15:21:12 +00:00