Skip to content

Commit de2ff82

Browse files
authored
Close on outbound finish (#708)
* Use closeOnOutboundFinish to ensure everything is written * Add testWriteLargeBodyAndClose * Require swift-nio 2.83.0 with outbound write fix
1 parent acaba2e commit de2ff82

File tree

4 files changed

+25
-3
lines changed

4 files changed

+25
-3
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ let package = Package(
2525
.package(url: "https://github.com/apple/swift-http-types.git", from: "1.0.0"),
2626
.package(url: "https://github.com/apple/swift-metrics.git", from: "2.5.0"),
2727
.package(url: "https://github.com/apple/swift-distributed-tracing.git", from: "1.1.0"),
28-
.package(url: "https://github.com/apple/swift-nio.git", from: "2.80.0"),
28+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.83.0"),
2929
.package(url: "https://github.com/apple/swift-nio-extras.git", from: "1.20.0"),
3030
.package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.34.1"),
3131
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.14.0"),

Sources/HummingbirdCore/Server/HTTP/HTTP1Channel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public struct HTTP1Channel: ServerChildChannel, HTTPChannelHandler {
9191
try channel.pipeline.syncOperations.addHandler(HTTPUserEventHandler(logger: logger))
9292
return try NIOAsyncChannel(
9393
wrappingChannelSynchronously: channel,
94-
configuration: .init()
94+
configuration: .init(isOutboundHalfClosureEnabled: true)
9595
)
9696
}
9797
}

Sources/HummingbirdCore/Server/HTTP/HTTPChannelHandler.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ extension HTTPChannelHandler {
5757
let responseWriter = ResponseWriter(outbound: outbound)
5858
try await self.responder(request, responseWriter, asyncChannel.channel)
5959
if request.headers[.connection] == "close" {
60-
return
60+
break
6161
}
6262

6363
// Flush current request
@@ -88,6 +88,9 @@ extension HTTPChannelHandler {
8888
try await outbound.write(.head(.init(status: .badRequest, headerFields: [.connection: "close", .contentLength: "0"])))
8989
try await outbound.write(.end(nil))
9090
}
91+
// close outbound and wait for channel to close
92+
outbound.finish()
93+
try await asyncChannel.channel.closeFuture.get()
9194
}
9295
} onCancel: {
9396
asyncChannel.channel.close(mode: .input, promise: nil)

Tests/HummingbirdCoreTests/CoreTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,25 @@ final class HummingbirdCoreTests: XCTestCase {
204204
)
205205
}
206206

207+
func testWriteLargeBodyAndClose() async throws {
208+
try await testServer(
209+
responder: { (_, responseWriter: consuming ResponseWriter, _) in
210+
let buffer = Self.randomBuffer(size: 1_140_000)
211+
var bodyWriter = try await responseWriter.writeHead(.init(status: .ok))
212+
try await bodyWriter.write(buffer)
213+
try await bodyWriter.finish(nil)
214+
},
215+
configuration: .init(address: .hostname(port: 0)),
216+
eventLoopGroup: Self.eventLoopGroup,
217+
logger: Logger(label: "Hummingbird"),
218+
test: { client in
219+
let response = try await client.get("/", headers: [.connection: "close"])
220+
let body = try XCTUnwrap(response.body)
221+
XCTAssertEqual(body.readableBytes, 1_140_000)
222+
}
223+
)
224+
}
225+
207226
func testStreamBody() async throws {
208227
try await testServer(
209228
responder: { (request, responseWriter: consuming ResponseWriter, _) in

0 commit comments

Comments
 (0)