Commit Graph
139 Commits
Author SHA1 Message Date
Joannis Orlandos e65f581985 Add support for Windows 2025-11-05 14:05:27 +01:00
George BarnettandGitHub 0397ea8392 Fix sendability issues in tests (#841)
Motivation:

The tests shouldn't be making sendability violations.

Modifications:

Fix the warnings

Result:

- No warnings
- Strict concurrency is adopted!
2025-05-01 09:38:10 +00:00
Cory BenfieldandGitHub beb2637432 Clean up Task error handling. (#839)
Motivation

We have some Task error handling functions that are generic for no
apparent reason. They're also typically called from contexts where they
also report the error to the delegate, but one of the call sites doesn't
do that. So add a test for that as well.

Modifications

- Rewrite Task.fail(with:delegate:) to be non-generic.
- Add a call to the delegate error handler on the path that is missing
it.
- Add a test for that call

Results

Cleaner, easier to follow code
2025-04-30 13:57:00 +00:00
a3d00a65b9 Add "debug initializer" hook for channels (#801)
Motivation:

As requested in #596, it can be handy to have a lower-level access to
channels (HTTP/1 connection, HTTP/2 connection, or HTTP/2 stream) to
enable a more fine-grained interaction for, say, observability, testing,
etc.

Modifications:

- Add 3 new properties (`http1_1ConnectionDebugInitializer`,
`http2ConnectionDebugInitializer` and
`http2StreamChannelDebugInitializer`) to `HTTPClient.Configuration` with
access to the respective channels. These properties are of `Optional`
type `@Sendable (Channel) -> EventLoopFuture<Void>` and are called when
creating a connection/stream.

Result:

Provides APIs for a lower-level access to channels.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
Co-authored-by: David Nadoba <d_nadoba@apple.com>
Co-authored-by: George Barnett <gbarnett@apple.com>
2025-04-25 12:11:02 +00:00
Cory BenfieldandGitHub a413b779fb Work around Foundation revert even more (#822)
Since #813, Foundation have backported their revert to 6.1. Now only 6.0
is the weird one.
2025-03-11 11:51:33 +00:00
Greg CottenandGitHub 31122eaf7c Add Request/Response History to all public Response types (#817)
Work to close
https://github.com/swift-server/async-http-client/issues/790

The fact that `HTTPClient.Request` is not Sendable make me think we're
going to need to store something else, such as a `URL` and
`HTTPRequestHead`, instead?
2025-03-03 15:48:27 +00:00
Greg CottenandGitHub ad262cc3d2 Propagate HTTPClient.Task<Response> failures to subsequent redirect tasks (#814)
Discussed in
https://github.com/swift-server/async-http-client/issues/753
2025-02-20 10:22:40 +00:00
Greg CottenandGitHub d05bf23650 Add head property to FileDownloadDelegate's Progress/Response struct (#811)
I needed a way to use a `FileDownloadDelegate` task to fish out the
recommended file name.
```swift
let response = try await downloadTask.get()

// access content-disposition
response.head.headers.first(name: "Content-Disposition")
```

The `head` property is an explicitly unwrapped optional because there is
no "default value" to set it to, and it won't be accessed by the user
until it's already been set anyway. This is a little inelegant, so I
could change it to something like below where I fill in bogus init data,
but that seems worse for some reason.
```swift
public struct Progress: Sendable {
    public var totalBytes: Int?
    public var receivedBytes: Int
    public var head: HTTPResponseHead
}

private var progress = Progress(
    totalBytes: nil,
    receivedBytes: 0,
    head: .init(
        version: .init(major: 0, minor: 0),
        status: .badRequest
    )
)
```
2025-02-18 15:18:55 +00:00
Cory BenfieldandGitHub 333f51104b Work around Foundation revert (#813)
Motivation

Foundation has reverted several of the changes of behaviour in the URL
type, leaving 6.0 and 6.1 with a different behaviour on non-Apple
platforms than all other versions.

We should tolerate that.

Modifications

Update the tests to understand the difference.

Result

Tests pass
2025-02-17 17:17:16 +00:00
Cory BenfieldandGitHub 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-RogersandGitHub 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
Rick Newton-RogersandGitHub 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
Agam DuaandGitHub acaca2d50d Added: ability to set basic authentication on requests (#778)
Motivation:

As an HTTP library, async-http-client should have authentication
support.

Modifications:

This adds a `setBasicAuth()` method to both HTTPClientRequest and
`HTTPClient.Request` and their related unit tests.

Result:

Library users will be able to leverage this method to use basic
authentication on their requests without implementing this in their own
projects.

Note: I also ran the tests (`swift test`) with the
`docker.io/library/swift:6.0-focal` and
`docker.io/library/swift:5.10.1-focal` to ensure linux compatibility.

Signed-off-by: Agam Dua <agam_dua@apple.com>
2024-10-21 16:27:28 +01:00
Rick Newton-RogersandGitHub 0a9b72369b workaround Foundation.URL behavior changes (#777)
`Foundation.URL` has various behavior changes in Swift 6 to better match
RFC 3986 which impact AHC.

In particular it now no longer strips the square brackets in IPv6 hosts
which are not tolerated by `inet_pton` so these must be manually
stripped.

https://github.com/swiftlang/swift-foundation/issues/957
https://github.com/swiftlang/swift-foundation/issues/958
https://github.com/swiftlang/swift-foundation/issues/962
2024-10-03 03:02:00 -07:00
15dbe6dcee Add an option to enable Multipath TCP on clients (#766)
Multipath TCP (MPTCP) is a TCP extension allowing to enhance the
reliability of the network by using multiple interfaces. This extension
provides a seamless handover between interfaces in case of deterioration
of the connection on the original one. In the context of iOS and Mac OS
X, it could be really interesting to leverage the capabilities of MPTCP
as they could benefit from their multiple interfaces (ethernet + Wi-fi
for Mac OS X, Wi-fi + cellular for iOS).

This contribution introduces patches to HTTPClient.Configuration and
establishment of the Bootstraps. A supplementary field "enableMultipath"
was added to the configuration, allowing to request the use of MPTCP.
This flag is then used when creating the channels to configure the
client.

Note that in the future, it might also be potentially interesting to
offer more precise configuration options for MPTCP on MacOS, as the
Network framework allows also to select a type of service, instead of
just offering the option to create MPTCP connections. Currently, when
enabling MPTCP, only the Handover mode is used.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2024-09-20 12:22:17 +01:00
Cory BenfieldandGitHub 07f171bed7 Avoid using deprecated API in tests (#762)
This gets CI working again
2024-08-07 07:49:48 -07:00
aryan-25andGitHub 54d1006dc9 Add leading slash in relative URL requests if necessary (#747) 2024-07-09 12:47:07 +02:00
aryan-25andGitHub 07536f6a4e Resolve ambiguity issue for the stream function, remove @deprecated marking from the original implementation, and make argument labels consistent. (#749) 2024-07-03 16:14:47 +01:00
aryan-25andGitHub 4316ecae09 Add support for request body to be larger than 2GB on 32-bit devices (#746)
### Motivation:

- The properties that store the request body length and the cumulative number of bytes sent as part of a request are of type `Int`. 
- On 32-bit devices, when sending requests larger than `Int32.max`, these properties overflow and cause a crash.
- To solve this problem, the properties should use the explicit `Int64` type.

### Modifications:

- Changed the type of the `known` field of the `RequestBodyLength` enum to `Int64`.
- Changed the type of `expectedBodyLength` and `sentBodyBytes` in `HTTPRequestStateMachine` to `Int64?` and `Int64` respectively.
- Deprecated the `public var length: Int?` property of `HTTPClient.Body` and backed it with a new property: `contentLength: Int64?`
  - Added a new initializer and "overloaded" the `stream` function in `HTTPClient.Body` to work with the new `contentLength` property.
  - **Note:** The newly added `stream` function has different parameter names (`length` -> `contentLength` and `stream` -> `bodyStream`) to avoid ambiguity problems.
- Added a test case that streams a 3GB request -- verified this fails with the types of the properties set explicitly to `Int32`. 

### Result:

- 32-bit devices can send requests larger than 2GB without integer overflow issues.
2024-06-28 11:33:04 +02:00
hamzahrmalikandGitHub fb308ee72f Move availability guard to correct test (#734)
It was previously accidentally moved to a different test, which does not need it
Async tests need the guard for macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0
2024-04-05 11:16:39 +01:00
e0977cf290 HTTPClient.shared a globally shared singleton & .browserLike configuration (#705)
Co-authored-by: Johannes Weiss <johannes@jweiss.io>
2024-04-03 05:54:00 -07:00
Gustavo CairoandGitHub 83f015bf94 Fix write timeout not being initialised (#730) 2024-03-21 16:18:22 +00:00
Gustavo CairoandGitHub 5ccda442f1 Use the given connection pool idle timeout in the HTTPClient.Configuration inits (#723) 2023-12-21 09:51:54 -03:00
Si BeaumontandGitHub a4904fcc6b Add missing availability guards in tests (#719)
## Motivation

Some of the test code was missing availability guards for Apple platforms, resulting in build failures for these platforms, e.g.

```
error: 'AsyncSequence' is only available in iOS 13.0 or newer
```

## Modifications

Add missing availability guards. I've tried to keep them as scoped as possible.

## Result

Tests can now build for run on iOS and other Apple platforms.
2023-12-18 04:52:50 -08:00
Johannes WeissandGitHub d766674c7e HTTPClientRequest: allow custom TLS config (#709) 2023-10-16 07:00:58 -07:00
8c90405f0c use NIOSingletons EventLoops/NIOThreadPool instead of spawning new (#697)
Co-authored-by: Johannes Weiss <johannes@jweiss.io>
2023-08-14 14:59:33 +01:00
Cory BenfieldandGitHub 62c06d47c8 Remove tests relying on OS-dependent behaviour (#703)
Motivation

URL parsing has changed in macOS Sonoma and associated releases. Our
tests were reliant on the old behaviour. The behaviour is controlled
by the OS on which the program was linked, which makes it impossible
for us to programmatically work out which result we should see.

The affected tests are not actually useful, we don't really care how
the URLs parse, so we can safely just remove them.

Modifications

Remove the affected tests.

Result

Tests pass!
2023-08-10 03:33:18 -07:00
David NadobaandGitHub b9029ef67c Add support for custom cancellation error (#683) 2023-04-13 17:00:03 +01:00
George BarnettandGitHub 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
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 NadobaandGitHub 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 NadobaandGitHub 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
carolinacassandGitHub 8b84142a70 Use #fileID/#filePath instead of #file (#644) 2022-11-04 08:20:19 -07:00
David NadobaandGitHub 9195d3bcb4 Speedup tests (#639)
* Enable fast failure mode for testing

* Split-up HTTPClientTests into multiple subclasses

* Move test subclasses into separate files
2022-10-11 16:40:26 +01:00
David NadobaandGitHub 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
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 NadobaandGitHub c3c90aab58 Adopt Sendable (#621) 2022-08-25 11:45:13 +02:00
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 NadobaandGitHub 46d1c76715 Support transparent decompression with HTTP/2 (#610) 2022-08-05 17:04:57 +02:00
David NadobaandGitHub 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 NadobaandGitHub 14fa6d944d Report last connection error if request deadline is exceeded (#601) 2022-07-01 10:39:38 +02:00
David NadobaandGitHub 794dc9d427 Add testSelfSignedCertificateIsRejectedWithCorrectError (#594) 2022-06-17 20:32:33 +02:00
Cory BenfieldandGitHub 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 BenfieldandGitHub 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
David NadobaandGitHub 0f21b44d1a Use a local TCP server that doesn’t accept connections on macOS for testConnectTimeout() (#592)
* Use a local TCP server that doesn’t accept connections on macOS for `testConnectTimeout()`

* fix linting
2022-06-09 18:35:05 +01:00
Cory BenfieldandGitHub 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
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 NadobaandGitHub 3725095966 Fix flaky HTTPClientTests.testResponseDelayGet() test (#584) 2022-04-22 10:37:00 +02:00
KarlandGitHub 6474d8d2b2 Add HTTPClient.Body.bytes as an alternative to .data (#534) 2022-01-13 14:19:48 +00:00
David NadobaandGitHub c4feafd813 Refactor redirect logic to be reusable for async/await (#522)
* refactor RedirectHandler
- `redirectState` is no longer a property of `HTTPClient.Request`. RedirectHandler now stores this state directly and therefore no longer optional.
- we no longer count the number of allowed redirects down. Instead the number of redirects is dervied from `self.visited.count` and we compare it to the maxRedirect to check if we git the limit.

* `HTTPClient.Configuration.RedirectConfiguration.Configuration` is now called `HTTPClient.Configuration.RedirectConfiguration.Mode`
only two `Configuration`s left in the type name

* add redirect logger test
2021-12-08 19:16:06 +01:00