Commit Graph
249 Commits
Author SHA1 Message Date
Fabian Fett e26459902c Fix HTTP2StreamChannel leak (#657)
* Fix HTTP2StreamChannel leak

* Update code comments.
2023-02-14 10:04:27 +01:00
Cory Benfield 9401037091 Make syncShutdown unavailable from async (#667)
* Make syncShutdown unavailable from async

Motivation

syncShutdown can cause unbounded thread blocking, we shouldn't allow it
in concurrent code.

Modification

Mark syncShutdown unavailable from async.

Result

Users are warned if they try to syncShutdown in an async context

* Only noasync on 5.7
2023-02-13 18:44:22 +01:00
David NadobaandCory Benfield 1d24271fee Fix crash for large HTTP request headers (#661)
* Reproducer

* Refactor test case

* Refactor tests

* Remove debugging artefacts

* Fix typo

* Fix formatting

* Remove `promise?.succeed(())`

* Add test for HTTP2 request with large header

Motivation

We currently don't handle large headers well which trigger a channel writability change event.

Modification

Add failing (but currently skipped) tests which reproduces the issue
Result

We can reliably reproduce the large request header issue in an integration and unit test.
Note that the actual fix is not included to make reviewing easier and will come in a follow up PR.

* Remove logging

* Fix crash for large HTTP request headers

Fix crash for when sending HTTP request headers result in a channel writability change event

* Formatting and linux tests

* Formatting and linux tests

* Generate linux tests

* Use previous default max concurrent streams value of 10

* Fix crash if request is canceled after request header is send

* generate linux tests and run swift format

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2023-02-10 15:41:26 +01:00
David Nadoba aa66da80fa Fix request head continuation misuse (#666)
* Fix request head continuation misuse

Fixes #664

* remove unused function

* format & generate linux tests
2023-02-10 14:13:21 +00:00
Fabian Fett f65f45b727 Fix Request streaming memory leak (#665) 2023-02-07 17:18:56 +01:00
David Nadoba 67f99d1798 Add test for HTTP1 request with large header (#658)
* Reproducer

* Refactor test case

* Refactor tests

* Remove debugging artefacts

* Fix typo

* Fix formatting

* Remove `promise?.succeed(())`

* Rename `onRequestCompleted` to `onConnectionIdle`
2023-01-26 11:11:30 +00:00
Felix Schlegel 817d9aa99f Make Task.logger accessible to delegate implementations outside of Package (#587)
Motivation:

This change was proposed in issue
[#389](https://github.com/swift-server/async-http-client/issues/389).
Users writing their own `HttpClientResponseDelegate` implementation
might want to emit log messages to the `task`'s `logger`.

Modifications:

Changed the access level of `Task`'s `logger` property from `internal`
to `public`.

Result:

Users can access the `logger` property of a `Task` outside of the
`async-http-client`.
2023-01-22 09:32:01 -08:00
Cory Benfield 7f05a8da46 Merge pull request from GHSA-v3r5-pjpm-mwgq
Motivation

Allowing arbitrary data in outbound header field values allows for the
possibility that users of AHC will accidentally pass untrusted data into
those values. That untrusted data can substantially alter the parsing
and content of the HTTP requests, which is extremely dangerous. The
result of this is vulnerability to CRLF injection.

Modifications

Add validation of outbound header field values.

Result

No longer vulnerable to CRLF injection
2023-01-17 11:06:08 +00:00
iMike 49abfc30ae Add Host header (#650) (#651) 2022-12-06 11:13:10 +00:00
David Nadoba 5bee16a799 Switch over state in HTTPConnectionPool.HTTP2StateMachine.failedToCreateNewConnection (#647) 2022-11-09 15:30:16 +01:00
David Nadoba fd03ed01c7 Tolerate shutdown message after channel is closed (#646)
* Tolerate shutdown message after channel is closed

### Motivation
A channel can close unexpectedly if something goes wrong. We may in the meantime have scheduled the connection for graceful shutdown but the connection has not yet seen the message. We need to still accept the shutdown message and just ignore it if we are already closed.

### Modification
- ignore calls to shutdown if the channel is already closed
- add a test which would previously crash because we have transition from the closed state to the closing state and we hit the deinit precondition
- include the current state in preconditions if we are in the wrong state

### Result

We don’t hit the precondition in the deinit in the scenario described above and have more descriptive crashes if something still goes wrong.
2022-11-08 17:48:56 +01:00
carolinacass 8b84142a70 Use #fileID/#filePath instead of #file (#644) 2022-11-04 08:20:19 -07:00
Max Desiatov 10f42e647a FileDownloadDelegate: mark Progress as Sendable (#643)
This is a trivial struct that should be `Sendable`, as it's a common use case to pass `Progress` values to `@Sendable` closures.
2022-10-26 02:50:36 -07:00
David Nadoba 0bdc425a84 Remove #if compiler(>=5.5) (#641)
* Remove `#if compiler(>=5.5)`

* Run SwiftFormat
2022-10-12 16:18:47 +01:00
David Nadoba 0b5bec741b Replace NIOSendable with Sendable (#640) 2022-10-12 08:50:28 +01:00
David Nadoba d7b69d9d56 Make HTTPClientResponse.init public (#632) 2022-10-11 10:36:21 +01:00
David Nadoba f17a47e916 Allow immediate request failure on connection error (#625) 2022-10-10 13:34:42 +01:00
David Nadoba 9937d8751a Handle ResponseAccumulator not being able to buffer large response in memory (#637)
* Handle ResponseAccumulator not being able to buffer large response in memory

Check content length header for early exit

* Add test which currently hangs indefinitely

* Run `generate_linux_tests.rb` and `SwiftFormat`

* Print type and value if assert fails

* Run `generate_linux_tests.rb` and `SwiftFormat`

* Remove duplicate test due too merge conflict

* Validate that maxBodySize is positive

* Address review comments
2022-10-10 11:18:58 +01:00
David Nadoba f7a84af5d6 Fix request hang if delegate fails promise returned by didReceiveBodyPart (#633)
* Add test which currently hangs indefinitely

* Fix request hang if delegate fails promise

* Run `generate_linux_tests.rb` and `SwiftFormat`
2022-10-07 08:22:56 -07:00
Fabian Fett 4d69c84617 Add Hashable conformance to HTTPClient.Configuration.HTTPVersion (#636) 2022-10-07 08:15:14 -07:00
Fabian Fett af5966f1d1 Reduce use of HTTPClient.Configuration in the Connection objects (#635) 2022-10-07 08:05:28 -07:00
Fabian Fett 64ff430582 Add Hashable conformace to HTTPClient.Configuration.Proxy (#634) 2022-10-07 15:49:29 +01:00
Fabian Fett 897d49aa1b Replace Lock with NIOLock (#628)
SwiftNIO 2.42.0 has deprecated Lock and replaced it with a new NIOLock. This commit removes all uses of Lock and replaces them with NIOLock. Further, now, we must require SwiftNIO 2.42.0
2022-09-27 15:42:47 +02:00
Johannes WeissandJohannes Weiss 7f998f5118 add a future-returning shutdown method (#626)
Co-authored-by: Johannes Weiss <johannes@jweiss.io>
2022-09-07 06:12:05 -07:00
David Nadoba c3c90aab58 Adopt Sendable (#621) 2022-08-25 11:45:13 +02:00
David Nadoba 9c7ab039fe Allow HTTPClientRequest to be executed multiple times if body is an AsyncSequence (#620) 2022-08-23 13:46:17 +01:00
Karl 18109d842d Use NIOCore.System.coreCount for the fileIO thread pool (#618) 2022-08-20 12:22:41 +01:00
David NadobaandCory Benfield fc510a39cf Fix thread leak in FileDownloadDelegate (#614)
* Fix thread leak in `FileDownloadDelegate`

* `SwiftFormat`

* Add a shared file IO thread pool per HTTPClient

* User bigger thread pool and initlize lazily during first file write

* thread pool is actually not used in tests

* Update documentation

* fix review comments

* make `fileIOThreadPool` internal

* Add test to verify that we actually share the same thread pool across all delegates for a given HTTPClient

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-08-18 11:55:55 +02:00
David Nadoba 0469acb3bd Tollerate more data after request body is cancelled (#617)
* Tollerate more data after request body is cancelled

* wait is not needed if we shutdown the server first

* Remove test that depends on external resources

* Remove unused conformance to Equatable

* SwiftFormat

* run generate_linux_tests.rb

* Increase timeout for CI
2022-08-18 10:39:55 +01:00
Cory Benfield e294c8f28f Accurately apply the connect timeout in async code (#616)
Motivation

We should apply the connect timeout to the complete set of connection
attempts, rather than the request deadline. This allows users
fine-grained control over how long we attempt to connect for. This is
also the behaviour of our old-school interface.

Modifications

- Changed the connect deadline calculation for async/await to match that
  of the future-based code.
- Added a connect timeout test.

Result

Connect timeouts are properly handled
2022-08-16 13:17:45 +01:00
Cory Benfield 5e3e58dafd Use Docc for documentation (#613)
Motivation

Documentation is nice, and we can help support users by providing useful
clear docs.

Modifications

Add Docc to 5.6 and later builds
Make sure symbol references work
Add overview docs

Result

Nice rendering docs
2022-08-09 16:23:14 +01:00
Cory BenfieldandDavid Nadoba df87a860fd Limit max recursion depth delivering body parts (#611)
Motivation

When receiving certain patterns of response body parts, we can end up
recursing almost indefinitely to deliver them to the application. This
can lead to crashes, so we might politely describe it as "sub-optimal".

Modifications

Keep track of our stack depth and avoid creating too many stack frames.
Added some unit tests.

Result

We no longer explode when handling bodies with lots of tiny parts.

Co-authored-by: David Nadoba <d_nadoba@apple.com>
2022-08-05 17:53:21 +01:00
David Nadoba 46d1c76715 Support transparent decompression with HTTP/2 (#610) 2022-08-05 17:04:57 +02:00
David NadobaandCory Benfield a9c3cfb387 Report last connection error if request deadline is exceeded with async/await API (#608)
Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-08-04 18:24:34 +02:00
David Nadoba 3960678bcd Don’t call didReceiveError twice if deadline is exceeded and request is canceled aftewards (#609) 2022-08-04 13:14:36 +01:00
Cory Benfield 0527bbb466 Remove the last remaining NIOAtomic (#607)
Motivation

Warnings aren't great, and NIOAtomic is deprecated.

Modifications

Replace the last use of NIOAtomic with ManagedAtomic.

Result

Fewer warnings
Fixes #606
2022-08-03 10:02:20 +01:00
David Nadoba 2adca4b003 Use swift-atomics instead of NIOAtomics (#603)
`NIOAtomics` was deprecated in https://github.com/apple/swift-nio/pull/2204 in favor of `swift-atomics` https://github.com/apple/swift-atomics
2022-07-13 13:48:24 +01:00
David Nadoba 14fa6d944d Report last connection error if request deadline is exceeded (#601) 2022-07-01 10:39:38 +02:00
David Nadoba 794dc9d427 Add testSelfSignedCertificateIsRejectedWithCorrectError (#594) 2022-06-17 20:32:33 +02:00
Cory Benfield 9a8553e8aa Correctly close the connection if sendEnd fails (#599)
Motivation

If we receive an early HTTP response, the last action on a HTTP/1.1
connection is to send the .end message. While we had an error handling
path in the code, it wasn't tested, and when executed it would end up
leaking the connection by failing to close it _or_ return it to the
pool.

This patch fixes the issue by appropriately terminating the connection
and adding a test.

Modifications

Add a test
Terminate the connection if sendEnd fails

Result

Fewer connection leaks
2022-06-17 17:09:19 +01:00
Cory Benfield ac34f6debc Correctly handle Connection: close with streaming (#598)
Motivation

When users stream their bodies they may still want to send Connection:
close headers and terminate the connection early. This should work
properly.

Unfortunately it became clear that we didn't correctly pass the
information that the connection needed to be closed. As a result, we'd
inappropriately re-use the connection, potentially causing unnecessary
HTTP errors.

Modifications

Signal whether the connection needs to be closed when the final
connection action is to send .end.

Results

We behave better with streaming uploads.
2022-06-17 12:27:03 +01:00
Cory Benfield 062989efd8 Correctly reset our state after .sendEnd (#597)
Motivation

In some cases, the last thing that happens in a request-response pair is
that we send our HTTP/1.1 .end. This can happen when the peer has sent
an early response, before we have finished uploading our body. When it
does, we need to be diligent about cleaning up our connection state.

Unfortunately, there was an edge in the HTTP1ConnectionStateMachine that
processed .succeedRequest but that did not transition the state into
either .idle or .closing. That was an error, and needed to be fixed.

Modifications

Transition to .idle when we're returning
.succeedRequest(.sendRequestEnd).

Result

Fewer crashes
2022-06-17 11:52:29 +01:00
Cory Benfield 2483e08ffb Fix crash when receiving 2xx response before stream is complete. (#591)
Motivation

It's totally acceptable for a HTTP server to respond before a request
upload has completed. If the response is an error, we should abort the
upload (and we do), but if the response is a 2xx we should probably just
finish the upload.

In this case it turns out we'll actually hit a crash when we attempt to
deliver an empty body message. his is no good!

Once that bug was fixed it revealed another: while we'd attempted to
account for this case, we hadn't tested it, and so it turns out that
shutdown would hang. As a result, I've also cleaned that up.

Modifications

- Tolerate empty circular buffers of bytes when streaming an upload.
- Notify the connection that the task is complete when we're done.

Result

Fewer crashes and hangs.
2022-06-07 12:31:57 +01:00
Cory BenfieldandDavid Nadoba 3fcd67061f Improve errors and testing using NIOTS (#588)
Motivation

Currently error reporting with NIO Transport Services is often sub-par.
This occurs because the Network.framework connections may enter the
waiting state until the network connectivity state changes. We were not
watching for the user event that contains the error in that state, so if
we timed out in that state we'd just give a generic timeout error,
instead of telling the user anything more detailed.

Additionally, several of our tests assume that failure will be fast, but
in NIO Transport Services we will enter that .waiting state. This is
reasonable, as changed network connections may make a connection that
was not succeeding suddenly viable. However, it's inconvenient for
testing, where we're mostly interested in confirming that the error path
works as expected.

Modifications

- Add an observer of the WaitingForConnectivity event that records it
  into our state machine for later reporting.
- Add support for disabling waiting for connectivity for testing
  purposes.
- Add annotations to several tests to stop them waiting for
  connectivity.

Results

Faster tests, better coverage, better errors for our users.

Co-authored-by: David Nadoba <dnadoba@gmail.com>
2022-06-01 14:13:47 +01:00
Franz BuschandFabian Fett 24425989da Call didSendRequestPart after the write has hit the socket (#566)
### Motivation

Today `didSendRequestPart` is called after a request body part has been passed to the executor. However, this does not mean that the write hit the socket. Users may depend on this behavior to implement back-pressure. For this reason, we should only call this `didSendRequestPart` once the write was successful.

### Modification

Pass a promise to the actual channel write and only call the delegate once that promise succeeds.

### Result

The delegate method `didSendRequestPart` is only called after the write was successful. Fixes #565.

Co-authored-by: Fabian Fett <fabianfett@apple.com>
2022-04-26 16:04:54 +02:00
Christian Priebe 89b0da2bf8 Add HTTPClientError shortDescription property (#583)
This adds a shortDescription property to HTTPClientError which provides a short
description of the error without associated values.
2022-04-22 07:59:58 +01:00
Fabian Fett 9d8cd95927 [Redirect] Allow redirect response to have body (#580)
### Motivation

Currently, we don’t consume the response body of redirect responses. Because of this requests, that receive a redirect response with response body, may hang indefinitely.

### Changes

- Consume redirect response body if less than 3kb
- Cancel redirect response if larger than 3kb

### Result

Redirect responses are consumed. Fixes #574
2022-04-12 13:40:16 +02:00
Fabian Fett 0a2004b1c6 [HTTP1] Tolerate immediate write errors (#579)
Same fix for HTTP/1 that landed for HTTP/2 in #558.

### Motivation

`HTTP1ClientChannelHandler` currently does not tolerate immediate write errors.

### Changes

Make `HTTP1ClientChannelHandler` resilient to failing writes.

### Result

Less crashes in AHC HTTP/1.
2022-04-11 16:41:10 +02:00
Fabian Fett d2da15c31c [HTTP2] Tolerate GoAway and Settings frames after connection close (#578) 2022-04-11 16:24:57 +02:00
Cory Benfield f50bf983ea Tolerate the request stream being started after .finished (#577)
Motivation

The RequestBag intermediates between two different threads. This means
it can get requests that were reasonable when they were made but have
been superseded with newer information since then. These generally have
to be tolerated.

Unfortunately if we received a request to resume the request body stream
_after_ the need for that stream has been invalidated, we could hit a
crash. That's unnecessary, and we should tolerate it better.

Modifications

Tolerated receiving requests to resume body streaming in the finished
state.

Result

Fewer crashes
Fixes #576
2022-04-11 11:13:56 +02:00