Skip to content

Commit e08bd92

Browse files
committed
Added TODO
1 parent c08452c commit e08bd92

File tree

2 files changed

+100
-42
lines changed

2 files changed

+100
-42
lines changed

Diff for: Sources/AsyncHTTPClient/ConnectionPool/HTTP2/HTTP2Connection.swift

+80-32
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@ import NIOHTTP2
1818

1919
protocol HTTP2ConnectionDelegate {
2020
func http2ConnectionStreamClosed(_: HTTP2Connection, availableStreams: Int)
21+
func http2ConnectionGoAwayReceived(_: HTTP2Connection)
2122
func http2ConnectionClosed(_: HTTP2Connection)
2223
}
2324

25+
struct HTTP2PushNotSupportedError: Error {}
26+
27+
struct HTTP2ReceivedGoAwayBeforeSettingsError: Error {}
28+
2429
class HTTP2Connection {
2530
let channel: Channel
2631
let multiplexer: HTTP2StreamMultiplexer
@@ -30,22 +35,20 @@ class HTTP2Connection {
3035
let delegate: HTTP2ConnectionDelegate
3136

3237
enum State {
38+
case initialized
3339
case starting(EventLoopPromise<Void>)
3440
case active(HTTP2Settings)
41+
case closing
3542
case closed
3643
}
3744

38-
var readyToAcceptConnectionsFuture: EventLoopFuture<Void>
39-
4045
var settings: HTTP2Settings? {
4146
self.channel.eventLoop.assertInEventLoop()
4247
switch self.state {
43-
case .starting:
48+
case .initialized, .starting, .closing, .closed:
4449
return nil
4550
case .active(let settings):
4651
return settings
47-
case .closed:
48-
return nil
4952
}
5053
}
5154

@@ -55,12 +58,10 @@ class HTTP2Connection {
5558
init(channel: Channel,
5659
connectionID: HTTPConnectionPool.Connection.ID,
5760
delegate: HTTP2ConnectionDelegate,
58-
logger: Logger) throws {
61+
logger: Logger) {
5962
precondition(channel.isActive)
6063
channel.eventLoop.preconditionInEventLoop()
6164

62-
let readyToAcceptConnectionsPromise = channel.eventLoop.makePromise(of: Void.self)
63-
6465
self.channel = channel
6566
self.id = connectionID
6667
self.logger = logger
@@ -71,32 +72,30 @@ class HTTP2Connection {
7172
outboundBufferSizeHighWatermark: 8196,
7273
outboundBufferSizeLowWatermark: 4092,
7374
inboundStreamInitializer: { (channel) -> EventLoopFuture<Void> in
74-
struct HTTP2PushNotsupportedError: Error {}
75-
return channel.eventLoop.makeFailedFuture(HTTP2PushNotsupportedError())
75+
76+
return channel.eventLoop.makeFailedFuture(HTTP2PushNotSupportedError())
7677
}
7778
)
7879
self.delegate = delegate
79-
self.state = .starting(readyToAcceptConnectionsPromise)
80-
self.readyToAcceptConnectionsFuture = readyToAcceptConnectionsPromise.futureResult
81-
82-
// 1. Modify channel pipeline and add http2 handlers
83-
let sync = channel.pipeline.syncOperations
84-
85-
let http2Handler = NIOHTTP2Handler(mode: .client, initialSettings: nioDefaultSettings)
86-
let idleHandler = HTTP2IdleHandler(connection: self, logger: self.logger)
87-
88-
try sync.addHandler(http2Handler, position: .last)
89-
try sync.addHandler(idleHandler, position: .last)
90-
try sync.addHandler(self.multiplexer, position: .last)
91-
92-
// 2. set properties
93-
94-
// with this we create an intended retain cycle...
95-
channel.closeFuture.whenComplete { _ in
96-
self.state = .closed
97-
self.delegate.http2ConnectionClosed(self)
80+
self.state = .initialized
81+
}
82+
83+
deinit {
84+
guard case .closed = self.state else {
85+
preconditionFailure("")
9886
}
9987
}
88+
89+
static func start(
90+
channel: Channel,
91+
connectionID: HTTPConnectionPool.Connection.ID,
92+
delegate: HTTP2ConnectionDelegate,
93+
configuration: HTTPClient.Configuration,
94+
logger: Logger
95+
) -> EventLoopFuture<HTTP2Connection> {
96+
let connection = HTTP2Connection(channel: channel, connectionID: connectionID, delegate: delegate, logger: logger)
97+
return connection.start().map{ _ in connection }
98+
}
10099

101100
func execute(request: HTTPExecutableRequest) {
102101
let createStreamChannelPromise = self.channel.eventLoop.makePromise(of: Channel.self)
@@ -128,19 +127,68 @@ class HTTP2Connection {
128127
self.channel.eventLoop.assertInEventLoop()
129128

130129
switch self.state {
130+
case .initialized, .closed:
131+
preconditionFailure("Invalid state: \(self.state)")
131132
case .starting(let promise):
132133
self.state = .active(settings)
133134
promise.succeed(())
134135
case .active:
135136
self.state = .active(settings)
136-
case .closed:
137-
preconditionFailure("Invalid state")
137+
case .closing:
138+
// ignore. we only wait for all connections to be closed anyway.
139+
break
138140
}
139141
}
140142

141-
func http2GoAwayReceived() {}
143+
func http2GoAwayReceived() {
144+
self.channel.eventLoop.assertInEventLoop()
145+
146+
switch self.state {
147+
case .initialized, .closed:
148+
preconditionFailure("Invalid state: \(self.state)")
149+
150+
case .starting(let promise):
151+
self.state = .closing
152+
promise.fail(HTTP2ReceivedGoAwayBeforeSettingsError())
153+
154+
case .active:
155+
self.state = .closing
156+
self.delegate.http2ConnectionGoAwayReceived(self)
157+
158+
case .closing:
159+
// we are already closing. Nothing new
160+
break
161+
}
162+
}
142163

143164
func http2StreamClosed(availableStreams: Int) {
144165
self.delegate.http2ConnectionStreamClosed(self, availableStreams: availableStreams)
145166
}
167+
168+
private func start() -> EventLoopFuture<Void> {
169+
170+
let readyToAcceptConnectionsPromise = channel.eventLoop.makePromise(of: Void.self)
171+
172+
self.state = .starting(readyToAcceptConnectionsPromise)
173+
self.channel.closeFuture.whenComplete { _ in
174+
self.state = .closed
175+
self.delegate.http2ConnectionClosed(self)
176+
}
177+
178+
do {
179+
let sync = channel.pipeline.syncOperations
180+
181+
let http2Handler = NIOHTTP2Handler(mode: .client, initialSettings: nioDefaultSettings)
182+
let idleHandler = HTTP2IdleHandler(connection: self, logger: self.logger)
183+
184+
try sync.addHandler(http2Handler, position: .last)
185+
try sync.addHandler(idleHandler, position: .last)
186+
try sync.addHandler(self.multiplexer, position: .last)
187+
} catch {
188+
self.channel.close(mode: .all, promise: nil)
189+
readyToAcceptConnectionsPromise.fail(error)
190+
}
191+
192+
return readyToAcceptConnectionsPromise.futureResult
193+
}
146194
}

Diff for: Sources/AsyncHTTPClient/ConnectionPool/HTTP2/HTTP2IdleHandler.swift

+20-10
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,30 @@ extension HTTP2IdleHandler {
116116
}
117117

118118
mutating func settingsReceived(_ settings: HTTP2Settings) -> Action {
119-
guard case .connected = self.state else {
120-
preconditionFailure("Invalid state")
119+
switch self.state {
120+
case .initialized, .closed:
121+
preconditionFailure("Invalid state: \(self.state)")
122+
123+
case .connected:
124+
let maxStreams = settings.last(where: { $0.parameter == .maxConcurrentStreams })?.value ?? 100
125+
self.state = .active(openStreams: 0, maxStreams: maxStreams)
126+
return .notifyConnectionNewSettings(settings)
127+
128+
case .active(openStreams: let openStreams, maxStreams: let maxStreams):
129+
if let newMaxStreams = settings.last(where: { $0.parameter == .maxConcurrentStreams })?.value, newMaxStreams != maxStreams {
130+
self.state = .active(openStreams: openStreams, maxStreams: newMaxStreams)
131+
return .notifyConnectionNewSettings(settings)
132+
}
133+
return .nothing
134+
135+
case .goAwayReceived:
136+
return .nothing
121137
}
122-
123-
let maxStream = settings.last(where: { $0.parameter == .maxConcurrentStreams })?.value ?? 100
124-
125-
self.state = .active(openStreams: 0, maxStreams: maxStream)
126-
return .notifyConnectionNewSettings(settings)
127138
}
128139

129140
mutating func goAwayReceived() -> Action {
130141
switch self.state {
131-
case .initialized:
142+
case .initialized, .closed:
132143
preconditionFailure("Invalid state")
133144
case .connected:
134145
self.state = .goAwayReceived(openStreams: 0, maxStreams: 0)
@@ -138,8 +149,6 @@ extension HTTP2IdleHandler {
138149
return .notifyConnectionGoAwayReceived
139150
case .goAwayReceived:
140151
return .nothing
141-
case .closed:
142-
preconditionFailure("Invalid state")
143152
}
144153
}
145154

@@ -158,6 +167,7 @@ extension HTTP2IdleHandler {
158167
mutating func streamClosed() -> Action {
159168
guard case .active(var openStreams, let maxStreams) = self.state else {
160169
preconditionFailure("Invalid state")
170+
// TODO: What happens, if we received a go away?!??!
161171
}
162172

163173
openStreams -= 1

0 commit comments

Comments
 (0)