Skip to content

Commit 8fbeb16

Browse files
committed
Add h2 support to HTTPBin
1 parent 102b7e4 commit 8fbeb16

6 files changed

+348
-142
lines changed

Package.swift

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ let package = Package(
2323
dependencies: [
2424
.package(url: "https://github.com/apple/swift-nio.git", from: "2.30.0"),
2525
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.14.0"),
26+
.package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.18.0"),
2627
.package(url: "https://github.com/apple/swift-nio-extras.git", from: "1.10.0"),
2728
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.11.0"),
2829
.package(url: "https://github.com/apple/swift-log.git", from: "1.4.0"),
@@ -48,6 +49,7 @@ let package = Package(
4849
.product(name: "NIO", package: "swift-nio"),
4950
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
5051
.product(name: "NIOSSL", package: "swift-nio-ssl"),
52+
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
5153
"AsyncHTTPClient",
5254
.product(name: "NIOFoundationCompat", package: "swift-nio"),
5355
.product(name: "NIOTestUtils", package: "swift-nio"),

Tests/AsyncHTTPClientTests/HTTPClient+SOCKSTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class HTTPClientSOCKSTests: XCTestCase {
2323

2424
var clientGroup: EventLoopGroup!
2525
var serverGroup: EventLoopGroup!
26-
var defaultHTTPBin: HTTPBin!
26+
var defaultHTTPBin: HTTPBin<HTTPBinHandler>!
2727
var defaultClient: HTTPClient!
2828
var backgroundLogStore: CollectEverythingLogHandler.LogStore!
2929

Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift

+48-15
Original file line numberDiff line numberDiff line change
@@ -368,11 +368,49 @@ class HTTPClientInternalTests: XCTestCase {
368368
func didFinishRequest(task: HTTPClient.Task<Response>) throws {}
369369
}
370370

371+
final class WriteAfterFutureSucceedsHandler: ChannelInboundHandler {
372+
typealias InboundIn = HTTPServerRequestPart
373+
typealias OutboundOut = HTTPServerResponsePart
374+
375+
let bodyFuture: EventLoopFuture<Void>
376+
let endFuture: EventLoopFuture<Void>
377+
378+
init(bodyFuture: EventLoopFuture<Void>, endFuture: EventLoopFuture<Void>) {
379+
self.bodyFuture = bodyFuture
380+
self.endFuture = endFuture
381+
}
382+
383+
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
384+
switch self.unwrapInboundIn(data) {
385+
case .head:
386+
let head = HTTPResponseHead(version: HTTPVersion(major: 1, minor: 1), status: .ok)
387+
context.writeAndFlush(wrapOutboundOut(.head(head)), promise: nil)
388+
case .body:
389+
// ignore
390+
break
391+
case .end:
392+
self.bodyFuture.hop(to: context.eventLoop).whenSuccess {
393+
let buffer = context.channel.allocator.buffer(string: "1234")
394+
context.writeAndFlush(self.wrapOutboundOut(.body(.byteBuffer(buffer))), promise: nil)
395+
}
396+
397+
self.endFuture.hop(to: context.eventLoop).whenSuccess {
398+
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
399+
}
400+
}
401+
}
402+
}
403+
371404
// cannot test with NIOTS as `maxMessagesPerRead` is not supported
372405
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
373406
let httpClient = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup))
374-
let promise = httpClient.eventLoopGroup.next().makePromise(of: Channel.self)
375-
let httpBin = HTTPBin(channelPromise: promise)
407+
let delegate = BackpressureTestDelegate(eventLoop: httpClient.eventLoopGroup.next())
408+
let httpBin = HTTPBin { _ in
409+
WriteAfterFutureSucceedsHandler(
410+
bodyFuture: delegate.optionsApplied.futureResult,
411+
endFuture: delegate.backpressurePromise.futureResult
412+
)
413+
}
376414

377415
defer {
378416
XCTAssertNoThrow(try httpClient.syncShutdown(requiresCleanClose: true))
@@ -381,27 +419,22 @@ class HTTPClientInternalTests: XCTestCase {
381419
}
382420

383421
let request = try Request(url: "http://localhost:\(httpBin.port)/custom")
384-
let delegate = BackpressureTestDelegate(eventLoop: httpClient.eventLoopGroup.next())
385-
let future = httpClient.execute(request: request, delegate: delegate).futureResult
386422

387-
let channel = try promise.futureResult.wait()
423+
let requestFuture = httpClient.execute(request: request, delegate: delegate).futureResult
388424

389425
// We need to wait for channel options that limit NIO to sending only one byte at a time.
390426
try delegate.optionsApplied.futureResult.wait()
391427

428+
//
392429
// Send 4 bytes, but only one should be received until the backpressure promise is succeeded.
393-
let buffer = channel.allocator.buffer(string: "1234")
394-
try channel.writeAndFlush(HTTPServerResponsePart.body(.byteBuffer(buffer))).wait()
395430

396431
// Now we wait until message is delivered to client channel pipeline
397432
try delegate.messageReceived.futureResult.wait()
398433
XCTAssertEqual(delegate.reads, 1)
399434

400435
// Succeed the backpressure promise.
401436
delegate.backpressurePromise.succeed(())
402-
403-
try channel.writeAndFlush(HTTPServerResponsePart.end(nil)).wait()
404-
try future.wait()
437+
try requestFuture.wait()
405438

406439
// At this point all other bytes should be delivered.
407440
XCTAssertEqual(delegate.reads, 4)
@@ -602,7 +635,7 @@ class HTTPClientInternalTests: XCTestCase {
602635
}
603636

604637
func testResponseConnectionCloseGet() throws {
605-
let httpBin = HTTPBin(ssl: false)
638+
let httpBin = HTTPBin(.http1_1())
606639
let httpClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup),
607640
configuration: HTTPClient.Configuration(certificateVerification: .none))
608641
defer {
@@ -756,14 +789,14 @@ class HTTPClientInternalTests: XCTestCase {
756789
struct NoChannelError: Error {}
757790

758791
let client = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup))
759-
var maybeServersAndChannels: [(HTTPBin, Channel)]?
792+
var maybeServersAndChannels: [(HTTPBin<HTTPBinHandler>, Channel)]?
760793
XCTAssertNoThrow(maybeServersAndChannels = try (0..<10).map { _ in
761794
let web = HTTPBin()
762795
defer {
763796
XCTAssertNoThrow(try web.shutdown())
764797
}
765798

766-
let req = try! HTTPClient.Request(url: "http://localhost:\(web.serverChannel.localAddress!.port!)/get",
799+
let req = try! HTTPClient.Request(url: "http://localhost:\(web.port)/get",
767800
method: .GET,
768801
body: nil)
769802
var maybeConnection: Connection?
@@ -847,7 +880,7 @@ class HTTPClientInternalTests: XCTestCase {
847880
XCTAssertNoThrow(try client.syncShutdown())
848881
}
849882

850-
let req = try! HTTPClient.Request(url: "http://localhost:\(web.serverChannel.localAddress!.port!)/get",
883+
let req = try! HTTPClient.Request(url: "http://localhost:\(web.port)/get",
851884
method: .GET,
852885
body: nil)
853886

@@ -1083,7 +1116,7 @@ class HTTPClientInternalTests: XCTestCase {
10831116
let el1 = elg.next()
10841117
let el2 = elg.next()
10851118

1086-
let httpBin = HTTPBin(refusesConnections: true)
1119+
let httpBin = HTTPBin(.refuse)
10871120
let client = HTTPClient(eventLoopGroupProvider: .shared(elg))
10881121

10891122
defer {

Tests/AsyncHTTPClientTests/HTTPClientNIOTSTests.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class HTTPClientNIOTSTests: XCTestCase {
5252
func testTLSFailError() {
5353
guard isTestingNIOTS() else { return }
5454

55-
let httpBin = HTTPBin(ssl: true)
55+
let httpBin = HTTPBin(.http1_1(ssl: true))
5656
let httpClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup))
5757
defer {
5858
XCTAssertNoThrow(try httpClient.syncShutdown(requiresCleanClose: true))
@@ -76,7 +76,7 @@ class HTTPClientNIOTSTests: XCTestCase {
7676

7777
func testConnectionFailError() {
7878
guard isTestingNIOTS() else { return }
79-
let httpBin = HTTPBin(ssl: true)
79+
let httpBin = HTTPBin(.http1_1(ssl: true))
8080
let httpClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup),
8181
configuration: .init(timeout: .init(connect: .milliseconds(100),
8282
read: .milliseconds(100))))
@@ -96,7 +96,7 @@ class HTTPClientNIOTSTests: XCTestCase {
9696
func testTLSVersionError() {
9797
guard isTestingNIOTS() else { return }
9898
#if canImport(Network)
99-
let httpBin = HTTPBin(ssl: true)
99+
let httpBin = HTTPBin(.http1_1(ssl: true))
100100
var tlsConfig = TLSConfiguration.makeClientConfiguration()
101101
tlsConfig.certificateVerification = .none
102102
tlsConfig.minimumTLSVersion = .tlsv11

0 commit comments

Comments
 (0)