Commit Graph
219 Commits
Author SHA1 Message Date
David Nadoba 3960678bcd Don’t call didReceiveError twice if deadline is exceeded and request is canceled aftewards (#609) 2022-08-04 13:14:36 +01: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
David Nadoba 14fa6d944d Report last connection error if request deadline is exceeded (#601) 2022-07-01 10:39:38 +02:00
David Nadoba b3583ba7ff Fix flaky Network.framework testConnectionFailError test (#600)
we may recieve a posix `ECONNREFUSED` too
2022-06-24 08:38:35 +01:00
David Nadoba 794dc9d427 Add testSelfSignedCertificateIsRejectedWithCorrectError (#594) 2022-06-17 20:32:33 +02:00
Cory Benfield 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 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
David Nadoba 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 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
Cory BenfieldandDavid Nadoba 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
Franz BuschandFabian Fett 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
David Nadoba a586fba7eb Fix flaky TransactionTests.testResponseStreamFails() test (#582) 2022-04-22 10:47:30 +02:00
David Nadoba 3725095966 Fix flaky HTTPClientTests.testResponseDelayGet() test (#584) 2022-04-22 10:37:00 +02:00
Fabian Fett 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 Fett 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 Fett d2da15c31c [HTTP2] Tolerate GoAway and Settings frames after connection close (#578) 2022-04-11 16:24:57 +02:00
Cory Benfield 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 Fett 71af9c7fb7 Crash fix: HTTPClientRequestHandler can deal with failing writes (#558) 2022-02-22 13:59:54 +01:00
Fabian FettandGeorge Barnett 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 Nadoba f3830d11ec Add async shutdown method to HTTPClient (#551) 2022-02-07 11:36:53 +01:00
David Nadoba 7b3415cd2e Fix test compilation for Swift 5.5.0/5.5.1 (#550)
#if compiler and #available probably didn't get correctly updated after some merge conflict.
2022-02-03 12:42:25 +01:00
Fabian Fett ce3958ff92 Fix race between connection close and scheduling new request (#546) 2022-01-24 12:07:41 +00:00
Fabian Fett 2497a68427 Print invalid state, if hitting precondition (#545) 2022-01-24 12:26:08 +01:00
David Nadoba c2805dfa4e Prepare async/await API for public release (#531) 2022-01-14 14:35:17 +01:00
Karl 6474d8d2b2 Add HTTPClient.Body.bytes as an alternative to .data (#534) 2022-01-13 14:19:48 +00: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
David Nadoba 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 Nadoba 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 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 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 Nadoba 239d6d2ebf Add end-to-end tests for async/await (#528)
* add end to end tets

* enable testCanceling on linux

* Remove testConnectTimeout test
2021-12-16 16:44:28 +01:00
David Nadoba 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 Nadoba 18c7266fe8 add missing @available anotations (#525)
Otherwise it fails to compile with Xcode 13.1.
Xcode 13.2 seems fine without but this is probably a regression in the swift compiler because the @available anotations are actally needed.
2021-12-14 15:48:10 +01:00
Fabian Fett 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 Nadoba 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 Fett 3d7c42e6dd Cleanup MockRequestExecutor (#521)
In async tests, we need to wait for events that happen on the async executor. We can use ConditionLocks to wait for async events to happen while using a synchronous invocation model in the tests. In this pr we restructure `MockRequestExecutor` to use `ConditionLock`s where appropiate.
2021-12-07 12:07:05 +01:00
Fabian Fett 29d194f4c4 Fix flaky test: testConnectionClosesAfterTheRequestWithoutHavingSentAnCloseHeader (#520) 2021-12-06 18:31:32 +01:00
Fabian FettandGeorge Barnett a79206d477 Add an AsyncWriter (#519)
This PR adds an AsyncWriter that we can be used to test our new async upload streaming API.

Co-authored-by: George Barnett <gbarnett@apple.com>
2021-12-06 18:07:39 +01:00
David Nadoba cc17c9cd82 Test HTTPClientRequest (#513)
* test `HTTPClientRequest.Prepared` and `HTTPClientRequest.Body`

* add scheme and headers tests

* fix tests
2021-12-06 10:53:42 +01:00
Fabian Fett 93de326a89 MockRequestExecutor runRequest (#517)
### Motivation

Our actual HTTPRequestExecutors send out an HTTPRequest as soon as they see it and they call `willExecuteRequest` and `requestHeadSent` in very fast succession on the `HTTPExecutableRequest`. We should have the same behavior in tests.

### Changes

- Call `requestHeadSent` from `MockRequestExecutor.runRequest`
- Tests that use `MockRequestExecutor` call `runRequest` on it first

### Result

Cleaner, more life like tests
2021-12-06 09:17:55 +01: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
David Nadoba 99bd384b38 Refactor deconstructURL and scheme parsing (#504)
* make `Scheme` a type

* introduce new Endpoint type

* use endpoint as storage in `HTTPClient.Request`

* fix merge conflicts

* rename Endpoint to DeconstructedURL

* swift-format

* make `DeconstructedURL` properties `var`'s

* move scheme into global namespace

- rename `useTLS` to `usesTLS` where posible without breaking public API
- only import Foundation.URL

* fix review comments
2021-12-01 13:03:09 +01:00
Fabian Fett 70826d038d Add h2 stream integration tests (#502) 2021-12-01 09:27:59 +01:00
Karl f1a91872c5 Introduce a ConnectionTarget enum (#501)
* Add a ConnectionPool.Host enum

* Move Host out as a top-level ConnectionTarget type, and use it in Request.
2021-11-30 18:29:38 +01:00
Fabian Fett 83c2625612 [Tests] Remove XCTAssertNoThrow that wraps XCTAssertEqual (#500) 2021-11-26 13:16:40 +01:00
f2c2f73fb9 Refactor URL component extraction (#485)
* Refactor URL component extraction

* Remove superfluous test message

Co-authored-by: Fabian Fett <fabianfett@apple.com>
Co-authored-by: David Nadoba <d_nadoba@apple.com>
2021-11-26 12:49:43 +01:00
David Nadoba 1119893f2e Add XCTAsyncTest and XCTAssertThrowsError from gRPC Swift (#493) 2021-11-26 10:21:05 +01:00
David Nadoba f2bb28390a Fix flaky tests in HTTPClientSOCKSTests (#498)
* bind to a port defined by the operating system
2021-11-26 00:22:37 +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