diff --git a/CHANGELOG.md b/CHANGELOG.md
index c934b93c..e80e4a2e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,18 @@
All notable changes to this project will be documented in this file.
`Starscream` adheres to [Semantic Versioning](http://semver.org/).
+#### [2.1.0](https://github.com/daltoniam/Starscream/tree/2.1.0)
+
+Adds WebSocket compression. Also adds advance WebSocket delegate for extra control. Bug Fixes.
+
+[#349](https://github.com/daltoniam/Starscream/pull/349)
+[#344](https://github.com/daltoniam/Starscream/pull/344)
+[#337](https://github.com/daltoniam/Starscream/pull/337)
+[#334](https://github.com/daltoniam/Starscream/issues/334)
+[#333](https://github.com/daltoniam/Starscream/pull/333)
+[#319](https://github.com/daltoniam/Starscream/issues/319)
+[#309](https://github.com/daltoniam/Starscream/issues/309)
+
#### [2.0.4](https://github.com/daltoniam/Starscream/tree/2.0.4)
SSL Pinning fix by Giuliano Galea as reported by Lukas Futera of [Centralway](https://www.centralway.com/de/).
diff --git a/README.md b/README.md
index 2c23a5d1..4a7639f6 100644
--- a/README.md
+++ b/README.md
@@ -187,16 +187,11 @@ socket.delegate = self
socket.connect()
```
-### Self Signed SSL and VOIP
-
-There are a couple of other properties that modify the stream:
+### Self Signed SSL
```swift
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
-//set this if you are planning on using the socket in a VOIP background setting (using the background VOIP service).
-socket.voipEnabled = true
-
//set this you want to ignore SSL cert validation, so a self signed SSL certificate can be used.
socket.disableSSLCertValidation = true
```
diff --git a/Source/Info-tvOS.plist b/Source/Info-tvOS.plist
index 24551b51..a664afcf 100644
--- a/Source/Info-tvOS.plist
+++ b/Source/Info-tvOS.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 2.0.4
+ 2.1.0
CFBundleSignature
????
CFBundleVersion
diff --git a/Source/Info.plist b/Source/Info.plist
index 241ef869..dca568ec 100644
--- a/Source/Info.plist
+++ b/Source/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 2.0.4
+ 2.1.0
CFBundleSignature
????
CFBundleVersion
diff --git a/Source/WebSocket.swift b/Source/WebSocket.swift
index 24808cab..5efc1d5f 100644
--- a/Source/WebSocket.swift
+++ b/Source/WebSocket.swift
@@ -21,7 +21,7 @@
import Foundation
import CoreFoundation
-import Security
+import CommonCrypto
public let WebsocketDidConnectNotification = "WebsocketDidConnectNotification"
public let WebsocketDidDisconnectNotification = "WebsocketDidDisconnectNotification"
@@ -80,6 +80,8 @@ open class WebSocket : NSObject, StreamDelegate {
// 0-999 WebSocket status codes not used
case outputStreamWriteError = 1
case compressionError = 2
+ case invalidSSLError = 3
+ case writeTimeoutError = 4
}
// Where the callback is executed. It defaults to the main UI thread queue.
@@ -168,7 +170,6 @@ open class WebSocket : NSObject, StreamDelegate {
public var httpMethod: HTTPMethod = .get
public var headers = [String: String]()
- public var voipEnabled = false
public var disableSSLCertValidation = false
public var enableCompression = true
public var security: SSLTrustValidator?
@@ -207,6 +208,7 @@ open class WebSocket : NSObject, StreamDelegate {
private var certValidated = false
private var didDisconnect = false
private var readyToWrite = false
+ private var headerSecKey = ""
private let mutex = NSLock()
private let notificationCenter = NotificationCenter.default
private var canDispatch: Bool {
@@ -329,8 +331,9 @@ open class WebSocket : NSObject, StreamDelegate {
if let protocols = optionalProtocols {
addHeader(urlRequest, key: headerWSProtocolName, val: protocols.joined(separator: ","))
}
+ headerSecKey = generateWebSocketKey()
addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
- addHeader(urlRequest, key: headerWSKeyName, val: generateWebSocketKey())
+ addHeader(urlRequest, key: headerWSKeyName, val: headerSecKey)
if let origin = origin {
addHeader(urlRequest, key: headerOriginName, val: origin)
}
@@ -419,10 +422,6 @@ open class WebSocket : NSObject, StreamDelegate {
} else {
certValidated = true //not a https session, so no need to check SSL pinning
}
- if voipEnabled {
- inStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
- outStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
- }
CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
@@ -446,7 +445,8 @@ open class WebSocket : NSObject, StreamDelegate {
WebSocket.sharedWorkQueue.async {
self?.cleanupStream()
}
- self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: 2))
+ let errCode = InternalErrorCode.writeTimeoutError.rawValue
+ self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: errCode))
return
} else if outStream.streamError != nil {
return // disconnectStream will be called.
@@ -460,7 +460,8 @@ open class WebSocket : NSObject, StreamDelegate {
s.certValidated = sec.isValid(trust, domain: domain)
if !s.certValidated {
WebSocket.sharedWorkQueue.async {
- let error = s.errorWithDetail("Invalid SSL certificate", code: 1)
+ let errCode = InternalErrorCode.invalidSSLError.rawValue
+ let error = s.errorWithDetail("Invalid SSL certificate", code: errCode)
s.disconnectStream(error)
}
return
@@ -645,6 +646,12 @@ open class WebSocket : NSObject, StreamDelegate {
if let acceptKey = headers[headerWSAcceptName as NSString] as? NSString {
if acceptKey.length > 0 {
+ if headerSecKey.characters.count > 0 {
+ let sha = "\(headerSecKey)258EAFA5-E914-47DA-95CA-C5AB0DC85B11".sha1Base64()
+ if sha != acceptKey as String {
+ return -1
+ }
+ }
return 0
}
}
@@ -661,19 +668,19 @@ open class WebSocket : NSObject, StreamDelegate {
let part = p.trimmingCharacters(in: .whitespaces)
if part == "permessage-deflate" {
compressionState.supportsCompression = true
- } else if part.hasPrefix("server_max_window_bits="){
+ } else if part.hasPrefix("server_max_window_bits=") {
let valString = part.components(separatedBy: "=")[1]
if let val = Int(valString.trimmingCharacters(in: .whitespaces)) {
compressionState.serverMaxWindowBits = val
}
- } else if part.hasPrefix("client_max_window_bits="){
+ } else if part.hasPrefix("client_max_window_bits=") {
let valString = part.components(separatedBy: "=")[1]
if let val = Int(valString.trimmingCharacters(in: .whitespaces)) {
compressionState.clientMaxWindowBits = val
}
- } else if part == "client_no_context_takeover"{
+ } else if part == "client_no_context_takeover" {
compressionState.clientNoContextTakeover = true
- } else if part == "server_no_context_takeover"{
+ } else if part == "server_no_context_takeover" {
compressionState.serverNoContextTakeover = true
}
}
@@ -1082,6 +1089,15 @@ open class WebSocket : NSObject, StreamDelegate {
}
+private extension String {
+ func sha1Base64() -> String {
+ let data = self.data(using: String.Encoding.utf8)!
+ var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
+ data.withUnsafeBytes { _ = CC_SHA1($0, CC_LONG(data.count), &digest) }
+ return Data(bytes: digest).base64EncodedString()
+ }
+}
+
private extension Data {
init(buffer: UnsafeBufferPointer) {
diff --git a/Starscream.podspec b/Starscream.podspec
index 03060df6..8aa31113 100644
--- a/Starscream.podspec
+++ b/Starscream.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Starscream"
- s.version = "2.0.4"
+ s.version = "2.1.0"
s.summary = "A conforming WebSocket RFC 6455 client library in Swift for iOS and OSX."
s.homepage = "https://github.com/daltoniam/Starscream"
s.license = 'Apache License, Version 2.0'
diff --git a/examples/SimpleTest/SimpleTest.xcodeproj/project.xcworkspace/xcuserdata/dalton.xcuserdatad/UserInterfaceState.xcuserstate b/examples/SimpleTest/SimpleTest.xcodeproj/project.xcworkspace/xcuserdata/dalton.xcuserdatad/UserInterfaceState.xcuserstate
index 94951322..6405dd2d 100644
Binary files a/examples/SimpleTest/SimpleTest.xcodeproj/project.xcworkspace/xcuserdata/dalton.xcuserdatad/UserInterfaceState.xcuserstate and b/examples/SimpleTest/SimpleTest.xcodeproj/project.xcworkspace/xcuserdata/dalton.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/zlib/include.h b/zlib/include.h
index bb92a98f..cb3747f2 100644
--- a/zlib/include.h
+++ b/zlib/include.h
@@ -1,2 +1,2 @@
-
#include
+#include
diff --git a/zlib/module.modulemap b/zlib/module.modulemap
index 0fdb2181..7172f843 100644
--- a/zlib/module.modulemap
+++ b/zlib/module.modulemap
@@ -2,3 +2,7 @@ module zlib [system] {
header "include.h"
link "z"
}
+module CommonCrypto [system] {
+ header "include.h"
+ export *
+}