Commit Graph
144 Commits
Author SHA1 Message Date
Fabian Fett a6ca288e18 [HTTPConnectionPool] StateMachine has explicit function for HTTP1 connection close (#448) 2021-10-01 12:50:13 +02:00
Fabian Fett 2bd88855b4 Remove deprecated connection pool (#443)
- Remove now unused Connection/ConnectionPool
- Removed TaskHandler
- Remove ResponseReadBuffer
- Removed further now unused code
- Remove unused imports
- Remove test util `RecordingHandler`
2021-09-29 18:42:24 +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 16ad7588b1 [HTTP1Connection] Handle 101 Switching Protocols (#442) 2021-09-28 09:52:26 +02:00
Fabian Fett 316cbf9353 [RequestBag] Fix consumption error in state machine (#441) 2021-09-27 15:33:45 +02:00
Fabian Fett 2a47a1da75 [HTTPClient.Configuration] Make connection pool size configurable (#437) 2021-09-27 09:35:40 +02:00
Fabian Fett dca46a92f0 [HTTPConnectionPool] Fix request timer scheduling (#438) 2021-09-24 15:38:19 +02:00
Fabian Fett 2565dfe0dc [HTTPConnectionPool] Implementation switch (#427) 2021-09-24 09:28:09 +02:00
Fabian Fett 0bce647a2f [HTTPConnectionPool] Fix timer action races (#434)
- `_idleTimer` and `_backoffTimer` are protected by `stateLock`
- Added a new `struct Actions` that splits up actions from the state machine into actions that need to be executed inside the `stateLock` and outside in `stateLock`
- Add HTTP/1.1 connection pool stress test
2021-09-22 16:47:26 +02:00
Fabian Fett d45fa9a0bd [HTTPConnectionPool] Move Connections down in the file (#433) 2021-09-22 15:35:41 +01:00
Fabian Fett 64fbfdaeda [HTTP1Connection] Option to ignore unclean ssl shutdown errors (#432)
- a new `RequestOptions` struct was created, that can be used to set request specific options. It is required by the `HTTPExecutableRequest`
- Added support for `ignoreUncleanSSLShutdown` in the `HTTPRequestStateMachine` and the `HTTP1ConnectionStateMachine`. In http/2 `ignoreUncleanSSLShutdown` is always off.
2021-09-21 10:04:17 +02:00
Fabian Fett b25943adad Fix HTTP/1.0 support (#431)
Use `HTTPResponseHead.isKeepAlive` instead of relying on our own keep-alive test.
2021-09-20 18:16:13 +02:00
Fabian Fett bef8878ede ChannelRead because of closing connection: Remove preconditions (#430)
### Motivation

NIO may send `channelRead` events without a handlers requesting more data with a `context.read()` invocation. This happens if the remote has closed the connection and NIO wants to inform the handlers as soon as possible.

### Changes

- Don't `precondition` on `channelRead` events anymore.
- Close channel if we received an http end without a `context.read()` invocation
2021-09-20 18:11:04 +02:00
Fabian Fett 7c9662d31c Add logging to the new ConnectionPool (#428) 2021-09-20 16:23:09 +02:00
Fabian Fett 324adb73ae HTTP1Connection: Close on error while in request (#425)
### Motivation

In the `HTTP1ConnectionStateMachine` we set the connection state to `.closed` after having forwarded an error to the inner RequestStateMachine. Since we set the state to close, the `state.modify` function did not create an action that would close the connection.

### Changes

- Modify the ConnectionState based on the RequestStateMachine's action only in the `state.modify` function.
- Add a test to verify the fixed behavior.
- Use ExpressibleByDictionaryLiteral syntax for some HTTPHeaders to increase readability.

### Result

Connections are closed, if an error happens, while we are in a request.
2021-09-14 10:27:32 +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 5d2bf9250d Ensure HTTPConnectionPool calls shutdown on active connections. (#422)
Trigger the correct method on HTTPConnectionPool.Connection to cancel the request and close the connection.
2021-09-13 14:57:18 +02:00
Fabian FettandGeorge Barnett fb49c1be5f Add new HTTPConnectionPool Manager (#420)
Co-authored-by: George Barnett <gbarnett@apple.com>
2021-09-10 17:25:41 +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 FettandCory Benfield 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 4068ee50d0 EventLoop preferences (#415) 2021-09-07 10:47:09 +01:00
Fabian FettandGeorge Barnett 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
Jake Petroules 6af7c8c2b2 Add missing availability to APIs requiring macOS 10.15 / iOS 13.0 (#411) 2021-08-31 14:02:11 -07:00
Fabian Fett eab2a84b1c Use explicit NIO imports (#407)
* Use explicit NIO imports for `NIOCore`, `NIOPosix` and `NIOEmbedded`
* Updated dependencies
2021-08-19 21:11:49 +02:00
Fabian Fett 44efb9481b Cleanup: Connection cancel -> shutdown (#404)
* Cleanup

* Code review
2021-07-23 11:52:46 +01:00
Fabian FettandGeorge Barnett 388b8dc14a Add HTTP2Connection (#401)
Co-authored-by: George Barnett <gbarnett@apple.com>
2021-07-22 18:30:37 +02:00
Fabian Fett e967f9a099 Add HTTP1Connection (#400) 2021-07-13 13:32:18 +02:00
Fabian Fett 79db46a757 HTTPSchedulableRequest extends HTTPExecutableRequest (#402) 2021-07-09 11:12:14 +01:00
Fabian Fett 152c21e45a Add HTTPConnectionPool Connection as a box type (#398)
Add a `HTTPConnectionPool.Connection` type that is a box around an actual connection. The purpose of the box is to ensure no actions are invoked on the connection within the state machine. Further the box can be used for testing the state machine without creating actual connections.
2021-07-09 10:13:35 +02:00
Fabian Fett 7311c0ecfe Add a request waiter box for the connection pool (#397) 2021-07-08 18:57:00 +02:00
Fabian Fett ed442836ac Add HTTP1ConnectionStateMachine (#396) 2021-07-08 15:59:20 +02:00
Fabian Fett 8d4e2b1d24 ConnectionFactory: Replace (Channel, HTTPVersion) with NegotiatedProtocol (#399) 2021-07-08 11:31:15 +01:00
Fabian FettandCory Benfield bccb075309 Refactor Request Validation (#391)
- Refactored code from `TaskHandler` into new method `HTTPClient.Request.createRequestHead` that creates an `HTTPRequestHead` and matching `RequestFramingMetadata`
- Added required property `requestFramingMetadata` to `HTTPExecutingRequest`
- Added property `requestFramingMetadata` to `RequestBag`

Co-authored-by: Cory Benfield <lukasa@apple.com>
2021-07-07 19:50:00 +02:00
a9aee2675f Add HTTPScheduledRequest and HTTPExecutingRequest (#384)
- Adding four new protocols:
  - `HTTPExecutingRequest` a protocol representing an HTTP task that is executed on a ChannelHandler.
  - `HTTPScheduledRequest` a protocol representing an HTTP task that is scheduled for execution, but in a waiting state (example: Waiting for an idle connection in the connection pool).
  - `HTTPRequestExecutor` a protocol that can be used from the `HTTPExecutingRequest` abstracting away functionality that will normally be implemented by a `ChannelHandler`
  - `HTTPRequestScheduler` a protocol that can be used from the `HTTPScheduledRequest` abstracting away functionality that will normally be implemented by a `ConnectionPool`
- An implementation of the `HTTPExecutingTask` and `HTTPScheduledRequest` called `RequestBag`. It implements  our current API using the new protocols

Co-authored-by: George Barnett <gbarnett@apple.com>
Co-authored-by: Cory Benfield <lukasa@apple.com>
2021-07-07 13:44:48 +02:00
Fabian Fett fcb0f21bfd Buffer channelReads in ResponseStreamState until the next channelReadComplete (#388)
- `ConsumerControlState` was replaced with `ResponseStreamState` in `HTTPRequestStateMachine`
- `channelRead`s are buffered up to a `channelReadComplete`.
- on `channelReadComplete` all buffered body parts are forwarded to the consumer
2021-07-07 13:30:22 +02:00
Fabian Fett cd7c8048a8 Add HTTPRequestStateMachine (#386)
This commit adds an explicit `HTTPRequestStateMachine`. It is intended to be used in two instances in the future:

1. As a substate machine for a `HTTP1ConnectionStateMachine`, when the connection is in a request.
2. As a state machine for a `HTTP2RequestHandler` that operates on a single http2 stream created by the multiplexer.

The new code paths are not triggered today, but will be enabled in the future.
2021-07-05 15:25:09 +02:00
Fabian Fett 8e4d51908d Refactor Channel creation (#377)
- The connection creation logic has been refactored into a number of smaller methods that can be combined
- Connection creation now has a logical home. It is moved from `Utils.swift` into a `ConnectionFactory`
- There are explicit `ChannelHandlers` that are used for connection creation:
  - `TLSEventsHandler` got its own file and unit tests
  - `HTTP1ProxyConnectHandler` got its own file and unit tests
  - `SOCKSEventsHandler` got its own file and unit tests
- Some small things are already part of this pr that will get their context later. For example: 
  - `HTTPConnectionPool` is added as a namespace to not cause major renames in follow up PRs
  - `HTTPConnectionPool.Connection.ID` and its generator were added now. (This will be used later to identify a connection during its lifetime)
  - the file `HTTPConnectionPool+Manager` was added to give `HTTPConnectionPool.Connection.ID.Generator` already its final destination.
2021-06-28 13:17:33 +02:00
David Evans 102b7e4bce Update NIO family dependencies to 5.2+ versions and fix deprecations (#381)
Updated:

NIO
NIOSSL
NIO Extras
NIOTS
Also fix TLSConfiguration.forClient() warnings by converting to TLSConfiguration.makeClientConfiguration(). Also the same for forServer().
2021-06-23 14:58:08 +01:00
David Evans 3fd0658dd9 Implement SOCKS proxy functionality (#375)
Add a new Proxy type to enable a HTTPClient to send requests via a SOCKSv5 Proxy server.
2021-06-18 13:02:58 +01:00
Johannes Weiss 8ccba7328d SSLContextCache: use DispatchQueue instead of NIOThreadPool (#368)
Motivation:

In the vast majority of cases, we'll only ever create one and only one
`NIOSSLContext`. It's therefore wasteful to keep around a whole thread
doing nothing just for that. A `DispatchQueue` is absolutely fine here.

Modification:

Run the `NIOSSLContext` creation on a `DispatchQueue` instead.

Result:

Fewer threads hanging around.
2021-05-13 15:11:49 +01:00
Adam Fowler 9cdf8a01e5 Generate trust roots SecCertificate for Transport Services (#350)
This PR is a result of another #321.

In that PR I provided an alternative structure to TLSConfiguration for when connecting with Transport Services.

In this one I construct the NWProtocolTLS.Options from TLSConfiguration. It does mean a little more work for whenever we make a connection, but having spoken to @weissi he doesn't seem to think that is an issue.

Also there is no method to create a SecIdentity at the moment. We need to generate a pkcs#12 from the certificate chain and private key, which can then be used to create the SecIdentity.

This should resolve #292
2021-05-13 13:59:18 +01:00
Johannes Weiss 06daedfbbd TLS on Darwin: Add explainer that MTELG supports all options 2021-05-13 12:17:38 +01:00
Johannes Weiss e2d03ffb32 cache NIOSSLContext (saves 27k allocs per conn) (#362)
Motivation:

At the moment, AHC assumes that creating a `NIOSSLContext` is both cheap
and doesn't block.

Neither of these two assumptions are true.

To create a `NIOSSLContext`, BoringSSL will have to read a lot of
certificates in the trust store (on disk) which require a lot of ASN1
parsing and much much more.

On my Ubuntu test machine, creating one `NIOSSLContext` is about 27,000
allocations!!! To make it worse, AHC allocates a fresh `NIOSSLContext`
for _every single connection_, whether HTTP or HTTPS. Yes, correct.

Modification:

- Cache NIOSSLContexts per TLSConfiguration in a LRU cache
- Don't get an NIOSSLContext for HTTP (plain text) connections

Result:

New connections should be _much_ faster in general assuming that you're
not using a different TLSConfiguration for every connection.
2021-05-13 12:16:52 +01:00
Mads Odgaard ca722d8337 Support request specific TLS configuration (#358)
Adds support for request-specific TLS configuration:
Request(url: "https://webserver.com", tlsConfiguration: .forClient())
2021-05-07 13:47:02 +01:00
Cory Benfield e4fded76ac Better backpressure management. (#352)
Motivation:

Users of the HTTPClientResponseDelegate expect that the event loop
futures returned from didReceiveHead and didReceiveBodyPart can be used
to exert backpressure. To be fair to them, they somewhat can. However,
the TaskHandler has a bit of a misunderstanding about how NIO
backpressure works, and does not correctly manage the buffer of inbound
data.

The result of this misunderstanding is that multiple calls to
didReceiveBodyPart and didReceiveHead can be outstanding at once. This
would likely lead to severe bugs in most delegates, as they do not
expect it.

We should make things work the way delegate implementers believe it
works.

Modifications:

- Added a buffer to the TaskHandler to avoid delivering data that the
   delegate is not ready for.
- Added a new "pending close" state that keeps track of a state where
   the TaskHandler has received .end but not yet delivered it to the
   delegate. This allows better error management.
- Added some more tests.
- Documented our backpressure commitments.

Result:

Better respect for backpressure.

Resolves #348
2021-03-30 11:39:35 +01:00
Cory Benfield b075d19007 Unconditionally insert TLSEventsHandler (#349)
Motivation:

AsyncHTTPClient attempts to avoid the problem of Happy Eyeballs making
it hard to know which Channel will be returned by only inserting the
TLSEventsHandler upon completion of the connect promise. Unfortunately,
as this may involve event loop hops, there are some awkward timing
windows in play where the connect may complete before this handler gets
added.

We should remove that timing window by ensuring that all channels always
have this handler in place, and instead of trying to wait until we know
which Channel will win, we can find the TLSEventsHandler that belongs to
the winning channel after the fact.

Modifications:

- TLSEventsHandler no longer removes itself from the pipeline or throws
  away its promise.
- makeHTTP1Channel now searches for the TLSEventsHandler from the
  pipeline that was created and is also responsible for removing it.
- Better sanity checking that the proxy TLS case does not overlap with
  the connection-level TLS case.

Results:

Further shrinking windows for pipeline management issues.
2021-03-18 12:21:23 +00:00