77 Commits

Author SHA1 Message Date
Cory Benfield 3b57e00556 Support selecting a specific local address. (#899)
Motivation

In machines with more complex network topologies it is possible for us
to have multiple possible NICs we might want to use for a request. Users
may wish to vary this on a per-request or even a per-client basis.

This control can typically be expressed by offering a local address to
bind to before making the connection attempt.

Modifications

Allow users to express a preferred local address at request or client
scope.
Make this part of the connection pool key.
Bind the local address when specified.
Test all of this.

Results

More capable clients.
2026-03-23 14:48:45 +00:00
Mads Odgaard c5784ca815 Replace import Foundation with FoundationEssentials (#897)
Replaces all the foundation imports.

One issue is that `HTTPClient.init?(httpsURLWithSocketPath socketPath:
String, uri: String = "/")` uses `addingPercentEncoding()` from
Foundation. So instead, we use a pure Swift impl. that does the same.

We also need to disable default traits from `swift-configuration` to
prevent linking Foundation, because the `JSON` trait does that.

This also adds a linkage test to prevent regressions to CI.
2026-03-13 13:23:14 +00:00
hamzahrmalik ba1d03d8d1 Add option to retain request method on 301/302/303 redirects (#887)
Add a configuration option to retain the HTTP method and body receiving
301 or 302 responses.

Currently we automatically change the method to GET, and remove the
body, before following a 301 or 302. This is compliant with the fetch
specification: https://fetch.spec.whatwg.org/#http-redirect-fetch

However, it is useful to be able to override this behaviour and retain
the method and body.

Changes
- Add a new struct to encapsulate the (now 4) arguments of the follow
case of the redirect mode
- Add new options `retainHTTPMethodAndBodyOn301` and
`retainHTTPMethodAndBodyOn302`. Defaults to false because thats the
existing behaviour today
- When it is true, do not convert requests to GET after following a
redirect
- Note: this does not affect 307/308 (or any other) redirects. They
always preserve their method

---------

Co-authored-by: Fabian Fett <fabianfett@apple.com>
2026-02-20 14:10:24 +00:00
hamzahrmalik 5dd84c7bb4 Remove CollectEverythingLogHandler implementation in favour of InMemoryLogHandler from swift-log (#874)
Swift log now has an InMemoryLogHandler. Lets depend on that instead of
having our own `CollectEverythingLogHandler`.

I've added an extension on top, to make it easier to create the logger
too

Result: less code
2025-12-04 13:33:27 +00:00
Cory Benfield efb14fec9f Resolve SendableMetatype issues (#865)
This resolves warnings around SendableMetatype in the AHC codebase, and
gets our 6.2 builds working again.
2025-10-15 13:06:05 +01:00
George Barnett 3b265e6a00 Enable warnings as errors in CI (#842)
Motivation:

Now that strict concurrency has been adopted the AHC should avoid
regressing by treating all warnings as errors in CI.

Modifications:

- Treat warnings as errors in CI

Result:

Stricter CI
2025-05-08 10:51:33 +01:00
George Barnett 4de7a26ca5 Fix a number of sendable warnings in test utilities (#836)
Motivation:

The test utilities have a number of sendability issues.

Modifications:

- Fix the issues

Result:

Fewer warnings
2025-04-29 18:48:45 +01:00
Marc Prud'hommeaux e69318d4cb Android support (#799)
This PR adds support for Android, mostly just by importing the Android
module when needed.
2025-01-14 16:39:43 +00:00
Cory Benfield 126518507b Unbreak CI (#800)
# Motivation

The NIO 2.78 release introduced a bunch of new warnings. These warnings
cause us a bunch of trouble, so we should fix them.

# Modifications

Mostly use a bunch of assumeIsolated() and syncOperations.

# Result 

CI passes again.

Note that Swift 6 has _many_ more warnings than this, but we expect more
to come and we aren't using warnings-as-errors on that mode at the
moment. We'll be cleaning that up soon.
2025-01-14 16:34:21 +00:00
Rick Newton-Rogers dbd5c864ad Enable MemberImportVisibility check on all targets (#794)
Enable MemberImportVisibility check on all targets. Use a standard
string header and footer to bracket the new block for ease of updating
in the future with scripts.
2024-12-13 15:07:57 +01:00
Johannes Weiss 2119f0d9cc fix 784: dont crash on huge in-memory bodies (#785)
fixes #784 

`writeChunks` had 3 bugs:
1. An actually wrong `UnsafeMutableTransferBox` -> removed that type
which should never be created
2. A loooong future chain (instead of one final promise) -> implemented
3. Potentially infinite recursion which lead to the crash in #784) ->
fixed too
2024-11-26 14:52:39 +00:00
Rick Newton-Rogers c621142327 Adopt GitHub actions (#780)
Migrate CI to use GitHub Actions.

### Motivation:

To migrate to GitHub actions and centralised infrastructure.

### Modifications:

Changes of note:
* Adopt swift-format using rules from SwiftNIO.
* Remove scripts and docker files which are no longer needed.
* Disabled warnings-as-errors on Swift 6.0 CI pipelines for now.

### Result:

Feature parity with old CI.
2024-10-29 15:01:46 +00:00
Ian Anderson 6df8e1c17e Explicitly import locale modules (#771)
The Darwin module is slowly being split up, and as it gets further
along, it will stop importing some of the split-out modules like the one
for locale.h that provides newlocale() and other locale API. However,
there's a wrinkle that on platforms with xlocale, it's xlocale.h that
provides most of the POSIX locale.h functions and not locale.h, so
prefer the xlocale module when available.
2024-09-14 07:55:55 +01:00
Gustavo Cairo a22083713e Disable SETTINGS_ENABLE_PUSH HTTP/2 setting (#741) 2024-05-01 12:49:09 +01:00
Alastair Houghton 09b7eb751e Add support for Musl. (#726)
Motivation:

We would like to make this work for Musl so that we can build fully
statically linked binaries that use AsyncHTTPClient.

Modifications:

Define `_GNU_SOURCE` as a compiler argument; doing it in a source file
doesn't work properly with modular headers.

Add imports of `Musl` in appropriate places.

`Musl` doesn't have `strptime_l`, so avoid using that.

Result:

async-http-client will build for Musl.
2024-01-19 16:09:35 -08:00
Peter Adams c70e085679 testPlatformConnectErrorIsForwardedOnTimeout port reuse (#716)
Motivation:

The above test has been seen to fail with port already in use.
The test assumes that a port can be bound to twice in a row.
It's possible that another process takes the port between the two
binds - this can be stopped by binding a second time before stopping
the first.

Modifications:

Allow port reuse and reorder the test to bind a second time before
releasing the first.

Result:

Test should no longer be flaky.
2023-11-03 06:58:47 -07:00
brenno df66c67cad Fixed typo (#695) 2023-06-30 12:18:05 +02:00
carolinacass 91b26407ad Update collect to use content-length to make early checks
Motivation:
not accumulate too many bytes

Modifications:
Implementing collect function to use NIOCore version to prevent overflowing

Co-authored-by: Cory Benfield <lukasa@apple.com>
2023-04-04 16:56:58 +01:00
David Nadoba 98b45ed1cd Allow DNS override (#675)
Sometimes it can be useful to connect to one host e.g. `x.example.com` but request and validate the certificate chain as if we would connect to `y.example.com`. This is what this PR adds support for by adding a `dnsOverride` configuration to `HTTPClient.Configuration`. This is similar to curls `—resolve-to` option but only allows overriding host and not ports for now.
2023-03-30 08:21:41 +01:00
David Nadoba 59bfb96afb Add test for HTTP2 request with large header (#659)
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.
2023-01-26 14:26:58 +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
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
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
David Nadoba 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
Cory Benfield 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 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
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
Karl 972bcddedc Redo HTTP cookie parsing (#510)
* Redo HTTP cookie parsing using strptime

* Make String(utf8Slice:from:) less ugly

* Adjust cookie component parsing to better match RFC-6562
2022-01-06 16:40:55 +00:00
Fabian Fett 65d97ff5ff Improve test utils for running request (#512)
### Motivation

To land support for async/await, we need test utilities. We already have a `MockRequestExecutor`. Let's improve this to better handle on and off `EventLoop` request processing.

### Changes

- Move `MockRequestExecutor` into its own file
- Add blocking APIs to `MockRequestExecutor` when called from another thread
2021-12-03 16:33:43 +01:00
Fabian Fett 70826d038d Add h2 stream integration tests (#502) 2021-12-01 09:27:59 +01:00
David Nadoba 9eaecbbbce SwiftFormat --ifdef no-indent (#494)
* SwiftFormat --ifdef no-indent

* update `generate_linux_tests.rb` to use new indention rule
2021-11-25 17:09:19 +01:00
Fabian Fett e5022468bb Update swiftformat to 0.48.8 (#491)
### Motivation

Our current swiftformat version does not support async/await. Since we want to add support for async/await we must update swiftformat or disable it. I tried my very best to keep the number of changes as small as possible. I assume we want to stick with the new 0.48.8 for some time.

### Changes

- Update swiftformat to 0.48.8

### Result

We can land async/await code.
2021-11-25 10:15:36 +01:00
Karl 6426c00d84 [Tests] Add some basic IPv6 tests (#483)
Co-authored-by: Cory Benfield <lukasa@apple.com>
2021-11-23 12:25:06 +00:00
Fabian Fett 7617c35db3 Handle NIOSSLError.uncleanShutdown correctly (#472)
### Motivation

Fixes #238 and #231.

### Changes

- Extracted the unclean shutdown test from `HTTPClientTests` into their own file `HTTPClientUncleanSSLConnectionShutdownTests`
- Copy and pasted @weissi great explanation from #238 into the test file
- Removed property `ignoreUncleanSSLShutdown` everywhere

### Result

`ignoreUncleanSSLShutdown` on `HTTPClient.Configuration` is deprecated and ignored.

Co-authored-by: Johannes Weiss <johannesweiss@apple.com>
2021-11-11 11:02:54 +01:00
David Nadoba cc8e7a68a2 basic http2 integration tests (#467) 2021-11-10 10:47:04 +01:00
Fabian Fett 2bd88855b4 Remove deprecated connection pool (#443)
- Remove now unused Connection/ConnectionPool
- Removed TaskHandler
- Remove ResponseReadBuffer
- Removed further now unused code
- Remove unused imports
- Remove test util `RecordingHandler`
2021-09-29 18:42:24 +02:00
Fabian Fett fb49c1be5f Add new HTTPConnectionPool Manager (#420)
Co-authored-by: George Barnett <gbarnett@apple.com>
2021-09-10 17:25:41 +02:00
Fabian Fett eab2a84b1c Use explicit NIO imports (#407)
* Use explicit NIO imports for `NIOCore`, `NIOPosix` and `NIOEmbedded`
* Updated dependencies
2021-08-19 21:11:49 +02:00
Fabian Fett da5da25c60 Fix bi directional streaming test (#405)
The bi directional streaming test writes and reads from an echo server.
2021-08-12 12:45:41 +02:00
Fabian Fett af837edfcb Add http/2 support to HTTPBin (#382)
- Add `swift-nio-http2` as a dependency to the Package.swift (only used in the test target so far).
- Remove unused initialization options for `HTTPBin`
- The initialization options `ssl: Bool = false, compress: Bool = false, refusesConnections: Bool = false` move into a `Mode` enum. The mode might be `.http1_1(ssl: Bool, compress: Bool)`, `.http2(compress: Bool)`, or `.refuse`
- Added support for `http/2` (not used in any tests yet, however I verified the support with curl locally.)
- Nearly all channel pipeline modifications in `HTTPBin` are synchronous now.
- HTTPBin's request handler is configurable. This allows testing of more esoteric cases without having to create a new server every time. The default `HTTPBin` continues to use the `HTTPBinHandler`.
2021-06-25 11:53:58 +02:00
David Evans 102b7e4bce Update NIO family dependencies to 5.2+ versions and fix deprecations (#381)
Updated:

NIO
NIOSSL
NIO Extras
NIOTS
Also fix TLSConfiguration.forClient() warnings by converting to TLSConfiguration.makeClientConfiguration(). Also the same for forServer().
2021-06-23 14:58:08 +01:00
Fabian Fett 210b54f0c0 Fixes the DelayOnHeadDelegate test utility (#374)
Currently the DelayOnHeadDelegate test utility depends on correct timings. Right now, if a request is slower than 50ms in  `testErrorAfterCloseWhileBackpressureExerted` the test will fail, since the backpressure promise is failed, before a head was received. This pr fixes this, by giving the user a callback, when the head was received.
2021-06-16 12:29:16 +01:00
Cory Benfield e4fded76ac Better backpressure management. (#352)
Motivation:

Users of the HTTPClientResponseDelegate expect that the event loop
futures returned from didReceiveHead and didReceiveBodyPart can be used
to exert backpressure. To be fair to them, they somewhat can. However,
the TaskHandler has a bit of a misunderstanding about how NIO
backpressure works, and does not correctly manage the buffer of inbound
data.

The result of this misunderstanding is that multiple calls to
didReceiveBodyPart and didReceiveHead can be outstanding at once. This
would likely lead to severe bugs in most delegates, as they do not
expect it.

We should make things work the way delegate implementers believe it
works.

Modifications:

- Added a buffer to the TaskHandler to avoid delivering data that the
   delegate is not ready for.
- Added a new "pending close" state that keeps track of a state where
   the TaskHandler has received .end but not yet delivered it to the
   delegate. This allows better error management.
- Added some more tests.
- Documented our backpressure commitments.

Result:

Better respect for backpressure.

Resolves #348
2021-03-30 11:39:35 +01:00
Artem Redkin 5d9b784d69 Fixes bi-directional streaming (#344)
Motivation:
When we stream request body, current implementation expects that body
will finish streaming _before_ we start to receive response body parts.
This is not correct, reponse body parts can start to arrive before we
finish sending the request.

Modifications:
 - Simplifies state machine, we only case about request being fully sent
   to prevent sending body parts after .end, but response state machine
   is mostly ignored and correct flow will be handled by NIOHTTP1
   pipeline
 - Adds HTTPEchoHandler, that replies to each response body part
 - Adds bi-directional streaming test

Result:
Closes #327
2021-03-03 17:10:48 +00:00
Cory Benfield 1aec5d7d0e Add defensive connection closure. (#328)
Motivation:

Currently when either we or the server send Connection: close, we
correctly do not return that connection to the pool. However, we rely on
the server actually performing the connection closure: we never call
close() ourselves. This is unnecessarily optimistic: a server may
absolutely fail to close this connection. To protect our own file
descriptors, we should make sure that any connection we do not return
the pool is closed.

Modifications:

If we think a connection is closing when we release it, we now call
close() on it defensively.

Result:

We no longer leak connections when the server fails to close them.

Fixes #324.
2021-01-19 17:27:09 +00:00
Max Desiatov 49a0d30fa3 Add FileDownloadDelegate for simple file downloads (#275)
* Add FileDownloadDelegate for simple file downloads

* Add testFileDownload to the allTests array

* Fix formatting

* Fix compatibility with Swift 5.0

* Add doc comments, update README.md

* Refine FileDownloadDelegate description in README

* Bump NIO version, remove weak self, cleanup test

* Fix formatting issues in a doc comment

* Create separate Progress struct, async open file

* Create an ad-hoc EventLoopGroup for opening a file

* Move file opening code to `didReceiveBodyPart`

* Fix linter error in FileDownloadDelegate.swift

* Fix wrong future assignment in FileDownloadDelegate

* Fix Swift 5.0 return statement compatibility

* Fix linter warning

* Fix Swift 5.0 return statement compatibility

* Remove redundant `write` function

* Add negative test case and separate testing endpoint

* Add missing testFileDownloadError to the manifest
2020-09-10 08:30:19 +01:00
Cory Benfield 8b23060fee Kill build warnings. (#283)
Motivation:

Build warnings fail our builds.

Modifications:

- Update minimum NIOSSL version
- Remove the use of the now-unnecessary `try` statement.

Result:

No warnings!
2020-07-16 17:26:26 +01:00