Commit Graph
548 Commits
Author SHA1 Message Date
Fabian Fett 9db886d105 Merge branch 'main' into ff-new-http-client-api 2026-04-24 14:13:21 +02:00
George Barnett 8cfd301b41 Update test certs (#901)
Motivation:

The cert used in some tests has expired so tests now fail

Modifications:

- Regenerate

Result:

Tests pass
2026-04-02 16:42:33 +00:00
Si Beaumont 3a5b74a587 Fix compilation on nightly-main Swift, which has new optional type inference (#900) 1.33.1 2026-03-24 14:29:58 +00:00
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.
1.33.0
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.
1.32.1
2026-03-13 13:23:14 +00:00
Fabian FettandGeorge Barnett c3a3925b7e Fix crash when response completes before request body finishes uploading (#895)
- Fix a `fatalError("Invalid state: idle")` crash in
`HTTP1ConnectionStateMachine.demandMoreResponseBodyParts()` that occurs
when a response completes before the request body finishes uploading
- The root cause is that `self.request` was only nilled out inside the
write-completion callback for `.sendRequestEnd`, creating a window where
`demandResponseBodyStream` could still see the old request and call into
the state machine after it had already transitioned to .idle
- The fix nils out `self.request` synchronously when handling
`.sendRequestEnd` (before the write completes), and moves
`requestBodyStreamSent()` to fire after the final action rather than
before it

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2026-03-03 14:31:01 +00:00
Rick Newton-Rogers f55968148d update actions/checkout from v4 to v6 (#896)
Motivation

* Following [GitHub's
announcement](https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/),
Node 20 is being deprecated and runners will begin using Node 24 by
default starting March 4th, 2026. Node 20 will reach end-of-life in
April 2026.

Modifications

* Upgrade GitHub Actions to their latest versions to ensure
compatibility with Node 24.
* Replace `actions/checkout@v4` with `actions/checkout@v6` in all
workflow files.

Result

* Workflow files reference `actions/checkout@v6`.
2026-03-02 13:33:33 +00:00
Xyan Bhatnagar 58d9e2172d Fix bug with response header creation (#892) 2026-02-25 18:29:38 +01:00
Fabian Fett 4073ca0a28 Merge branch 'main' into ff-new-http-client-api 2026-02-25 16:22:08 +01:00
Fabian Fett 209722da53 Make CI green?! 2026-02-25 16:18:09 +01:00
Tom Stovall 2fc4652fb4 Add explicit swift-service-context dependency (#891) 1.32.0 2026-02-25 12:42:35 +00:00
hamzahrmalikandFabian Fett 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
Rick Newton-Rogers 101258d831 switch from main to 0.0.7 for swiftlang workflows (#889)
Motivation

* `@main` references to `swiftlang/github-workflows` are deprecated.

Modifications

* Replace `@main` with `@0.0.7` in all workflow files.

Result

* Workflow files reference a pinned version of
`swiftlang/github-workflows`.
2026-02-20 11:52:36 +01:00
Fabian Fett b0e0847f2c swift format 2 2026-02-18 14:49:37 +01:00
Fabian Fett e636653ecf Swift format 2026-02-18 14:45:02 +01:00
Fabian Fett 6584afb56e Cleanup 2026-02-18 14:23:10 +01:00
Fabian Fett 8c3516bcbf Hide feature behind experimental trait... 2026-02-18 14:20:44 +01:00
Fabian Fett 10cc2b4053 Further small ajdustments 2026-02-12 14:00:44 +01:00
Fabian Fett c4eacee92b Count cars demo 2026-02-12 13:00:58 +01:00
Fabian Fett 06619de908 More post stuff 2026-02-12 12:22:39 +01:00
Fabian Fett e214892ecd Sending a payload is working! 2026-02-12 12:07:22 +01:00
Fabian Fett b0a7431c90 Trailers are working! 2026-02-11 16:40:43 +01:00
Fabian Fett 1dec19fed4 Tests pass
Remove debug line
2026-02-11 15:30:36 +01:00
Cory Benfield 52ed9d1720 Use a smaller max buffer size on 32-bit platforms (#886)
Resolves #884
1.31.0
2026-02-11 10:11:12 +00:00
Fabian Fett 67ac92dc76 Support sending and receiving trailers in HTTPExecutableRequest (#882)
This pr adds all the internal wiring in `HTTP1ClientChannelHandler` and
`HTTP2ClientRequestHandler` to send and receive HTTP trailers.
2026-02-10 11:53:56 +01:00
hamzahrmalik 986dc47c11 Add swift-configuration support (#878)
Users should be able to use swift-configuration to create the http
client configuration object

Changes
- duplicate package.swift to create a separate version for 6.0 and 6.1, 
since Configuration is 6.2+
- add helper to create http client configuration using ConfigReader
2026-02-05 12:12:14 +01:00
Fabian FettandGeorge Barnett e2ab0d176f Full support for bidirectional streaming (#879)
> ## Note: 
> This is a long LLM generated PR description. However it captures very
well, what has been changed and has already been reduced for brevity.
The PR is sadly quite complex but I think the description captures the
changes quite well.

This is foundational work needed to properly support HTTP trailers and
scenarios where the server sends a complete response before the client
finishes uploading (e.g., early rejection, 100-continue flows, or
bidirectional streaming protocols).

## Changes

### State Machine Improvements

- **Added `endForwarded` state** to
`Transaction.StateMachine.RequestStreamState`
- This new state distinguishes between "request data forwarded to the
channel" and "request data written to the network"
- Properly handles the race condition where response completes before
the request write completes

- **Renamed `succeedRequest` → `forwardResponseEnd`** in both
`HTTPRequestStateMachine.Action` and
`HTTP1ConnectionStateMachine.Action`
- Better reflects the semantic meaning: we're forwarding the end of the
response stream, not necessarily succeeding the entire request yet
  - More accurate naming for bidirectional streaming scenarios

### Protocol Changes

- **Added `requestBodyStreamSent()` to `HTTPExecutableRequest`
protocol**
- Called by the channel handler when the request body stream has been
fully written to the network
- Allows proper coordination between request and response stream
completion
  - Implemented in both `Transaction` and `RequestBag`

### Request State Machine Updates

- **Updated `FinalSuccessfulRequestAction`**
- Changed `.sendRequestEnd(EventLoopPromise<Void>?)` to simpler
`.requestDone`
- Added `.none` case for when response completes but request is still
in-flight
- Removed the need to pass promises around, simplifying the state
machine

- **`sendRequestEnd` action now includes
`FinalSuccessfulRequestAction`**
- Allows the state machine to signal what should happen after the
request completes
- Enables proper cleanup coordination (idle connection, close, or
continue)

### Channel Handler Updates

- **HTTP1ClientChannelHandler**
- `sendRequestEnd` now properly handles scenarios where response has
already completed
- Added future callback to coordinate request completion with final
actions
- Properly manages connection state (idle vs close) based on both
streams completing

- **HTTP2ClientRequestHandler**
  - Updated to handle new `sendRequestEnd` signature
  - Properly ignores HTTP/1-specific final actions (like `.requestDone`)

### RequestBag State Machine

- **Added `endReceived` state to `ResponseStreamState`**
- Tracks when the response has completed while request is still ongoing
- Enables proper sequencing: response end → request end → task
completion

- **Updated `FinishAction`**
- Added `.forwardStreamFinishedAndSucceedTask` for the case where both
streams complete simultaneously
  - Ensures delegate methods are called in the correct order

### Error Handling

- **Improved failure handling in `Transaction.StateMachine`**
- Now properly handles errors that occur after response completes but
before request finishes
  - Added `cancelExecutor` action to the fail path
- Executor is now passed to `failRequestStreamContinuation` for proper
cleanup

## Technical Details

### The Problem

Previously, when a server sent a complete response before the client
finished uploading the request body, AHC would:
1. Receive the full response (head, body, end)
2. But NOT inform the user that the response was complete if the request
was still streaming
3. Only succeed the request after both streams completed

This made it impossible to implement proper bidirectional streaming or
handle scenarios like:
- Server rejecting a large upload early (e.g., 413 Payload Too Large)
- 100-continue flows where the server responds before request completes
- HTTP trailers sent by the server

### The Solution

The new state machine properly tracks four completion states:
1. **Neither complete**: Normal request/response in flight
2. **Response complete, request ongoing**: New
`endForwarded`/`endReceived` states
3. **Request complete, response ongoing**: Existing logic
4. **Both complete**: Request succeeds

The key insight is the `endForwarded` state, which represents "we've
given all request data to the channel, but it hasn't been written to the
network yet". This allows us to:
- Immediately forward response completion to the user
- Wait for the write to complete before cleaning up resources
- Properly sequence connection state transitions

## Future Work

This PR lays the groundwork for:
- Proper internal HTTP trailer support (both sending and receiving)

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2026-02-03 12:21:31 +01:00
Fabian Fett 4b99975677 Rename succeedRequest to receiveResponseEnd (#877) 1.30.3 2026-01-08 11:36:36 +00:00
Fabian Fett 5fd3d5ce22 Mark HTTPClientRequest.Prepared as Sendable (#876)
`Transaction` is @unchecked Sendable, since its NIOLockedValueBox can
not infer Sendability if its value isn't Sendable. The @unchecked
Sendable annotation has hidden the fact, that
`HTTPClientRequest.Prepared` needs to be Sendable as well. Let's make
this right in this PR.
2026-01-07 07:55:53 +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
1.30.2
2025-12-04 13:33:27 +00:00
George Barnett c464bf94ea Don't hold a lock over a continuation in test helpers (#872)
Motivation:

The various 'withMumbleContinuation' APIs are supposed to be invoked
synchronously with the caller. This assumption allows a lock to be
acquired before the call and released from the body of the
'withMumbleContinuation' after e.g. storing the continuation. However
this isn't the case and the job may be re-enqueued on the executor
meaning that this is pattern is vulnerable to deadlocks.

Modifications:

- Rework the test helpers to avoid holding a lock when a continuation is
created.
- Switch to using NIOLockedValue box

Result:

Lower chance of deadlock
1.30.1
2025-12-01 12:36:23 +01:00
Fabian FettandGeorge Barnett 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
George Barnett ce04df0613 Don't hold a lock over a continuation in Transaction (#871)
Motivation:

The various 'withMumbleContinuation' APIs are supposed to be invoked
synchronously with the caller. This assumption allows a lock to be
acquired before the call and released from the body of the
'withMumbleContinuation' after e.g. storing the continuation. However
this isn't the case and the job may be re-enqueued on the executor
meaning that this is pattern is vulnerable to deadlocks.

Modifications:

- Drop and reacquire the lock in Transaction

Result:

Lower chance of deadlock
2025-11-26 14:13:29 +00:00
Cory Benfield b2faff932b Drop Swift 5.10 (#870) 1.30.0 2025-11-07 08:50:46 -05:00
Rick Newton-Rogers b2ae84569c Add explicit read permissions to workflows (#867)
Motivation:

* More secure GitHub Actions workflows

Modifications:

Add explicit 'contents: read' permissions to workflows that did not have
explicit permissions defined. This follows GitHub Actions security best
practices by limiting the default GITHUB_TOKEN permissions.

Result:

An extra layer of security.
2025-10-30 16:43:10 +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.
1.29.1
2025-10-15 13:06:05 +01:00
Cory Benfield 0ce87cb315 Avoid delays when inserting HTTP/2 handlers. (#864)
Motivation

Right now, we insert HTTP/2 handlers in a callback on a future that is
done very late. The result of this is that an entire ALPN negotiaton
_can_ complete before this callback is attached. That can in rare cases
cause the HTTP/2 handler to miss the server preamble, because it gets
added too late.

Modifications

This patch refactors the existing code to close that window. It does so
by passing a promise into the connection path and completing that
promise _on_ the event loop where we add the ALPN handlers, which should
ensure this will execute immediately when the ALPN negotiation
completes. Immportantly, we attach our promise callbacks to that promise
_before_ we hand it off, making sure the timing windows go away.

Results

Timing window is closed
2025-10-14 15:43:56 +01:00
Konrad `ktoso` Malawski 353bbc8cc2 [Tracing] Implement trace header context propagation (#862) 2025-10-10 08:35:50 +01:00
Konrad `ktoso` Malawski c2a3a2cfb7 [Tracing] Default tracer to global bootstrapped tracer (#861) 2025-10-09 17:01:05 +09:00
8430dd49d4 Introduce built-in swift-distributed-tracing support (#857)
Co-authored-by: Moritz Lang <16192401+slashmo@users.noreply.github.com>
Co-authored-by: George Barnett <gbarnett@apple.com>
1.29.0
2025-10-07 16:30:31 +09:00
Rick Newton-Rogers 31c8b047b5 Enable Swift 6.2 jobs in CI (#859)
Motivation:

Swift 6.2 has been released, we should add it to our CI coverage.

Modifications:

Add additional Swift 6.2 jobs where appropriate in main.yml,
pull_request.yml

Result:

Improved test coverage.
2025-09-22 14:28:49 +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.
1.28.0
2025-09-09 09:55:45 +01:00
Gwynne Raskind 254d340961 Fix trailing space in ConnectionPool.Key string (#855)
Motivation:

The trailing space is visible in log message metadata, and depending
upon the log handler in use, will sometimes be visible due to quoting.

Modifications:

Just remove the trailing space.

Result:

There won't be a trailing space in the key anymore. This has no
functional impact whatsoever as far as I was able to determine.
1.27.0
2025-08-24 16:55:12 -04:00
Johannes Weiss abb11d5b90 make HTTPClient Sendable without @unchecked (#852)
Previously, `HTTPClient` used `@unchecked Sendable`, now it's compiler
checked.
2025-08-12 10:04:16 +01:00
George Barnett 2edac1df19 Deflake HTTP2ConnectionTests/testSimpleGetRequest (#851)
Motivation:

testSimpleGetRequest asserts right after submitting the request for
execution that no streams have been closed. While unlikely there's
nothing to prevent this assertion from failing (and indeed it has
failed): the request may have executed immediately and the stream closed
before checking the delegate.

Modifications:

- Remove the assertion

Result:

Tests are less flaky
2025-08-04 10:17:30 +01:00
Raphael 64021b3066 Enable release mode builds (#850)
### Motivation:

Some errors do not show up in debug builds. Enabling release mode builds
improves the CI coverage.

### Modifications:

Enable release mode builds for pull requests and scheduled builds on
main.

### Result:

Improved CI coverage.
2025-07-30 08:55:42 +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 20216dfe9d Drop support for Swift 5.9 (#845) 2025-05-22 11:56:34 +01:00
George Barnett 6023598316 Fix 5.9 build (#844)
Motivation:

An oversight in 373862a meant that 5.9 wasn't actually dropped which
means that the use of 'nonisolated(unsafe)' in 0e715a27 broke users of
5.9.

Modifications:

- Add back a 5.9 path

Result:

- Builds on 5.9
- Resolves #843
1.26.1
2025-05-22 11:07:10 +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
1.26.0
2025-05-08 10:51:33 +01:00