Commit Graph
224 Commits
Author SHA1 Message Date
David NadobaandGitHub 9c7ab039fe Allow HTTPClientRequest to be executed multiple times if body is an AsyncSequence (#620) 2022-08-23 13:46:17 +01:00
KarlandGitHub 18109d842d Use NIOCore.System.coreCount for the fileIO thread pool (#618) 2022-08-20 12:22:41 +01:00
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 NadobaandGitHub 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 BenfieldandGitHub 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 BenfieldandGitHub 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
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
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 NadobaandGitHub 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 BenfieldandGitHub 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 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 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 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
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
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 PriebeandGitHub 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 FettandGitHub 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 FettandGitHub 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 FettandGitHub d2da15c31c [HTTP2] Tolerate GoAway and Settings frames after connection close (#578) 2022-04-11 16:24:57 +02:00
Cory BenfieldandGitHub 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
Fabian FettandGitHub 71af9c7fb7 Crash fix: HTTPClientRequestHandler can deal with failing writes (#558) 2022-02-22 13:59:54 +01:00
Johannes WeissandGitHub 16aed40d3e SSLProtocol tls* deprecations (#561) 2022-02-16 09:24:31 +00:00
5844a6b4ee Crash fix: HTTP2 can handle requests are cancelled (#555)
Co-authored-by: George Barnett <gbarnett@apple.com>
2022-02-10 10:42:27 +01:00
David NadobaandGitHub 06b9f98989 Make async/await API public (#552) 2022-02-08 11:48:58 +01:00
David NadobaandGitHub f3830d11ec Add async shutdown method to HTTPClient (#551) 2022-02-07 11:36:53 +01:00
David NadobaandGitHub 14c95bf6c9 Disable logging by default and add timeout API (#549) 2022-02-01 17:32:33 +01:00
Fabian FettandGitHub ce3958ff92 Fix race between connection close and scheduling new request (#546) 2022-01-24 12:07:41 +00:00
Fabian FettandGitHub 2497a68427 Print invalid state, if hitting precondition (#545) 2022-01-24 12:26:08 +01:00
KarlandGitHub 609b4368b8 Used vendored base64 encoding implementation rather than Foundation.Data (#539) 2022-01-21 15:28:26 +01:00
David NadobaandGitHub c2805dfa4e Prepare async/await API for public release (#531) 2022-01-14 14:35:17 +01:00
KarlandGitHub 6474d8d2b2 Add HTTPClient.Body.bytes as an alternative to .data (#534) 2022-01-13 14:19:48 +00:00
KarlandGitHub 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
David NadobaandGitHub 19e83a35df Set host on new request correctly (#536)
### Motivation
If we follow a redirect which changes the origin e.g. from `127.0.0.1` to `localhost` we didn't change the `Host` header to the appropriate new origin and port combination.
### Changes
Use the original request which does not include the host instead of the prepared request to form a new request to the redirect URL.

### Alternatives
If the user defines a `Host` header themselves on the original `HTTPClientRequest` we currently never touch it, even in the redirect case. Maybe we should change our strategy and do one of the following:
1. We could always override the user defined `Host` header
2. We could only remove the user defined `Host` header on redirect and set it to the new origin and port combination
2021-12-24 12:31:24 +01:00
David NadobaandGitHub e531961906 remove dot from HTTP1.1 folder (#535)
Swift tools version 5.3 and higher (the version that is specified at very top of a Package.swift file) excludes folders with a dot in the name by default. It luckily produces a warning "found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target". However, this issue is buried under a lot of missing types Errors because of the 3 excluded files.
I run into this issue and it took me some time to figure out what the actual problem was. As we will eventually move from 5.2 to 5.3 we can already save the next person some time by resolving this issue now.
2021-12-23 00:09:38 +01:00
David NadobaandGitHub d372bdc213 Make async/await available on older Apple Platforms (#527)
### Motivation
With Xcode 13.2, and therefore Swift 5.5.2, Swift Concurrecy is supported on older Apple OSs. async/await suport will no longer be available on Swift before `5.5.2` but this isn't a breaking change because we have not yet made anything of it public.

### Changes
- replace all `#if compiler(>=5.5) && canImport(_Concurrency)` with `#if compiler(>=5.5.2) && canImport(_Concurrency)`
- replace all `available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)` with `available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)`
2021-12-17 16:08:24 +01:00
David NadobaandGitHub 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 NadobaandGitHub d95277640f Respect deadline on new HTTPClient.execute for async/await (#529)
* Schedule deadline timeout
* Add state machine tests and enable skipped test for http1
2021-12-17 09:36:41 +01:00
David NadobaandGitHub b1c0c3c77b replace EventLoopGroup.next() with .any() (#526) 2021-12-14 21:59:54 +01:00
David NadobaandGitHub 5db7719a27 async/await execute (#524)
* async/await execute

* remove default length for `HTTPClientRequest.Body`

* make redirect logic iterative

* move Task creation into `TransactionCancelHandler`
2021-12-14 20:24:45 +01:00
David NadobaandGitHub bf5668c37b Use the current EventLoop as the requests preferred EventLoop (#515)
* Use the current `EventLoop` as the requests prefered `EventLoop` if possible

* use released version of swift-nio
2021-12-14 20:10:31 +01:00
Fabian FettandGitHub 24b0a14e9c Add async Transaction (#518)
This introduces an async Transaction object. The object is the translation layer between the user facing async API and the NIO channel handler.
2021-12-09 18:04:01 +01: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
Fabian FettandGitHub 474b23d677 Typo: Replace HTTPExecutingRequest with HTTPExecutableRequest (#514) 2021-12-03 17:10:55 +01:00
David NadobaandGitHub 5ce7377a8a Add HTTPClientReuqest.Prepared (#511)
* add HTTPClientReuqest.Prepared

* make `prepared()` an init of `Prepared`

* make all stored properties of `Prepared` `var`s
2021-12-03 09:54:01 +01:00
David NadobaandGitHub a956e7b448 Add HTTPClientRequest (#509)
* HTTPClientRequest

* move into single file

* fix review comments

* remove overload
2021-12-02 14:25:58 +01:00