Skip to content

Commit c80bd97

Browse files
author
John Kassebaum
committed
Make HTTP/2 flow control target window size configurable in a server connection.
Motivation: Higher streaming thruput from client to server is available by specifying a flow control window size higher than the initial value of 2^16-1. The target value needs to be passed either using SETTINGS_INITIAL_WINDOW_SIZE in the connection preface, or via a WINDOW_UPDATE. The HTTP2FlowControlWindow passes the value configured here in `windowUpdate`. Modifications: Added property `httpTargetWindowSize` to `Server.Configuration`. In `Server.Configuration.init`, added httpTargetWindowSize arg with default value 2^16-1. Added property and setter for `httpTargetWindowSize` to `Server.Builder`. During server bootstrap in Server.start, pass `configuration.httpTargetWindowSize` to the HTTPProtocolSwitcher. Configure http/2 flow control target window size on the http2 pipeline in HTTPProxySwitcher. Result: One can build a `Server` with a target window size value that is configured via a WINDOW_UPDATE after the connection is established.
1 parent b2d2b49 commit c80bd97

File tree

3 files changed

+34
-6
lines changed

3 files changed

+34
-6
lines changed

Sources/GRPC/HTTPProtocolSwitcher.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ internal class HTTPProtocolSwitcher {
2525
private let handlersInitializer: ((Channel) -> EventLoopFuture<Void>)
2626
private let errorDelegate: ServerErrorDelegate?
2727
private let logger = Logger(subsystem: .serverChannelCall)
28+
private let httpTargetWindowSize: Int
2829

2930
// We could receive additional data after the initial data and before configuring
3031
// the pipeline; buffer it and fire it down the pipeline once it is configured.
@@ -41,8 +42,13 @@ internal class HTTPProtocolSwitcher {
4142
}
4243
private var bufferedData: [NIOAny] = []
4344

44-
init(errorDelegate: ServerErrorDelegate?, handlersInitializer: (@escaping (Channel) -> EventLoopFuture<Void>)) {
45+
init(
46+
errorDelegate: ServerErrorDelegate?,
47+
httpTargetWindowSize: Int = 65535,
48+
handlersInitializer: (@escaping (Channel) -> EventLoopFuture<Void>)
49+
) {
4550
self.errorDelegate = errorDelegate
51+
self.httpTargetWindowSize = httpTargetWindowSize
4652
self.handlersInitializer = handlersInitializer
4753
}
4854
}
@@ -132,7 +138,10 @@ extension HTTPProtocolSwitcher: ChannelInboundHandler, RemovableChannelHandler {
132138
.cascade(to: pipelineConfigured)
133139

134140
case .http2:
135-
context.channel.configureHTTP2Pipeline(mode: .server) { (streamChannel, streamID) in
141+
context.channel.configureHTTP2Pipeline(
142+
mode: .server,
143+
targetWindowSize: httpTargetWindowSize
144+
) { (streamChannel, streamID) in
136145
streamChannel.pipeline.addHandler(HTTP2ToHTTP1ServerCodec(streamID: streamID, normalizeHTTPHeaders: true))
137146
.flatMap { self.handlersInitializer(streamChannel) }
138147
}

Sources/GRPC/Server.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ public final class Server {
9999
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
100100
// Set the handlers that are applied to the accepted Channels
101101
.childChannelInitializer { channel in
102-
let protocolSwitcher = HTTPProtocolSwitcher(errorDelegate: configuration.errorDelegate) { channel -> EventLoopFuture<Void> in
102+
let protocolSwitcher = HTTPProtocolSwitcher(
103+
errorDelegate: configuration.errorDelegate,
104+
httpTargetWindowSize: configuration.httpTargetWindowSize
105+
) { channel -> EventLoopFuture<Void> in
103106
let logger = Logger(subsystem: .serverChannelCall, metadata: [MetadataKey.requestID: "\(UUID())"])
104107
let handler = GRPCServerRequestRoutingHandler(
105108
servicesByName: configuration.serviceProvidersByName,
@@ -173,7 +176,7 @@ extension Server {
173176
public struct Configuration {
174177
/// The target to bind to.
175178
public var target: BindTarget
176-
179+
177180
/// The event loop group to run the connection on.
178181
public var eventLoopGroup: EventLoopGroup
179182

@@ -196,6 +199,9 @@ extension Server {
196199
/// streaming and bidirectional streaming RPCs) by passing setting `compression` to `.disabled`
197200
/// in `sendResponse(_:compression)`.
198201
public var messageEncoding: ServerMessageEncoding
202+
203+
/// The HTTP/2 flow control target window size.
204+
public var httpTargetWindowSize: Int
199205

200206
/// Create a `Configuration` with some pre-defined defaults.
201207
///
@@ -212,14 +218,16 @@ extension Server {
212218
serviceProviders: [CallHandlerProvider],
213219
errorDelegate: ServerErrorDelegate? = LoggingServerErrorDelegate.shared,
214220
tls: TLS? = nil,
215-
messageEncoding: ServerMessageEncoding = .disabled
221+
messageEncoding: ServerMessageEncoding = .disabled,
222+
httpTargetWindowSize: Int = 65535
216223
) {
217224
self.target = target
218225
self.eventLoopGroup = eventLoopGroup
219226
self.serviceProviders = serviceProviders
220227
self.errorDelegate = errorDelegate
221228
self.tls = tls
222229
self.messageEncoding = messageEncoding
230+
self.httpTargetWindowSize = httpTargetWindowSize
223231
}
224232
}
225233
}

Sources/GRPC/ServerBuilder.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ extension Server {
2323
private var providers: [CallHandlerProvider] = []
2424
private var errorDelegate: ServerErrorDelegate?
2525
private var messageEncoding: ServerMessageEncoding = .disabled
26+
private var httpTargetWindowSize: Int = 65535
2627

2728
fileprivate init(group: EventLoopGroup) {
2829
self.group = group
@@ -50,7 +51,8 @@ extension Server {
5051
serviceProviders: self.providers,
5152
errorDelegate: self.errorDelegate,
5253
tls: self.maybeTLS,
53-
messageEncoding: self.messageEncoding
54+
messageEncoding: self.messageEncoding,
55+
httpTargetWindowSize: self.httpTargetWindowSize
5456
)
5557
return Server.start(configuration: configuration)
5658
}
@@ -102,6 +104,15 @@ extension Server.Builder.Secure {
102104
}
103105
}
104106

107+
extension Server.Builder {
108+
/// Sets the HTTP/2 flow control target window size.
109+
@discardableResult
110+
public func withHttpTargetWindowSize(_ httpTargetWindowSize: Int) -> Self {
111+
self.httpTargetWindowSize = httpTargetWindowSize
112+
return self
113+
}
114+
}
115+
105116
extension Server {
106117
/// Returns an insecure `Server` builder which is *not configured with TLS*.
107118
public static func insecure(group: EventLoopGroup) -> Builder {

0 commit comments

Comments
 (0)