Skip to content

Commit 3872998

Browse files
committed
Add HTTPClientTask
1 parent af837ed commit 3872998

File tree

8 files changed

+1373
-1
lines changed

8 files changed

+1373
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Logging
16+
import NIO
17+
import NIOConcurrencyHelpers
18+
import NIOHTTP1
19+
20+
/// A handle to the request queuer.
21+
///
22+
/// Use this handle to cancel the request, while it is waiting for a free connection, to execute the request.
23+
/// This protocol is implemented by the `HTTPConnectionPool`.
24+
protocol HTTPTaskQueuer {
25+
/// Informs the task queuer that a request has been cancelled.
26+
func cancelRequest(task: HTTPClientTask)
27+
}
28+
29+
/// A handle to the request executor.
30+
///
31+
/// This protocol is implemented by the `HTTP1ClientChannelHandler`.
32+
protocol HTTPTaskExecutor {
33+
/// Writes a body part into the channel pipeline
34+
///
35+
/// This method may be **called on any thread**. The executor needs to ensure thread safety.
36+
func writeRequestBodyPart(_: IOData, task: HTTPClientTask)
37+
38+
/// Signals that the request body stream has finished
39+
///
40+
/// This method may be **called on any thread**. The executor needs to ensure thread safety.
41+
func finishRequestBodyStream(task: HTTPClientTask)
42+
43+
/// Signals that more bytes from response body stream can be consumed.
44+
///
45+
/// The request executor will call `receiveResponseBodyPart(_ buffer: ByteBuffer)` with more data after
46+
/// this call.
47+
///
48+
/// This method may be **called on any thread**. The executor needs to ensure thread safety.
49+
func demandResponseBodyStream(task: HTTPClientTask)
50+
51+
/// Signals that the request has been cancelled.
52+
///
53+
/// This method may be **called on any thread**. The executor needs to ensure thread safety.
54+
func cancelRequest(task: HTTPClientTask)
55+
}
56+
57+
/// An abstraction over a request that we want to send. A request may need to comunicate with its request
58+
/// queuer and executor. The client's methods will be called synchronously on an `EventLoop` by the
59+
/// executor. For this reason it is very important that the implementation of these functions never blocks.
60+
protocol HTTPClientTask: AnyObject {
61+
/// The task's logger
62+
var logger: Logger { get }
63+
64+
/// A connection to run this task on needs to be found before this deadline!
65+
var connectionDeadline: NIODeadline? { get }
66+
67+
/// The request's head.
68+
///
69+
/// Based on the content of the request head the task executor will call `startRequestBodyStream`
70+
/// after `requestHeadSent` was called.
71+
var requestHead: HTTPRequestHead { get }
72+
73+
/// The maximal `TimeAmount` that is allowed to pass between reads from the Channel.
74+
var idleReadTimeout: TimeAmount? { get }
75+
76+
/// The task's eventLoopPreference
77+
var eventLoopPreference: HTTPClient.EventLoopPreference { get }
78+
79+
/// Informs the task, that it was queued for execution
80+
///
81+
/// This happens if all available connections are currently in use
82+
func requestWasQueued(_: HTTPTaskQueuer)
83+
84+
/// Informs the task about the connection it will be executed on
85+
///
86+
/// This is only here to allow existing tests to pass. We should rework this ASAP to get rid of this functionality
87+
func willBeExecutedOnConnection(_: HTTPConnectionPool.Connection)
88+
89+
/// Will be called by the ChannelHandler to indicate that the request is going to be send.
90+
///
91+
/// This will be called on the Channel's EventLoop. Do **not block** during your execution!
92+
///
93+
/// - Returns: A bool indicating if the request should really be started. Return false if the request has already been cancelled.
94+
/// If the request is cancelled after this method call `executor.cancel()` to stop request execution.
95+
func willExecuteRequest(_: HTTPTaskExecutor) -> Bool
96+
97+
/// Will be called by the ChannelHandler to indicate that the request head has been sent.
98+
///
99+
/// This will be called on the Channel's EventLoop. Do **not block** during your execution!
100+
func requestHeadSent(_: HTTPRequestHead)
101+
102+
/// Start request streaming
103+
///
104+
/// This will be called on the Channel's EventLoop. Do **not block** during your execution!
105+
func startRequestBodyStream()
106+
107+
/// Pause request streaming
108+
///
109+
/// This will be called on the Channel's EventLoop. Do **not block** during your execution!
110+
func pauseRequestBodyStream()
111+
112+
/// Resume request streaming
113+
///
114+
/// This will be called on the Channel's EventLoop. Do **not block** during your execution!
115+
func resumeRequestBodyStream()
116+
117+
/// Receive a response head.
118+
///
119+
/// Please note that `receiveResponseHead` and `receiveResponseBodyPart` may
120+
/// be called in quick succession. It is the task's job to buffer those events for the user. Once all
121+
/// buffered data has been consumed the task must call `executor.demandResponseBodyStream`
122+
/// to ask for more data.
123+
func receiveResponseHead(_ head: HTTPResponseHead)
124+
125+
/// Receive a response body stream part.
126+
///
127+
/// Please note that `receiveResponseHead` and `receiveResponseBodyPart` may
128+
/// be called in quick succession. It is the task's job to buffer those events for the user. Once all
129+
/// buffered data has been consumed the task must call `executor.demandResponseBodyStream`
130+
/// to ask for more data.
131+
func receiveResponseBodyPart(_ buffer: ByteBuffer)
132+
133+
func receiveResponseEnd()
134+
135+
func fail(_ error: Error)
136+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
enum HTTPConnectionPool {
16+
struct Connection {
17+
typealias ID = Int
18+
}
19+
}

Diff for: Sources/AsyncHTTPClient/HTTPHandler.swift

+4
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,10 @@ extension URL {
624624
}
625625
}
626626

627+
protocol HTTPClientTaskDelegate {
628+
func cancel()
629+
}
630+
627631
extension HTTPClient {
628632
/// Response execution context. Will be created by the library and could be used for obtaining
629633
/// `EventLoopFuture<Response>` of the execution or cancellation of the execution.

0 commit comments

Comments
 (0)