Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check if self is nil in infinite while loop. #448

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 29 additions & 32 deletions Sources/WebSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ enum InternalErrorCode: UInt16 {
case compressionError = 2
case invalidSSLError = 3
case writeTimeoutError = 4
case writeStreamClosed = 5
}

//WebSocketClient is setup to be dependency injection for testing
Expand Down Expand Up @@ -187,10 +188,10 @@ open class FoundationStream : NSObject, WSStream, StreamDelegate {
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
if resIn != errSecSuccess {
completion(errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn)))
completion(ErrorHandler.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn)))
}
if resOut != errSecSuccess {
completion(errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut)))
completion(ErrorHandler.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut)))
}
}
#endif
Expand All @@ -206,12 +207,14 @@ open class FoundationStream : NSObject, WSStream, StreamDelegate {
var out = timeout// wait X seconds before giving up
FoundationStream.sharedWorkQueue.async { [weak self] in
while !outStream.hasSpaceAvailable {
if self == nil {
completion(ErrorHandler.errorWithDetail("outStream was closed", code: InternalErrorCode.writeStreamClosed.rawValue))
return
}
usleep(100) // wait until the socket is ready
out -= 100
if out < 0 {
guard let s = self else {return}
let errCode = InternalErrorCode.writeTimeoutError.rawValue
completion(s.errorWithDetail("write wait timed out", code: errCode))
completion(ErrorHandler.errorWithDetail("write wait timed out", code: InternalErrorCode.writeTimeoutError.rawValue))
return
} else if let error = outStream.streamError {
completion(error)
Expand Down Expand Up @@ -290,12 +293,7 @@ open class FoundationStream : NSObject, WSStream, StreamDelegate {
delegate?.streamDidError(error: nil)
}
}

private func errorWithDetail(_ detail: String, code: UInt16) -> Error {
var details = [String: String]()
details[NSLocalizedDescriptionKey] = detail
return NSError(domain: WebSocket.ErrorDomain, code: Int(code), userInfo: details) as Error
}

}

//WebSocket implementation
Expand Down Expand Up @@ -680,7 +678,7 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
}
if !s.certValidated {
let errCode = InternalErrorCode.invalidSSLError.rawValue
let error = s.errorWithDetail("Invalid SSL certificate", code: errCode)
let error = ErrorHandler.errorWithDetail("Invalid SSL certificate", code: errCode)
s.disconnectStream(error)
return
}
Expand Down Expand Up @@ -788,7 +786,7 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
fragBuffer = Data(bytes: buffer, count: bufferLen)
break // do nothing, we are going to collect more data
default:
doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
doDisconnect(ErrorHandler.errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
}
}

Expand Down Expand Up @@ -987,21 +985,21 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
}
if (isMasked > 0 || (RSVMask & baseAddress[0]) > 0) && receivedOpcode != .pong && !compressionState.messageNeedsDecompression {
let errCode = CloseCode.protocolError.rawValue
doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode))
doDisconnect(ErrorHandler.errorWithDetail("masked and rsv data is not currently supported", code: errCode))
writeError(errCode)
return emptyBuffer
}
let isControlFrame = (receivedOpcode == .connectionClose || receivedOpcode == .ping)
if !isControlFrame && (receivedOpcode != .binaryFrame && receivedOpcode != .continueFrame &&
receivedOpcode != .textFrame && receivedOpcode != .pong) {
let errCode = CloseCode.protocolError.rawValue
doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcodeRawValue)", code: errCode))
doDisconnect(ErrorHandler.errorWithDetail("unknown opcode: \(receivedOpcodeRawValue)", code: errCode))
writeError(errCode)
return emptyBuffer
}
if isControlFrame && isFin == 0 {
let errCode = CloseCode.protocolError.rawValue
doDisconnect(errorWithDetail("control frames can't be fragmented", code: errCode))
doDisconnect(ErrorHandler.errorWithDetail("control frames can't be fragmented", code: errCode))
writeError(errCode)
return emptyBuffer
}
Expand All @@ -1016,7 +1014,7 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
}
}
if payloadLen < 2 {
doDisconnect(errorWithDetail("connection closed by server", code: closeCode))
doDisconnect(ErrorHandler.errorWithDetail("connection closed by server", code: closeCode))
writeError(closeCode)
return emptyBuffer
}
Expand Down Expand Up @@ -1055,7 +1053,7 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
} catch {
let closeReason = "Decompression failed: \(error)"
let closeCode = CloseCode.encoding.rawValue
doDisconnect(errorWithDetail(closeReason, code: closeCode))
doDisconnect(ErrorHandler.errorWithDetail(closeReason, code: closeCode))
writeError(closeCode)
return emptyBuffer
}
Expand All @@ -1070,7 +1068,7 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
} else {
closeCode = CloseCode.protocolError.rawValue
}
doDisconnect(errorWithDetail(closeReason, code: closeCode))
doDisconnect(ErrorHandler.errorWithDetail(closeReason, code: closeCode))
writeError(closeCode)
return emptyBuffer
}
Expand All @@ -1091,15 +1089,15 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
}
if isFin == 0 && receivedOpcode == .continueFrame && response == nil {
let errCode = CloseCode.protocolError.rawValue
doDisconnect(errorWithDetail("continue frame before a binary or text frame", code: errCode))
doDisconnect(ErrorHandler.errorWithDetail("continue frame before a binary or text frame", code: errCode))
writeError(errCode)
return emptyBuffer
}
var isNew = false
if response == nil {
if receivedOpcode == .continueFrame {
let errCode = CloseCode.protocolError.rawValue
doDisconnect(errorWithDetail("first frame can't be a continue frame",
doDisconnect(ErrorHandler.errorWithDetail("first frame can't be a continue frame",
code: errCode))
writeError(errCode)
return emptyBuffer
Expand All @@ -1114,7 +1112,7 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
response!.bytesLeft = Int(dataLength)
} else {
let errCode = CloseCode.protocolError.rawValue
doDisconnect(errorWithDetail("second and beyond of fragment message must be a continue frame",
doDisconnect(ErrorHandler.errorWithDetail("second and beyond of fragment message must be a continue frame",
code: errCode))
writeError(errCode)
return emptyBuffer
Expand Down Expand Up @@ -1189,15 +1187,6 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
return false
}

/**
Create an error
*/
private func errorWithDetail(_ detail: String, code: UInt16) -> Error {
var details = [String: String]()
details[NSLocalizedDescriptionKey] = detail
return NSError(domain: WebSocket.ErrorDomain, code: Int(code), userInfo: details) as Error
}

/**
Write an error to the socket
*/
Expand Down Expand Up @@ -1263,7 +1252,7 @@ open class WebSocket : NSObject, StreamDelegate, WebSocketClient, WSStreamDelega
if len <= 0 {
var error: Error?
let errCode = InternalErrorCode.outputStreamWriteError.rawValue
error = s.errorWithDetail("output stream error during write", code: errCode)
error = ErrorHandler.errorWithDetail("output stream error during write", code: errCode)
s.doDisconnect(error)
break
} else {
Expand Down Expand Up @@ -1341,4 +1330,12 @@ private extension UnsafeBufferPointer {

}

private struct ErrorHandler {
static func errorWithDetail(_ detail: String, code: UInt16) -> Error{
var details = [String: String]()
details[NSLocalizedDescriptionKey] = detail
return NSError(domain: WebSocket.ErrorDomain, code: Int(code), userInfo: details) as Error
}
}

private let emptyBuffer = UnsafeBufferPointer<UInt8>(start: nil, count: 0)