37 Commits

Author SHA1 Message Date
Fabian Fett 3c45dbde2d Fix Connection Creation Crash (#873)
### Motivation

When creating a connection, we wrongfully assumed that
`failedToCreateNewConnection` will always be called before
`http*ConnectionClosed` in the `HTTPConnectionPoolStateMachine`. However
this is far from correct. In NIO Futures are fulfilled before
`ChannelHandler` callbacks. Ordering in futures should not be assumed in
such a complex project.

### Change

We change the `http*ConnectionClosed` methods to be noops, if the
connection is in the starting state. We instead wait for the
`failedToCreateNewConnection` to create backoff timers and friends.

rdar://164674912

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2025-12-01 09:31:32 +01:00
Cory Benfield 7dc119c7ed Add support for HTTP/1 connection pre-warming (#856)
Motivation

This patch adds support for HTTP/1 connection pre-warming. This allows
the user to request that the HTTP/1 connection pool create and maintain
extra connections, above-and-beyond those strictly needed to run the
pool. This pool can be used to absorb small spikes in request traffic
without increasing latency to account for connection creation.

Modifications

- Added new configuration properties for pre-warmed connections.
- Amended the HTTP/1 state machine to create new connections where
necessary.
- Added state machine tests.

Results

Pre-warmed connections are available.
2025-09-09 09:55:45 +01:00
jessezamora 0b6f957d33 Use Int64.random instead of .randomElement in HTTPConnectionPool.calculateBackoff (#848)
Fixes #847. 

Motivation:

On 32-bit systems, using .randomElement on a range larger than what can
fit in Int32 (Int) causes a crash. After only 26 or 27 retries of a
request using HTTPClient, the calculateBackoff method would run into
this and crash consistently on an armv7 (32-bit) device.

Modifications:

A one-line fix to opt to using Int64.random on the same jitterRange
instead of .randomElement, which works as expected without crashing on
32-bit systems.

Result:

The HTTPClient now works as expected and can perform as many retries as
needed without crashing.

I tested this on my armv7 board doing the retries, and ran up to several
hundred repetitions after a few hours with no crashes as was happening
before.

@Lukasa
2025-07-11 14:33:27 +00:00
George Barnett 0e715a2793 Fix a few simple sendability issues (#832)
Motivation:

We're about to go on a sendability journey. Let's pick some low hanging
fruit to get started.

Modifications:

- Add a few assume-isolated calls
- Stop using static var
- Use a dispatch group instead of a work item to wait for work to be
done.

Result:

Fewer warnings
2025-04-28 14:17:36 +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
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
Ayush Garg 1290119b31 Assume http2 connection by default, instead of http1 (#758)
Since most of the servers now conform to http2, the change here updates
the behaviour of assuming the connection to be http2 and not http1 by
default. It will migrate to http1 if the server only supports http1.
One can set the `httpVersion` in `ClientConfiguration` to `.http1Only`
which will start with http1 instead of http2.

Additional Changes:

- Fixed an off by one error in the maximum additional general purpose
connection check
- Updated tests

---------

Co-authored-by: Ayush Garg <ayushgarg@apple.com>
Co-authored-by: David Nadoba <d_nadoba@apple.com>
Co-authored-by: Fabian Fett <fabianfett@apple.com>
2024-08-15 14:26:52 +02:00
aryan-25 4b7a68e997 Fix OOM issue when setting concurrentHTTP1ConnectionsPerHostSoftLimit to Int.max (#763)
### Motivation:

When a user wishes to make the connection pool create as many concurrent
connections as possible, a natural way to achieve this would be to set
`.max` to the `concurrentHTTP1ConnectionsPerHostSoftLimit` property.

```swift
HTTPClient.Configuration().connectionPool = .init(
    idleTimeout: .hours(1),
    concurrentHTTP1ConnectionsPerHostSoftLimit: .max
)
```

The `concurrentHTTP1ConnectionsPerHostSoftLimit` property is of type
`Int`. Setting it to `Int.max` leads to `Int.max` being passed as an
argument to `Array`s `.reserveCapacity(_:)` method, causing an OOM
issue.

Addresses Github Issue #751 

### Modifications:

Capped the argument to `self.connections.reserveCapacity(_:)` to 1024 in
`HTTPConnectionPool.HTTP1Connections`

### Result:

Users can now set the `concurrentHTTP1ConnectionsPerHostSoftLimit`
property to `.max` without causing an OOM issue.
2024-08-14 11:56:26 +02: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
George Barnett 6c5058ee2c Add a control to limit connection reuses (#678)
Motivation:

Sometimes it can be helpful to limit the number of times a connection
can be used before discarding it. AHC has no such support for this at
the moment.

Modifications:

- Add a `maximumUsesPerConnection` configuration option which defaults
  to `nil` (i.e. no limit).
- For HTTP1 we count down uses in the state machine and close the
  connection if it hits zero.
- For HTTP2, each use maps to a stream so we count down remaining uses
  in the state machine which we combine with max concurrent streams to
  limit how many streams are available per connection. We also count
  remaining uses in the HTTP2 idle handler: we treat no remaining uses
  as receiving a GOAWAY frame and notify the pool which then drains the
  streams and replaces the connection.

Result:

Users can control how many times each connection can be used.
2023-04-11 14:49:44 +01:00
David Nadoba 5bee16a799 Switch over state in HTTPConnectionPool.HTTP2StateMachine.failedToCreateNewConnection (#647) 2022-11-09 15:30:16 +01:00
David Nadoba f17a47e916 Allow immediate request failure on connection error (#625) 2022-10-10 13:34:42 +01:00
David Nadoba 14fa6d944d Report last connection error if request deadline is exceeded (#601) 2022-07-01 10:39:38 +02:00
Cory Benfield 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
David Nadoba e4b11eb547 Fix HTTP1 to HTTP2 migration while shutdown is in progress (#530)
* Fix HTTP1 to HTTP2 migration while shutdown is in progress

### Motivation
Calling `HTTPClient.shutdown()` may never return if connections are still starting and one new established connection results in a state migration (i.e. from HTTP1 to HTTP2 or vice versa). We forgot to migrate the shutdown state. This could result in a large dealy until `.shutdown()` returns because we wait until connections are closed because of idle timeout. Worse, it could also never return if more requests are queued because the connections would not be idle and therefore not close itself.
###Changes
- Mirgrate shutdown state too
- add tests for this specific case

* simplify testMigrationFromHTTP1ToHTTP2WhileShuttingDown
* add http2 to http1 migration test
2021-12-17 14:44:11 +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
David Nadoba b479afe4c8 Fix bug in migration from HTTP1 to HTTP2 and back to HTTP1 (#486) 2021-11-22 12:33:57 +01:00
Fabian Fett 2fe3f42fee Crash fix: HTTP2Connections emit events after the pool has closed them. (#481) 2021-11-19 12:33:08 +01:00
David Nadoba 18a58bb874 [HTTP2] Improve performance of backoff timer done event (#464) 2021-11-03 14:29:24 +00:00
David Nadoba 149b8d2656 [HTTP2] Integrate HTTP2StateMachine into HTTPConnectionPool.StateMachine (#462) 2021-11-02 11:51:18 +00:00
David Nadoba 4147fd647d [HTTP2] Create new connections during migration if needed (#459) 2021-10-27 18:28:51 +02:00
David Nadoba c1a60d8aa4 [HTTP2] Prepare migration actions (#456) 2021-10-13 17:11:04 +02:00
Cory Benfield 1081b0b054 Don't crash when hitting long backoffs. (#458)
Motivation:

If we backoff sufficiently far we can overflow Int64, which will cause
us to crash.

Modifications:

Clamp the backoff value before we convert to Int64.

Results:

No crashes!
2021-10-13 13:09:54 +01:00
David Nadoba a0b09857d8 [HTTP2StateMachine] test and fix HTTP2 go away (#452) 2021-10-05 13:59:09 +02:00
David Nadoba a57c4b309c [HTTP2ConnectionPool] added HTTP2StateMachine (#447) 2021-10-05 11:19:41 +02:00
David Nadoba 96963810cb [HTTP2Connections] Return if connection was idle before lease (#451) 2021-10-02 14:06:13 +02:00
Fabian Fett a6ca288e18 [HTTPConnectionPool] StateMachine has explicit function for HTTP1 connection close (#448) 2021-10-01 12:50:13 +02:00
David Nadoba e4e233a2b1 remove umbrella NIO imports and add soundness check (#446) 2021-09-29 17:42:42 +02:00
David Nadoba 628b942522 prepare calculateBackoff(failedAttempt:) to be used in HTTP2StateMachine (#445) 2021-09-29 16:43:10 +02:00
David Nadoba 88d47f12ca [HTTP2ConnectionPool] added HTTP2Connections struct (#440)
One step closer to support HTTP/2 in the new connection pool. 
`HTTP2Connections` will be used in a new `HTTP2StateMaschine` in a follow up PR.
2021-09-28 12:06:54 +02:00
Fabian Fett 0c36de21d6 HTTPConnectionPool timeout requests: preserve connection errors
If a request times out because no connection could be attained, we should fail the request with the last connection creation error. If no connection creation error is present and there is no active connection, we fail the request with a connectTimeout error.
2021-09-13 18:22:29 +02:00
Fabian Fett 7bb58e536c Fix a race between shutdown and backoff timer (#419) 2021-09-09 17:01:07 +02:00
Fabian Fett 4d726bad8d Add ConnectionPool HTTP1StateMachine (#416) 2021-09-09 15:34:03 +02:00
Fabian Fett 05e570dd87 Add MockTools for testing HTTP1ConnectionPool.StateMachine (#417)
Co-authored-by: Cory Benfield <lukasa@apple.com>
2021-09-08 17:45:09 +02:00
Fabian Fett 7d3c578472 HTTP1Connections state machine for ConnectionPool (#413)
Co-authored-by: George Barnett <gbarnett@apple.com>
2021-09-06 12:56:20 +02:00
Fabian Fett 1f5b633457 Add a RequestQueue for the ConnectionPool (#412) 2021-09-01 13:55:06 +02:00