Skip to content
This repository was archived by the owner on Apr 7, 2022. It is now read-only.

Commit 939d1f9

Browse files
committed
add support for enabling HTTP pipelining
1 parent 6973bf5 commit 939d1f9

3 files changed

Lines changed: 13 additions & 6 deletions

File tree

Sources/HTTP/Responder/HTTPServer.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public final class HTTPServer {
2323
/// - reuseAddress: When `true`, can prevent errors re-binding to a socket after successive server restarts.
2424
/// - tcpNoDelay: When `true`, OS will attempt to minimize TCP packet delay.
2525
/// - supportCompression: When `true`, HTTP server will support gzip and deflate compression.
26+
/// - supportPipelining: When `true`, HTTP server will support pipelined HTTP requests.
2627
/// - serverName: If set, this name will be serialized as the `Server` header in outgoing responses.
2728
/// - upgraders: An array of `HTTPProtocolUpgrader` to check for with each request.
2829
/// - worker: `Worker` to perform async work on.
@@ -36,6 +37,7 @@ public final class HTTPServer {
3637
reuseAddress: Bool = true,
3738
tcpNoDelay: Bool = true,
3839
supportCompression: Bool = false,
40+
supportPipelining: Bool = false,
3941
serverName: String? = nil,
4042
upgraders: [HTTPProtocolUpgrader] = [],
4143
on worker: Worker,
@@ -59,7 +61,7 @@ public final class HTTPServer {
5961

6062
// configure the pipeline
6163
return channel.pipeline.configureHTTPServerPipeline(
62-
withPipeliningAssistance: false,
64+
withPipeliningAssistance: supportPipelining,
6365
withServerUpgrade: upgrade,
6466
withErrorHandling: false
6567
).then {
@@ -126,6 +128,9 @@ private final class HTTPServerHandler<R>: ChannelInboundHandler where R: HTTPSer
126128

127129
/// Optional server header.
128130
private let serverHeader: String?
131+
132+
/// If true, we are waiting for a response to be sent.
133+
var awaitingReponse: Bool
129134

130135
/// Current HTTP state.
131136
var state: HTTPServerState
@@ -137,10 +142,12 @@ private final class HTTPServerHandler<R>: ChannelInboundHandler where R: HTTPSer
137142
self.errorHandler = onError
138143
self.serverHeader = serverHeader
139144
self.state = .ready
145+
self.awaitingReponse = false
140146
}
141147

142148
/// See `ChannelInboundHandler`.
143149
func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
150+
debugOnly { assert(!self.awaitingReponse, "Pipelined HTTP request detected. Enable pipelining to prevent this error.")}
144151
debugOnly { assert(ctx.channel.eventLoop.inEventLoop) }
145152
switch unwrapInboundIn(data) {
146153
case .head(let head):
@@ -197,6 +204,7 @@ private final class HTTPServerHandler<R>: ChannelInboundHandler where R: HTTPSer
197204
case .streamingBody(let stream): _ = stream.write(.end)
198205
}
199206
state = .ready
207+
self.awaitingReponse = true
200208
}
201209
}
202210

@@ -246,6 +254,7 @@ private final class HTTPServerHandler<R>: ChannelInboundHandler where R: HTTPSer
246254
}
247255

248256
// begin serializing
257+
self.awaitingReponse = false
249258
ctx.write(wrapOutboundOut(.head(reshead)), promise: nil)
250259
if reqhead.method == .HEAD || res.status == .noContent {
251260
// skip sending the body for HEAD requests

Tests/HTTPTests/HTTPClientTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ class HTTPClientTests: XCTestCase {
2626
try testURL("http://zombo.com", contains: "<title>ZOMBO</title>")
2727
}
2828

29-
func testAmazonWithTLS() throws {
30-
try testURL("https://www.amazon.com", contains: "Amazon.com, Inc.")
29+
func testVaporWithTLS() throws {
30+
try testURL("https://vapor.codes", contains: "Server-side Swift")
3131
}
3232

3333
func testQuery() throws {
@@ -41,7 +41,7 @@ class HTTPClientTests: XCTestCase {
4141
("testGoogleAPIsFCM", testGoogleAPIsFCM),
4242
("testExampleCom", testExampleCom),
4343
("testZombo", testZombo),
44-
("testAmazonWithTLS", testAmazonWithTLS),
44+
("testVaporWithTLS", testVaporWithTLS),
4545
("testQuery", testQuery),
4646
]
4747
}

Tests/HTTPTests/HTTPTests.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ class HTTPTests: XCTestCase {
9595
func upgrade(ctx: ChannelHandlerContext, upgradeResponse: HTTPResponseHead) -> EventLoopFuture<String> {
9696
return ctx.eventLoop.future("hello")
9797
}
98-
99-
10098
}
10199
do {
102100
_ = try HTTPClient.upgrade(hostname: "foo", upgrader: FakeUpgrader(), on: worker).wait()

0 commit comments

Comments
 (0)