Merge branch 'development' of https://github.com/socketio/socket.io-client-swift into development

* 'development' of https://github.com/socketio/socket.io-client-swift:
  SocketAckEmitter.isExpected => .expected
  change isRequired() to isExpected()
  remove semicolon
  Update README.md
  add SocketAckEmitter.isRequired()
  Update README.md
  bump version
  bump websocket version
  fix Use Legacy Swift issue
  bump websocket version
  Update README.md
This commit is contained in:
Erik 2016-11-11 15:52:48 -05:00
commit 56278795ea
No known key found for this signature in database
GPG Key ID: 4930B7C5FBC1A69D
5 changed files with 78 additions and 74 deletions

View File

@ -39,7 +39,7 @@ SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url config:@{
[socket on:@"currentAmount" callback:^(NSArray* data, SocketAckEmitter* ack) {
double cur = [[data objectAtIndex:0] floatValue];
[[socket emitWithAck:@"canUpdate" withItems:@[@(cur)]] timingOutAfter:0 callback:^(NSArray* data) {
[[socket emitWithAck:@"canUpdate" with:@[@(cur)]] timingOutAfter:0 callback:^(NSArray* data) {
[socket emit:@"update" withItems:@[@{@"amount": @(cur + 2.50)}]];
}];
@ -95,7 +95,7 @@ Carthage
-----------------
Add this line to your `Cartfile`:
```
github "socketio/socket.io-client-swift" ~> 8.0.2 # Or latest version
github "socketio/socket.io-client-swift" ~> 8.1.0 # Or latest version
```
Run `carthage update --platform ios,macosx`.
@ -108,7 +108,7 @@ Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`:
use_frameworks!
target 'YourApp' do
pod 'Socket.IO-Client-Swift', '~> 8.0.2' # Or latest version
pod 'Socket.IO-Client-Swift', '~> 8.1.0' # Or latest version
end
```
@ -137,7 +137,7 @@ CocoaSeeds
Add this line to your `Seedfile`:
```
github "socketio/socket.io-client-swift", "v8.0.2", :files => "Source/*.swift" # Or latest version
github "socketio/socket.io-client-swift", "v8.1.0", :files => "Source/*.swift" # Or latest version
```
Run `seed install`.

View File

@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "Socket.IO-Client-Swift"
s.module_name = "SocketIO"
s.version = "8.0.2"
s.version = "8.1.0"
s.summary = "Socket.IO-client for iOS and OS X"
s.description = <<-DESC
Socket.IO-client for iOS and OS X.
@ -14,8 +14,9 @@ Pod::Spec.new do |s|
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10'
s.tvos.deployment_target = '9.0'
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v8.0.2' }
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v8.1.0' }
s.source_files = "Source/**/*.swift"
s.requires_arc = true
s.pod_target_xcconfig = {'SWIFT_VERSION' => '3.0'}
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
end

View File

@ -4,7 +4,7 @@
// Starscream
//
// Created by Dalton Cherry on 5/16/15.
// Copyright (c) 2014-2015 Dalton Cherry.
// Copyright (c) 2014-2016 Dalton Cherry.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -19,11 +19,14 @@
// limitations under the License.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
import Foundation
import Security
public class SSLCert : NSObject {
public protocol SSLTrustValidator {
func isValid(_ trust: SecTrust, domain: String?) -> Bool
}
open class SSLCert {
var certData: Data?
var key: SecKey?
@ -50,7 +53,7 @@ public class SSLCert : NSObject {
}
}
public class SSLSecurity : NSObject {
open class SSLSecurity : SSLTrustValidator {
public var validatedDN = true //should the domain name be validated?
var isReady = false //is the key processing done?
@ -82,7 +85,7 @@ public class SSLSecurity : NSObject {
/**
Designated init
- parameter keys: is the certificates or public keys to use
- parameter certs: is the certificates or public keys to use
- parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning validation
- returns: a representation security object to be used with
@ -90,8 +93,6 @@ public class SSLSecurity : NSObject {
public init(certs: [SSLCert], usePublicKeys: Bool) {
self.usePublicKeys = usePublicKeys
super.init()
if self.usePublicKeys {
DispatchQueue.global(qos: .default).async {
let pubKeys = certs.reduce([SecKey]()) { (pubKeys: [SecKey], cert: SSLCert) -> [SecKey] in

View File

@ -27,6 +27,10 @@ import Foundation
public final class SocketAckEmitter : NSObject {
let socket: SocketIOClient
let ackNum: Int
public var expected: Bool {
return ackNum != -1
}
init(socket: SocketIOClient, ackNum: Int) {
self.socket = socket
@ -44,6 +48,7 @@ public final class SocketAckEmitter : NSObject {
socket.emitAck(ackNum, with: items)
}
}
public final class OnAckCallback : NSObject {

View File

@ -3,7 +3,7 @@
// Websocket.swift
//
// Created by Dalton Cherry on 7/16/14.
// Copyright (c) 2014-2015 Dalton Cherry.
// Copyright (c) 2014-2016 Dalton Cherry.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -18,7 +18,6 @@
// limitations under the License.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
import Foundation
import CoreFoundation
import Security
@ -38,7 +37,7 @@ public protocol WebSocketPongDelegate: class {
func websocketDidReceivePong(socket: WebSocket, data: Data?)
}
public class WebSocket : NSObject, StreamDelegate {
open class WebSocket : NSObject, StreamDelegate {
enum OpCode : UInt8 {
case continueFrame = 0x0
@ -77,7 +76,6 @@ public class WebSocket : NSObject, StreamDelegate {
var optionalProtocols: [String]?
// MARK: - Constants
let headerWSUpgradeName = "Upgrade"
let headerWSUpgradeValue = "websocket"
let headerWSHostName = "Host"
@ -108,7 +106,6 @@ public class WebSocket : NSObject, StreamDelegate {
}
// MARK: - Delegates
/// Responds to callback about new messages coming in over the WebSocket
/// and also connection/disconnect messages.
public weak var delegate: WebSocketDelegate?
@ -118,7 +115,6 @@ public class WebSocket : NSObject, StreamDelegate {
// MARK: - Block based API.
public var onConnect: ((Void) -> Void)?
public var onDisconnect: ((NSError?) -> Void)?
public var onText: ((String) -> Void)?
@ -128,7 +124,7 @@ public class WebSocket : NSObject, StreamDelegate {
public var headers = [String: String]()
public var voipEnabled = false
public var disableSSLCertValidation = false
public var security: SSLSecurity?
public var security: SSLTrustValidator?
public var enabledSSLCipherSuites: [SSLCipherSuite]?
public var origin: String?
public var timeout = 5
@ -139,7 +135,6 @@ public class WebSocket : NSObject, StreamDelegate {
public var currentURL: URL { return url }
// MARK: - Private
private var url: URL
private var inputStream: InputStream?
private var outputStream: OutputStream?
@ -198,7 +193,8 @@ public class WebSocket : NSObject, StreamDelegate {
public func disconnect(forceTimeout: TimeInterval? = nil, closeCode: UInt16 = CloseCode.normal.rawValue) {
switch forceTimeout {
case .some(let seconds) where seconds > 0:
callbackQueue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(seconds * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { [weak self] in
let milliseconds = Int(seconds * 1_000)
callbackQueue.asyncAfter(deadline: .now() + .milliseconds(milliseconds)) { [weak self] in
self?.disconnectStream(nil)
}
fallthrough
@ -213,7 +209,7 @@ public class WebSocket : NSObject, StreamDelegate {
/**
Write a string to the websocket. This sends it as a text frame.
If you supply a non-nil completion block, I will perform it when the write completes.
- parameter str: The string to write.
- parameter string: The string to write.
- parameter completion: The (optional) completion handler.
*/
public func write(string: String, completion: (() -> ())? = nil) {
@ -305,7 +301,6 @@ public class WebSocket : NSObject, StreamDelegate {
private func initStreamsWithData(_ data: Data, _ port: Int) {
//higher level API we will cut over to at some point
//NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream)
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
let h = url.host! as NSString
@ -318,6 +313,28 @@ public class WebSocket : NSObject, StreamDelegate {
if supportedSSLSchemes.contains(url.scheme!) {
inStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
outStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
if disableSSLCertValidation {
let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(value: false), kCFStreamSSLPeerName: kCFNull]
inStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
outStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
}
if let cipherSuites = self.enabledSSLCipherSuites {
if let sslContextIn = CFReadStreamCopyProperty(inputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext?,
let sslContextOut = CFWriteStreamCopyProperty(outputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext? {
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
if resIn != errSecSuccess {
let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn))
disconnectStream(error)
return
}
if resOut != errSecSuccess {
let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut))
disconnectStream(error)
return
}
}
}
} else {
certValidated = true //not a https session, so no need to check SSL pinning
}
@ -325,28 +342,6 @@ public class WebSocket : NSObject, StreamDelegate {
inStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
outStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
}
if disableSSLCertValidation {
let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(value: false), kCFStreamSSLPeerName: kCFNull]
inStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
outStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
}
if let cipherSuites = self.enabledSSLCipherSuites {
if let sslContextIn = CFReadStreamCopyProperty(inputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext?,
let sslContextOut = CFWriteStreamCopyProperty(outputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext? {
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
if resIn != errSecSuccess {
let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn))
disconnectStream(error)
return
}
if resOut != errSecSuccess {
let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut))
disconnectStream(error)
return
}
}
}
CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
@ -358,7 +353,7 @@ public class WebSocket : NSObject, StreamDelegate {
self.mutex.unlock()
let bytes = UnsafeRawPointer((data as NSData).bytes).assumingMemoryBound(to: UInt8.self)
var out = timeout * 1000000 // wait 5 seconds before giving up
var out = timeout * 1_000_000 // wait 5 seconds before giving up
writeQueue.addOperation { [weak self] in
while !outStream.hasSpaceAvailable {
usleep(100) // wait until the socket is ready
@ -380,9 +375,9 @@ public class WebSocket : NSObject, StreamDelegate {
*/
public func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
if let sec = security, !certValidated && [.hasBytesAvailable, .hasSpaceAvailable].contains(eventCode) {
let trust = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as AnyObject
let trust = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust
let domain = aStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as? String
if sec.isValid(trust as! SecTrust, domain: domain) {
if sec.isValid(trust, domain: domain) {
certValidated = true
} else {
let error = errorWithDetail("Invalid SSL certificate", code: 1)
@ -439,7 +434,6 @@ public class WebSocket : NSObject, StreamDelegate {
let buf = NSMutableData(capacity: BUFFER_MAX)
let buffer = UnsafeMutableRawPointer(mutating: buf!.bytes).assumingMemoryBound(to: UInt8.self)
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
guard length > 0 else { return }
var process = false
if inputQueue.count == 0 {
@ -635,34 +629,22 @@ public class WebSocket : NSObject, StreamDelegate {
writeError(errCode)
return emptyBuffer
}
var closeCode = CloseCode.normal.rawValue
if receivedOpcode == .connectionClose {
var code = CloseCode.normal.rawValue
if payloadLen == 1 {
code = CloseCode.protocolError.rawValue
closeCode = CloseCode.protocolError.rawValue
} else if payloadLen > 1 {
code = WebSocket.readUint16(baseAddress, offset: offset)
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
code = CloseCode.protocolError.rawValue
}
offset += 2
}
var closeReason = "connection closed by server"
if payloadLen > 2 {
let len = Int(payloadLen - 2)
if len > 0 {
let bytes = baseAddress + offset
if let customCloseReason = String(data: Data(bytes: bytes, count: len), encoding: .utf8) {
closeReason = customCloseReason
} else {
code = CloseCode.protocolError.rawValue
}
closeCode = WebSocket.readUint16(baseAddress, offset: offset)
if closeCode < 1000 || (closeCode > 1003 && closeCode < 1007) || (closeCode > 1011 && closeCode < 3000) {
closeCode = CloseCode.protocolError.rawValue
}
}
doDisconnect(errorWithDetail(closeReason, code: code))
writeError(code)
return emptyBuffer
}
if isControlFrame && payloadLen > 125 {
if payloadLen < 2 {
doDisconnect(errorWithDetail("connection closed by server", code: closeCode))
writeError(closeCode)
return emptyBuffer
}
} else if isControlFrame && payloadLen > 125 {
writeError(CloseCode.protocolError.rawValue)
return emptyBuffer
}
@ -687,8 +669,24 @@ public class WebSocket : NSObject, StreamDelegate {
len = 0
data = Data()
} else {
if receivedOpcode == .connectionClose && len > 0 {
let size = MemoryLayout<UInt16>.size
offset += size
len -= UInt64(size)
}
data = Data(bytes: baseAddress+offset, count: Int(len))
}
if receivedOpcode == .connectionClose {
var closeReason = "connection closed by server"
if let customCloseReason = String(data: data, encoding: .utf8) {
closeReason = customCloseReason
} else {
closeCode = CloseCode.protocolError.rawValue
}
doDisconnect(errorWithDetail(closeReason, code: closeCode))
writeError(closeCode)
return emptyBuffer
}
if receivedOpcode == .pong {
if canDispatch {
callbackQueue.async { [weak self] in
@ -902,7 +900,6 @@ public class WebSocket : NSObject, StreamDelegate {
}
// MARK: - Deinit
deinit {
mutex.lock()
readyToWrite = false