Skip to content

Commit cb75234

Browse files
committed
Don't crash if server capabilities are not available during connection close.
1 parent 98b8230 commit cb75234

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

Sources/MySQLNIO/MySQLConnectionHandler.swift

+25-6
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ final class MySQLConnectionHandler: ChannelDuplexHandler {
7474
case .commandPhase:
7575
if let current = self.queue.first {
7676
do {
77-
let commandState = try current.handler.handle(packet: &packet, capabilities: self.serverCapabilities!)
77+
guard let capabilities = self.serverCapabilities else {
78+
throw MySQLError.protocolError
79+
}
80+
let commandState = try current.handler.handle(packet: &packet, capabilities: capabilities)
7881
self.handleCommandState(context: context, commandState)
7982
} catch {
8083
self.queue.removeFirst()
@@ -226,7 +229,10 @@ final class MySQLConnectionHandler: ChannelDuplexHandler {
226229
database: state.database,
227230
authPluginName: authPluginName
228231
)
229-
try context.write(self.wrapOutboundOut(.encode(res, capabilities: self.serverCapabilities!)), promise: nil)
232+
guard let capabilities = self.serverCapabilities else {
233+
throw MySQLError.protocolError
234+
}
235+
try context.write(self.wrapOutboundOut(.encode(res, capabilities: capabilities)), promise: nil)
230236
context.flush()
231237
}
232238

@@ -264,7 +270,10 @@ final class MySQLConnectionHandler: ChannelDuplexHandler {
264270
}
265271
guard !packet.isError else {
266272
self.logger.trace("caching_sha2_password replied ERR, decoding")
267-
let err = try packet.decode(MySQLProtocol.ERR_Packet.self, capabilities: self.serverCapabilities!)
273+
guard let capabilities = self.serverCapabilities else {
274+
throw MySQLError.protocolError
275+
}
276+
let err = try packet.decode(MySQLProtocol.ERR_Packet.self, capabilities: capabilities)
268277
throw MySQLError.server(err)
269278
}
270279
guard let status = packet.payload.readInteger(endianness: .little, as: UInt8.self) else {
@@ -327,7 +336,10 @@ final class MySQLConnectionHandler: ChannelDuplexHandler {
327336
case "mysql_native_password":
328337
guard !packet.isError else {
329338
self.logger.trace("mysql_native_password sent ERR, decoding")
330-
let error = try packet.decode(MySQLProtocol.ERR_Packet.self, capabilities: self.serverCapabilities!)
339+
guard let capabilities = self.serverCapabilities else {
340+
throw MySQLError.protocolError
341+
}
342+
let error = try packet.decode(MySQLProtocol.ERR_Packet.self, capabilities: capabilities)
331343
throw MySQLError.server(error)
332344
}
333345
guard !packet.isOK else {
@@ -365,12 +377,16 @@ final class MySQLConnectionHandler: ChannelDuplexHandler {
365377
guard let command = self.queue.first else {
366378
return
367379
}
380+
guard let capabilities = self.serverCapabilities else {
381+
command.promise.fail(MySQLError.protocolError)
382+
return
383+
}
368384
self.commandState = .busy
369385

370386
// send initial
371387
do {
372388
self.sequence.current = nil
373-
let commandState = try command.handler.activate(capabilities: self.serverCapabilities!)
389+
let commandState = try command.handler.activate(capabilities: capabilities)
374390
self.handleCommandState(context: context, commandState)
375391
} catch {
376392
self.queue.removeFirst()
@@ -413,7 +429,10 @@ final class MySQLConnectionHandler: ChannelDuplexHandler {
413429
private func _close(context: ChannelHandlerContext, mode: CloseMode, promise: EventLoopPromise<Void>?) throws {
414430
self.sequence.reset()
415431
let quit = MySQLProtocol.COM_QUIT()
416-
try context.write(self.wrapOutboundOut(.encode(quit, capabilities: self.serverCapabilities!)), promise: nil)
432+
// N.B.: It is possible to get here without having processed a handshake packet yet, in which case there will
433+
// not be any serverCapabilities. Since COM_QUIT doesn't care about any of those anyway, don't crash if they're
434+
// not there!
435+
try context.write(self.wrapOutboundOut(.encode(quit, capabilities: self.serverCapabilities ?? .init())), promise: nil)
417436
context.flush()
418437

419438
if let promise = promise {

0 commit comments

Comments
 (0)