@@ -18,25 +18,48 @@ import NIOConcurrencyHelpers
18
18
import NIOHTTP1
19
19
import NIOSSL
20
20
21
- public extension HTTPClient {
22
- enum Body : Equatable {
23
- case byteBuffer( ByteBuffer )
24
- case data( Data )
25
- case string( String )
26
-
27
- var length : Int {
28
- switch self {
29
- case . byteBuffer( let buffer) :
30
- return buffer. readableBytes
31
- case . data( let data) :
32
- return data. count
33
- case . string( let string) :
34
- return string. utf8. count
21
+ extension HTTPClient {
22
+
23
+ public struct Body {
24
+ public struct StreamWriter {
25
+ let closure : ( IOData ) -> EventLoopFuture < Void >
26
+
27
+ public func write( _ data: IOData ) -> EventLoopFuture < Void > {
28
+ return self . closure ( data)
29
+ }
30
+ }
31
+
32
+ public var length : Int ?
33
+ public var stream : ( StreamWriter ) -> EventLoopFuture < Void >
34
+
35
+ public static func byteBuffer( _ buffer: ByteBuffer ) -> Body {
36
+ return Body ( length: buffer. readableBytes) { writer in
37
+ writer. write ( . byteBuffer( buffer) )
38
+ }
39
+ }
40
+
41
+ public static func stream( length: Int ? = nil , _ stream: @escaping ( StreamWriter ) -> EventLoopFuture < Void > ) -> Body {
42
+ return Body ( length: length, stream: stream)
43
+ }
44
+
45
+ public static func data( _ data: Data ) -> Body {
46
+ return Body ( length: data. count) { writer in
47
+ var buffer = ByteBufferAllocator ( ) . buffer ( capacity: data. count)
48
+ buffer. writeBytes ( data)
49
+ return writer. write ( . byteBuffer( buffer) )
50
+ }
51
+ }
52
+
53
+ public static func string( _ string: String ) -> Body {
54
+ return Body ( length: string. utf8. count) { writer in
55
+ var buffer = ByteBufferAllocator ( ) . buffer ( capacity: string. utf8. count)
56
+ buffer. writeString ( string)
57
+ return writer. write ( . byteBuffer( buffer) )
35
58
}
36
59
}
37
60
}
38
61
39
- struct Request : Equatable {
62
+ public struct Request {
40
63
public var version : HTTPVersion
41
64
public var method : HTTPMethod
42
65
public var url : URL
@@ -53,7 +76,7 @@ public extension HTTPClient {
53
76
try self . init ( url: url, version: version, method: method, headers: headers, body: body)
54
77
}
55
78
56
- public init ( url: URL , version: HTTPVersion , method: HTTPMethod = . GET, headers: HTTPHeaders = HTTPHeaders ( ) , body: Body ? = nil ) throws {
79
+ public init ( url: URL , version: HTTPVersion = HTTPVersion ( major : 1 , minor : 1 ) , method: HTTPMethod = . GET, headers: HTTPHeaders = HTTPHeaders ( ) , body: Body ? = nil ) throws {
57
80
guard let scheme = url. scheme else {
58
81
throw HTTPClientError . emptyScheme
59
82
}
@@ -88,7 +111,7 @@ public extension HTTPClient {
88
111
}
89
112
}
90
113
91
- struct Response : Equatable {
114
+ public struct Response {
92
115
public var host : String
93
116
public var status : HTTPResponseStatus
94
117
public var headers : HTTPHeaders
@@ -114,9 +137,7 @@ internal class ResponseAccumulator: HTTPClientResponseDelegate {
114
137
self . request = request
115
138
}
116
139
117
- func didTransmitRequestBody( task: HTTPClient . Task < Response > ) { }
118
-
119
- func didReceiveHead( task: HTTPClient . Task < Response > , _ head: HTTPResponseHead ) {
140
+ func didReceiveHead( task: HTTPClient . Task < Response > , _ head: HTTPResponseHead ) -> EventLoopFuture < Void > {
120
141
switch self . state {
121
142
case . idle:
122
143
self . state = . head( head)
@@ -129,9 +150,10 @@ internal class ResponseAccumulator: HTTPClientResponseDelegate {
129
150
case . error:
130
151
break
131
152
}
153
+ return task. eventLoop. makeSucceededFuture ( ( ) )
132
154
}
133
155
134
- func didReceivePart( task: HTTPClient . Task < Response > , _ part: ByteBuffer ) {
156
+ func didReceivePart( task: HTTPClient . Task < Response > , _ part: ByteBuffer ) -> EventLoopFuture < Void > {
135
157
switch self . state {
136
158
case . idle:
137
159
preconditionFailure ( " no head received before body " )
@@ -146,6 +168,7 @@ internal class ResponseAccumulator: HTTPClientResponseDelegate {
146
168
case . error:
147
169
break
148
170
}
171
+ return task. eventLoop. makeSucceededFuture ( ( ) )
149
172
}
150
173
151
174
func didReceiveError( task: HTTPClient . Task < Response > , _ error: Error ) {
@@ -174,25 +197,33 @@ internal class ResponseAccumulator: HTTPClientResponseDelegate {
174
197
public protocol HTTPClientResponseDelegate : AnyObject {
175
198
associatedtype Response
176
199
177
- func didTransmitRequestBody( task: HTTPClient . Task < Response > )
200
+ func didSendRequestHead( task: HTTPClient . Task < Response > , _ head: HTTPRequestHead )
201
+
202
+ func didSendRequestPart( task: HTTPClient . Task < Response > , _ part: IOData )
203
+
204
+ func didSendRequest( task: HTTPClient . Task < Response > )
178
205
179
- func didReceiveHead( task: HTTPClient . Task < Response > , _ head: HTTPResponseHead )
206
+ func didReceiveHead( task: HTTPClient . Task < Response > , _ head: HTTPResponseHead ) -> EventLoopFuture < Void >
180
207
181
- func didReceivePart( task: HTTPClient . Task < Response > , _ buffer: ByteBuffer )
208
+ func didReceivePart( task: HTTPClient . Task < Response > , _ buffer: ByteBuffer ) -> EventLoopFuture < Void >
182
209
183
210
func didReceiveError( task: HTTPClient . Task < Response > , _ error: Error )
184
211
185
212
func didFinishRequest( task: HTTPClient . Task < Response > ) throws -> Response
186
213
}
187
214
188
215
extension HTTPClientResponseDelegate {
189
- func didTransmitRequestBody ( task: HTTPClient . Task < Response > ) { }
216
+ public func didSendRequestHead ( task: HTTPClient . Task < Response > , _ head : HTTPRequestHead ) { }
190
217
191
- func didReceiveHead ( task: HTTPClient . Task < Response > , _: HTTPResponseHead ) { }
218
+ public func didSendRequestPart ( task: HTTPClient . Task < Response > , _ part : IOData ) { }
192
219
193
- func didReceivePart ( task: HTTPClient . Task < Response > , _ : ByteBuffer ) { }
220
+ public func didSendRequest ( task: HTTPClient . Task < Response > ) { }
194
221
195
- func didReceiveError( task: HTTPClient . Task < Response > , _: Error ) { }
222
+ public func didReceiveHead( task: HTTPClient . Task < Response > , _: HTTPResponseHead ) -> EventLoopFuture < Void > { return task. eventLoop. makeSucceededFuture ( ( ) ) }
223
+
224
+ public func didReceivePart( task: HTTPClient . Task < Response > , _: ByteBuffer ) -> EventLoopFuture < Void > { return task. eventLoop. makeSucceededFuture ( ( ) ) }
225
+
226
+ public func didReceiveError( task: HTTPClient . Task < Response > , _: Error ) { }
196
227
}
197
228
198
229
internal extension URL {
@@ -207,13 +238,15 @@ internal extension URL {
207
238
208
239
public extension HTTPClient {
209
240
final class Task < Response> {
241
+ public let eventLoop : EventLoop
210
242
let future : EventLoopFuture < Response >
211
243
212
244
private var channel : Channel ?
213
245
private var cancelled : Bool
214
246
private let lock : Lock
215
247
216
- init ( future: EventLoopFuture < Response > ) {
248
+ init ( eventLoop: EventLoop , future: EventLoopFuture < Response > ) {
249
+ self . eventLoop = eventLoop
217
250
self . future = future
218
251
self . cancelled = false
219
252
self . lock = Lock ( )
@@ -267,6 +300,8 @@ internal class TaskHandler<T: HTTPClientResponseDelegate>: ChannelInboundHandler
267
300
let redirectHandler : RedirectHandler < T . Response > ?
268
301
269
302
var state : State = . idle
303
+ var pendingRead = false
304
+ var mayRead = true
270
305
271
306
init ( task: HTTPClient . Task < T . Response > , delegate: T , promise: EventLoopPromise < T . Response > , redirectHandler: RedirectHandler < T . Response > ? ) {
272
307
self . task = task
@@ -298,35 +333,52 @@ internal class TaskHandler<T: HTTPClientResponseDelegate>: ChannelInboundHandler
298
333
299
334
head. headers = headers
300
335
301
- context. write ( wrapOutboundOut ( . head( head) ) , promise: nil )
336
+ context. write ( wrapOutboundOut ( . head( head) ) ) . whenSuccess {
337
+ self . delegate. didSendRequestHead ( task: self . task, head)
338
+ }
302
339
303
- if let body = request. body {
304
- let part : HTTPClientRequestPart
305
- switch body {
306
- case . byteBuffer( let buffer) :
307
- part = HTTPClientRequestPart . body ( . byteBuffer( buffer) )
308
- case . data( let data) :
309
- var buffer = context. channel. allocator. buffer ( capacity: data. count)
310
- buffer. writeBytes ( data)
311
- part = HTTPClientRequestPart . body ( . byteBuffer( buffer) )
312
- case . string( let string) :
313
- var buffer = context. channel. allocator. buffer ( capacity: string. utf8. count)
314
- buffer. writeString ( string)
315
- part = HTTPClientRequestPart . body ( . byteBuffer( buffer) )
316
- }
340
+ self . writeBody ( request: request, context: context) . whenComplete { result in
341
+ switch result {
342
+ case . success:
343
+ context. write ( self . wrapOutboundOut ( . end( nil ) ) , promise: promise)
344
+ context. flush ( )
317
345
318
- context . write ( wrapOutboundOut ( part ) , promise : nil )
319
- }
346
+ self . state = . sent
347
+ self . delegate . didSendRequest ( task : self . task )
320
348
321
- context. write ( wrapOutboundOut ( . end( nil ) ) , promise: promise)
322
- context. flush ( )
349
+ let channel = context. channel
350
+ self . promise. futureResult. whenComplete { _ in
351
+ channel. close ( promise: nil )
352
+ }
353
+ case . failure( let error) :
354
+ self . state = . end
355
+ self . delegate. didReceiveError ( task: self . task, error)
356
+ self . promise. fail ( error)
357
+ context. close ( promise: nil )
358
+ }
359
+ }
360
+ }
323
361
324
- self . state = . sent
325
- self . delegate. didTransmitRequestBody ( task: self . task)
362
+ private func writeBody( request: HTTPClient . Request , context: ChannelHandlerContext ) -> EventLoopFuture < Void > {
363
+ if let body = request. body {
364
+ return body. stream ( HTTPClient . Body. StreamWriter { part in
365
+ let future = context. writeAndFlush ( self . wrapOutboundOut ( . body( part) ) )
366
+ future. whenSuccess { _ in
367
+ self . delegate. didSendRequestPart ( task: self . task, part)
368
+ }
369
+ return future
370
+ } )
371
+ } else {
372
+ return context. eventLoop. makeSucceededFuture ( ( ) )
373
+ }
374
+ }
326
375
327
- let channel = context. channel
328
- self . promise. futureResult. whenComplete { _ in
329
- channel. close ( promise: nil )
376
+ public func read( context: ChannelHandlerContext ) {
377
+ if self . mayRead {
378
+ self . pendingRead = false
379
+ context. read ( )
380
+ } else {
381
+ self . pendingRead = true
330
382
}
331
383
}
332
384
@@ -338,15 +390,21 @@ internal class TaskHandler<T: HTTPClientResponseDelegate>: ChannelInboundHandler
338
390
self . state = . redirected( head, redirectURL)
339
391
} else {
340
392
self . state = . head
341
- self . delegate. didReceiveHead ( task: self . task, head)
393
+ self . mayRead = false
394
+ self . delegate. didReceiveHead ( task: self . task, head) . whenComplete { result in
395
+ self . handleBackpressureResult ( context: context, result: result)
396
+ }
342
397
}
343
398
case . body( let body) :
344
399
switch self . state {
345
400
case . redirected:
346
401
break
347
402
default :
348
403
self . state = . body
349
- self . delegate. didReceivePart ( task: self . task, body)
404
+ self . mayRead = false
405
+ self . delegate. didReceivePart ( task: self . task, body) . whenComplete { result in
406
+ self . handleBackpressureResult ( context: context, result: result)
407
+ }
350
408
}
351
409
case . end:
352
410
switch self . state {
@@ -365,6 +423,20 @@ internal class TaskHandler<T: HTTPClientResponseDelegate>: ChannelInboundHandler
365
423
}
366
424
}
367
425
426
+ private func handleBackpressureResult( context: ChannelHandlerContext , result: Result < Void , Error > ) {
427
+ switch result {
428
+ case . success:
429
+ self . mayRead = true
430
+ if self . pendingRead {
431
+ context. read ( )
432
+ }
433
+ case . failure( let error) :
434
+ self . state = . end
435
+ self . delegate. didReceiveError ( task: self . task, error)
436
+ self . promise. fail ( error)
437
+ }
438
+ }
439
+
368
440
func userInboundEventTriggered( context: ChannelHandlerContext , event: Any ) {
369
441
if ( event as? IdleStateHandler . IdleStateEvent) == . read {
370
442
self . state = . end
0 commit comments